提交 bd0bd5d1 authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov

Add DATABASE_TO_LOWER and CASE_INSENSITIVE_IDENTIFIERS

上级 27a103a2
...@@ -609,6 +609,11 @@ public class Parser { ...@@ -609,6 +609,11 @@ public class Parser {
private final Database database; private final Database database;
private final Session session; private final Session session;
/**
* @see org.h2.engine.DbSettings#databaseToLower
*/
private final boolean identifiersToLower;
/** /**
* @see org.h2.engine.DbSettings#databaseToUpper * @see org.h2.engine.DbSettings#databaseToUpper
*/ */
...@@ -645,6 +650,7 @@ public class Parser { ...@@ -645,6 +650,7 @@ public class Parser {
public Parser(Session session) { public Parser(Session session) {
this.database = session.getDatabase(); this.database = session.getDatabase();
this.identifiersToLower = database.getSettings().databaseToLower;
this.identifiersToUpper = database.getSettings().databaseToUpper; this.identifiersToUpper = database.getSettings().databaseToUpper;
this.session = session; this.session = session;
} }
...@@ -1375,9 +1381,12 @@ public class Parser { ...@@ -1375,9 +1381,12 @@ public class Parser {
private Prepared parseHelp() { private Prepared parseHelp() {
Select select = new Select(session, null); Select select = new Select(session, null);
select.setWildcard(); select.setWildcard();
Table table = database.getSchema("INFORMATION_SCHEMA").resolveTableOrView(session, "HELP"); String informationSchema = database.sysIdentifier("INFORMATION_SCHEMA");
Table table = database.getSchema(informationSchema)
.resolveTableOrView(session, database.sysIdentifier("HELP"));
Function function = Function.getFunction(database, "UPPER"); Function function = Function.getFunction(database, "UPPER");
function.setParameter(0, new ExpressionColumn(database, "INFORMATION_SCHEMA", "HELP", "TOPIC")); function.setParameter(0, new ExpressionColumn(database, informationSchema,
database.sysIdentifier("HELP"), database.sysIdentifier("TOPIC")));
function.doneWithParameters(); function.doneWithParameters();
TableFilter filter = new TableFilter(session, table, null, rightsChecked, select, 0, null); TableFilter filter = new TableFilter(session, table, null, rightsChecked, select, 0, null);
select.addTableFilter(filter, true); select.addTableFilter(filter, true);
...@@ -1419,7 +1428,7 @@ public class Parser { ...@@ -1419,7 +1428,7 @@ public class Parser {
buff.append("'UTF8' AS SERVER_ENCODING FROM DUAL"); buff.append("'UTF8' AS SERVER_ENCODING FROM DUAL");
} else if (readIf("TABLES")) { } else if (readIf("TABLES")) {
// for MySQL compatibility // for MySQL compatibility
String schema = Constants.SCHEMA_MAIN; String schema = database.getMainSchema().getName();
if (readIf(FROM)) { if (readIf(FROM)) {
schema = readUniqueIdentifier(); schema = readUniqueIdentifier();
} }
...@@ -1825,7 +1834,7 @@ public class Parser { ...@@ -1825,7 +1834,7 @@ public class Parser {
table = parseValuesTable(0).getTable(); table = parseValuesTable(0).getTable();
} else if (readIf(TABLE)) { } else if (readIf(TABLE)) {
read(OPEN_PAREN); read(OPEN_PAREN);
table = readTableFunction("TABLE", null, database.getSchema(Constants.SCHEMA_MAIN)); table = readTableFunction("TABLE", null, database.getMainSchema());
} else { } else {
String tableName = readIdentifierWithSchema(null); String tableName = readIdentifierWithSchema(null);
Schema schema; Schema schema;
...@@ -1850,7 +1859,7 @@ public class Parser { ...@@ -1850,7 +1859,7 @@ public class Parser {
foundLeftBracket = false; foundLeftBracket = false;
} }
if (foundLeftBracket) { if (foundLeftBracket) {
Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN); Schema mainSchema = database.getMainSchema();
if (equalsToken(tableName, RangeTable.NAME) if (equalsToken(tableName, RangeTable.NAME)
|| equalsToken(tableName, RangeTable.ALIAS)) { || equalsToken(tableName, RangeTable.ALIAS)) {
Expression min = readExpression(); Expression min = readExpression();
...@@ -2812,7 +2821,7 @@ public class Parser { ...@@ -2812,7 +2821,7 @@ public class Parser {
} }
private Table getDualTable(boolean noColumns) { private Table getDualTable(boolean noColumns) {
Schema main = database.findSchema(Constants.SCHEMA_MAIN); Schema main = database.getMainSchema();
Expression one = ValueExpression.get(ValueLong.get(1)); Expression one = ValueExpression.get(ValueLong.get(1));
return new RangeTable(main, one, one, noColumns); return new RangeTable(main, one, one, noColumns);
} }
...@@ -4098,8 +4107,7 @@ public class Parser { ...@@ -4098,8 +4107,7 @@ public class Parser {
read(DOT); read(DOT);
} }
if (readIf("REGCLASS")) { if (readIf("REGCLASS")) {
FunctionAlias f = findFunctionAlias(Constants.SCHEMA_MAIN, FunctionAlias f = findFunctionAlias(database.getMainSchema().getName(), "PG_GET_OID");
"PG_GET_OID");
if (f == null) { if (f == null) {
throw getSyntaxError(); throw getSyntaxError();
} }
...@@ -5050,6 +5058,10 @@ public class Parser { ...@@ -5050,6 +5058,10 @@ public class Parser {
} }
type = CHAR_NAME; type = CHAR_NAME;
} else if (c >= 'A' && c <= 'Z') { } else if (c >= 'A' && c <= 'Z') {
if (identifiersToLower) {
command[i] = (char) (c + ('a' - 'A'));
changed = true;
}
type = CHAR_NAME; type = CHAR_NAME;
} else if (c >= '0' && c <= '9') { } else if (c >= '0' && c <= '9') {
type = CHAR_VALUE; type = CHAR_VALUE;
...@@ -5058,8 +5070,8 @@ public class Parser { ...@@ -5058,8 +5070,8 @@ public class Parser {
// whitespace // whitespace
} else if (Character.isJavaIdentifierPart(c)) { } else if (Character.isJavaIdentifierPart(c)) {
type = CHAR_NAME; type = CHAR_NAME;
if (identifiersToUpper) { if (identifiersToUpper || identifiersToLower) {
char u = Character.toUpperCase(c); char u = identifiersToUpper ? Character.toUpperCase(c) : Character.toLowerCase(c);
if (u != c) { if (u != c) {
command[i] = u; command[i] = u;
changed = true; changed = true;
...@@ -5931,7 +5943,7 @@ public class Parser { ...@@ -5931,7 +5943,7 @@ public class Parser {
} }
private TableFilter parseValuesTable(int orderInFrom) { private TableFilter parseValuesTable(int orderInFrom) {
Schema mainSchema = database.getSchema(Constants.SCHEMA_MAIN); Schema mainSchema = database.getMainSchema();
TableFunction tf = (TableFunction) Function.getFunction(database, "TABLE"); TableFunction tf = (TableFunction) Function.getFunction(database, "TABLE");
ArrayList<Column> columns = Utils.newSmallArrayList(); ArrayList<Column> columns = Utils.newSmallArrayList();
ArrayList<ArrayList<Expression>> rows = Utils.newSmallArrayList(); ArrayList<ArrayList<Expression>> rows = Utils.newSmallArrayList();
...@@ -6909,7 +6921,11 @@ public class Parser { ...@@ -6909,7 +6921,11 @@ public class Parser {
currentToken = SetTypes currentToken = SetTypes
.getTypeName(SetTypes.REFERENTIAL_INTEGRITY); .getTypeName(SetTypes.REFERENTIAL_INTEGRITY);
} }
int type = SetTypes.getType(currentToken); String typeName = currentToken;
if (!identifiersToUpper) {
typeName = StringUtils.toUpperEnglish(typeName);
}
int type = SetTypes.getType(typeName);
if (type < 0) { if (type < 0) {
throw getSyntaxError(); throw getSyntaxError();
} }
......
...@@ -401,6 +401,16 @@ public class Constants { ...@@ -401,6 +401,16 @@ public class Constants {
*/ */
public static final int SALT_LEN = 8; public static final int SALT_LEN = 8;
/**
* The identity of INFORMATION_SCHEMA.
*/
public static final int META_SCHEMA_ID = -1;
/**
* The identity of PUBLIC schema.
*/
public static final int MAIN_SCHEMA_ID = 0;
/** /**
* The name of the default schema. * The name of the default schema.
*/ */
......
...@@ -660,7 +660,8 @@ public class Database implements DataHandler { ...@@ -660,7 +660,8 @@ public class Database implements DataHandler {
if (n == null || n.isEmpty()) { if (n == null || n.isEmpty()) {
n = "unnamed"; n = "unnamed";
} }
return dbSettings.databaseToUpper ? StringUtils.toUpperEnglish(n) : n; return dbSettings.databaseToUpper ? StringUtils.toUpperEnglish(n)
: dbSettings.databaseToLower ? StringUtils.toLowerEnglish(n) : n;
} }
private synchronized void open(int traceLevelFile, int traceLevelSystemOut, ConnectionInfo ci) { private synchronized void open(int traceLevelFile, int traceLevelSystemOut, ConnectionInfo ci) {
...@@ -788,12 +789,14 @@ public class Database implements DataHandler { ...@@ -788,12 +789,14 @@ public class Database implements DataHandler {
store.getTransactionStore().init(); store.getTransactionStore().init();
} }
systemUser = new User(this, 0, SYSTEM_USER_NAME, true); systemUser = new User(this, 0, SYSTEM_USER_NAME, true);
mainSchema = new Schema(this, 0, Constants.SCHEMA_MAIN, systemUser, true); mainSchema = new Schema(this, Constants.MAIN_SCHEMA_ID, sysIdentifier(Constants.SCHEMA_MAIN), systemUser,
infoSchema = new Schema(this, -1, "INFORMATION_SCHEMA", systemUser, true); true);
infoSchema = new Schema(this, Constants.META_SCHEMA_ID, sysIdentifier("INFORMATION_SCHEMA"), systemUser,
true);
schemas.put(mainSchema.getName(), mainSchema); schemas.put(mainSchema.getName(), mainSchema);
schemas.put(infoSchema.getName(), infoSchema); schemas.put(infoSchema.getName(), infoSchema);
publicRole = new Role(this, 0, Constants.PUBLIC_ROLE_NAME, true); publicRole = new Role(this, 0, sysIdentifier(Constants.PUBLIC_ROLE_NAME), true);
roles.put(Constants.PUBLIC_ROLE_NAME, publicRole); roles.put(publicRole.getName(), publicRole);
systemUser.setAdmin(true); systemUser.setAdmin(true);
systemSession = new Session(this, systemUser, ++nextSessionId); systemSession = new Session(this, systemUser, ++nextSessionId);
lobSession = new Session(this, systemUser, ++nextSessionId); lobSession = new Session(this, systemUser, ++nextSessionId);
...@@ -1687,6 +1690,15 @@ public class Database implements DataHandler { ...@@ -1687,6 +1690,15 @@ public class Database implements DataHandler {
return i; return i;
} }
/**
* Returns main schema (usually PUBLIC).
*
* @return main schema (usually PUBLIC)
*/
public Schema getMainSchema() {
return mainSchema;
}
public ArrayList<UserAggregate> getAllAggregates() { public ArrayList<UserAggregate> getAllAggregates() {
return new ArrayList<>(aggregates.values()); return new ArrayList<>(aggregates.values());
} }
...@@ -2760,8 +2772,8 @@ public class Database implements DataHandler { ...@@ -2760,8 +2772,8 @@ public class Database implements DataHandler {
continue; continue;
} }
// exclude the LOB_MAP that the Recover tool creates // exclude the LOB_MAP that the Recover tool creates
if (table.getName().equals("LOB_BLOCKS") && table.getSchema() if (table.getSchema().getId() == Constants.META_SCHEMA_ID
.getName().equals("INFORMATION_SCHEMA")) { && table.getName().equalsIgnoreCase("LOB_BLOCKS")) {
continue; continue;
} }
return table; return table;
...@@ -3041,7 +3053,7 @@ public class Database implements DataHandler { ...@@ -3041,7 +3053,7 @@ public class Database implements DataHandler {
* @return the hash map * @return the hash map
*/ */
public <V> HashMap<String, V> newStringMap() { public <V> HashMap<String, V> newStringMap() {
return dbSettings.databaseToUpper ? new HashMap<String, V>() : new CaseInsensitiveMap<V>(); return dbSettings.caseInsensitiveIdentifiers ? new CaseInsensitiveMap<V>() : new HashMap<String, V>();
} }
/** /**
...@@ -3052,7 +3064,8 @@ public class Database implements DataHandler { ...@@ -3052,7 +3064,8 @@ public class Database implements DataHandler {
* @return the hash map * @return the hash map
*/ */
public <V> ConcurrentHashMap<String, V> newConcurrentStringMap() { public <V> ConcurrentHashMap<String, V> newConcurrentStringMap() {
return dbSettings.databaseToUpper ? new ConcurrentHashMap<String, V>() : new CaseInsensitiveConcurrentMap<V>(); return dbSettings.caseInsensitiveIdentifiers ? new CaseInsensitiveConcurrentMap<V>()
: new ConcurrentHashMap<String, V>();
} }
/** /**
...@@ -3064,7 +3077,18 @@ public class Database implements DataHandler { ...@@ -3064,7 +3077,18 @@ public class Database implements DataHandler {
* @return true if they match * @return true if they match
*/ */
public boolean equalsIdentifiers(String a, String b) { public boolean equalsIdentifiers(String a, String b) {
return a.equals(b) || (!dbSettings.databaseToUpper && a.equalsIgnoreCase(b)); return a.equals(b) || dbSettings.caseInsensitiveIdentifiers && a.equalsIgnoreCase(b);
}
/**
* Returns identifier in upper or lower case depending on database settings.
*
* @param upperName
* identifier in the upper case
* @return identifier in upper or lower case
*/
public String sysIdentifier(String upperName) {
return dbSettings.databaseToLower ? StringUtils.toLowerEnglish(upperName) : upperName;
} }
@Override @Override
......
...@@ -6,6 +6,7 @@ ...@@ -6,6 +6,7 @@
package org.h2.engine; package org.h2.engine;
import java.util.HashMap; import java.util.HashMap;
import org.h2.api.ErrorCode;
import org.h2.message.DbException; import org.h2.message.DbException;
import org.h2.util.Utils; import org.h2.util.Utils;
...@@ -55,15 +56,28 @@ public class DbSettings extends SettingsBase { ...@@ -55,15 +56,28 @@ public class DbSettings extends SettingsBase {
*/ */
public final int analyzeSample = get("ANALYZE_SAMPLE", 10_000); public final int analyzeSample = get("ANALYZE_SAMPLE", 10_000);
/**
* Database setting <code>DATABASE_TO_LOWER</code> (default: false).<br />
* Database short names are converted to lowercase for the DATABASE()
* function, and in the CATALOG column of all database meta data methods.
* Setting this to "true" is experimental.
*/
public final boolean databaseToLower;
/** /**
* Database setting <code>DATABASE_TO_UPPER</code> (default: true).<br /> * Database setting <code>DATABASE_TO_UPPER</code> (default: true).<br />
* Database short names are converted to uppercase for the DATABASE() * Database short names are converted to uppercase for the DATABASE()
* function, and in the CATALOG column of all database meta data methods. * function, and in the CATALOG column of all database meta data methods.
* Setting this to "false" is experimental. When set to false, all
* identifier names (table names, column names) are case sensitive (except
* aggregate, built-in functions, data types, and keywords).
*/ */
public final boolean databaseToUpper = get("DATABASE_TO_UPPER", true); public final boolean databaseToUpper;
/**
* Database setting <code>CASE_INSENSITIVE_IDENTIFIERS</code> (default:
* false).<br />
* When set to true, all identifier names (table names, column names) are
* case insensitive. Setting this to "true" is experimental.
*/
public final boolean caseInsensitiveIdentifiers = get("CASE_INSENSITIVE_IDENTIFIERS", false);
/** /**
* Database setting <code>DB_CLOSE_ON_EXIT</code> (default: true).<br /> * Database setting <code>DB_CLOSE_ON_EXIT</code> (default: true).<br />
...@@ -337,6 +351,18 @@ public class DbSettings extends SettingsBase { ...@@ -337,6 +351,18 @@ public class DbSettings extends SettingsBase {
if (s.get("NESTED_JOINS") != null || Utils.getProperty("h2.nestedJoins", null) != null) { if (s.get("NESTED_JOINS") != null || Utils.getProperty("h2.nestedJoins", null) != null) {
throw DbException.getUnsupportedException("NESTED_JOINS setting is not available since 1.4.197"); throw DbException.getUnsupportedException("NESTED_JOINS setting is not available since 1.4.197");
} }
boolean lower = get("DATABASE_TO_LOWER", false);
boolean upperSet = containsKey("DATABASE_TO_UPPER");
boolean upper = get("DATABASE_TO_UPPER", true);
if (lower && upper) {
if (upperSet) {
throw DbException.get(ErrorCode.UNSUPPORTED_SETTING_COMBINATION,
"DATABASE_TO_LOWER & DATABASE_TO_UPPER");
}
upper = false;
}
databaseToLower = lower;
databaseToUpper = upper;
} }
/** /**
......
...@@ -205,8 +205,7 @@ public class FunctionAlias extends SchemaObjectBase { ...@@ -205,8 +205,7 @@ public class FunctionAlias extends SchemaObjectBase {
@Override @Override
public StringBuilder getSQL(StringBuilder builder) { public StringBuilder getSQL(StringBuilder builder) {
// TODO can remove this method once FUNCTIONS_IN_SCHEMA is enabled // TODO can remove this method once FUNCTIONS_IN_SCHEMA is enabled
if (database.getSettings().functionsInSchema || if (database.getSettings().functionsInSchema || getSchema().getId() != Constants.MAIN_SCHEMA_ID) {
!getSchema().getName().equals(Constants.SCHEMA_MAIN)) {
return super.getSQL(builder); return super.getSQL(builder);
} }
return Parser.quoteIdentifier(builder, getName()); return Parser.quoteIdentifier(builder, getName());
......
...@@ -176,7 +176,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba ...@@ -176,7 +176,7 @@ public class Session extends SessionWithState implements TransactionStore.Rollba
this.user = user; this.user = user;
this.id = id; this.id = id;
this.lockTimeout = database.getLockTimeout(); this.lockTimeout = database.getLockTimeout();
this.currentSchemaName = Constants.SCHEMA_MAIN; this.currentSchemaName = database.getMainSchema().getName();
this.columnNamerConfiguration = ColumnNamerConfiguration.getDefault(); this.columnNamerConfiguration = ColumnNamerConfiguration.getDefault();
} }
......
...@@ -84,7 +84,7 @@ public class JavaFunction extends Expression implements FunctionCall { ...@@ -84,7 +84,7 @@ public class JavaFunction extends Expression implements FunctionCall {
public StringBuilder getSQL(StringBuilder builder) { public StringBuilder getSQL(StringBuilder builder) {
// TODO always append the schema once FUNCTIONS_IN_SCHEMA is enabled // TODO always append the schema once FUNCTIONS_IN_SCHEMA is enabled
if (functionAlias.getDatabase().getSettings().functionsInSchema || if (functionAlias.getDatabase().getSettings().functionsInSchema ||
!functionAlias.getSchema().getName().equals(Constants.SCHEMA_MAIN)) { functionAlias.getSchema().getId() != Constants.MAIN_SCHEMA_ID) {
Parser.quoteIdentifier(builder, functionAlias.getSchema().getName()).append('.'); Parser.quoteIdentifier(builder, functionAlias.getSchema().getName()).append('.');
} }
Parser.quoteIdentifier(builder, functionAlias.getName()).append('('); Parser.quoteIdentifier(builder, functionAlias.getName()).append('(');
......
...@@ -343,7 +343,6 @@ public class Schema extends DbObjectBase { ...@@ -343,7 +343,6 @@ public class Schema extends DbObjectBase {
if (synonym != null) { if (synonym != null) {
return synonym.getSynonymFor(); return synonym.getSynonymFor();
} }
return null;
} }
return table; return table;
} }
......
...@@ -16,7 +16,6 @@ import org.h2.command.Prepared; ...@@ -16,7 +16,6 @@ import org.h2.command.Prepared;
import org.h2.command.ddl.CreateTableData; import org.h2.command.ddl.CreateTableData;
import org.h2.command.dml.AllColumnsForPlan; import org.h2.command.dml.AllColumnsForPlan;
import org.h2.command.dml.Query; import org.h2.command.dml.Query;
import org.h2.engine.Constants;
import org.h2.engine.Database; import org.h2.engine.Database;
import org.h2.engine.DbObject; import org.h2.engine.DbObject;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -547,7 +546,7 @@ public class TableView extends Table { ...@@ -547,7 +546,7 @@ public class TableView extends Table {
*/ */
public static TableView createTempView(Session session, User owner, public static TableView createTempView(Session session, User owner,
String name, Query query, Query topQuery) { String name, Query query, Query topQuery) {
Schema mainSchema = session.getDatabase().getSchema(Constants.SCHEMA_MAIN); Schema mainSchema = session.getDatabase().getMainSchema();
String querySQL = query.getPlanSQL(); String querySQL = query.getPlanSQL();
TableView v = new TableView(mainSchema, 0, name, TableView v = new TableView(mainSchema, 0, name,
querySQL, query.getParameters(), null /* column templates */, session, querySQL, query.getParameters(), null /* column templates */, session,
......
...@@ -71,7 +71,7 @@ public class TestCompatibility extends TestDb { ...@@ -71,7 +71,7 @@ public class TestCompatibility extends TestDb {
} }
private void testCaseSensitiveIdentifiers() throws SQLException { private void testCaseSensitiveIdentifiers() throws SQLException {
Connection c = getConnection("compatibility;DATABASE_TO_UPPER=FALSE"); Connection c = getConnection("compatibility;DATABASE_TO_UPPER=FALSE;CASE_INSENSITIVE_IDENTIFIERS=TRUE");
Statement stat = c.createStatement(); Statement stat = c.createStatement();
stat.execute("create table test(id int primary key, name varchar) " + stat.execute("create table test(id int primary key, name varchar) " +
"as select 1, 'hello'"); "as select 1, 'hello'");
......
...@@ -73,7 +73,7 @@ public class TestPgServer extends TestDb { ...@@ -73,7 +73,7 @@ public class TestPgServer extends TestDb {
} }
deleteDb("pgserver"); deleteDb("pgserver");
Connection conn = getConnection( Connection conn = getConnection(
"mem:pgserver;DATABASE_TO_UPPER=false", "sa", "sa"); "mem:pgserver;DATABASE_TO_LOWER=true", "sa", "sa");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("create table test(id int, name varchar(255))"); stat.execute("create table test(id int, name varchar(255))");
Server server = createPgServer("-baseDir", getBaseDir(), Server server = createPgServer("-baseDir", getBaseDir(),
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论