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

Add DATABASE_TO_LOWER and CASE_INSENSITIVE_IDENTIFIERS

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