Unverified 提交 6178c2ed authored 作者: Evgenij Ryazanov's avatar Evgenij Ryazanov 提交者: GitHub

Merge pull request #1776 from katzyn/lower

Improve DATABASE_TO_LOWER handling
......@@ -338,7 +338,7 @@ This is achieved using different database URLs. Settings in the URLs are not cas
<td><a href="#compatibility">Compatibility mode</a></td>
<td class="notranslate">
jdbc:h2:&lt;url&gt;;MODE=&lt;databaseType&gt;<br />
jdbc:h2:~/test;MODE=MYSQL
jdbc:h2:~/test;MODE=MYSQL;DATABASE_TO_LOWER=TRUE
</td>
</tr>
<tr>
......@@ -894,8 +894,9 @@ or the SQL statement <code>SET MODE MSSQLServer</code>.
<h3>MySQL Compatibility Mode</h3>
<p>
To use the MySQL mode, use the database URL <code>jdbc:h2:~/test;MODE=MySQL</code>
or the SQL statement <code>SET MODE MySQL</code>. Use this mode for compatibility with MariaDB too.
To use the MySQL mode, use the database URL <code>jdbc:h2:~/test;MODE=MySQL;DATABASE_TO_LOWER=TRUE</code>.
Use this mode for compatibility with MariaDB too.
When case-insensitive identifiers are needed append <code>;CASE_INSENSITIVE_IDENTIFIERS=TRUE</code> to URL.
</p>
<ul><li>When inserting data, if a column is defined to be <code>NOT NULL</code>
and <code>NULL</code> is inserted,
......@@ -904,7 +905,6 @@ or the SQL statement <code>SET MODE MySQL</code>. Use this mode for compatibilit
</li><li>Creating indexes in the <code>CREATE TABLE</code> statement is allowed using
<code>INDEX(..)</code> or <code>KEY(..)</code>.
Example: <code>create table test(id int primary key, name varchar(255), key idx_name(name));</code>
</li><li>Meta data calls return identifiers in lower case.
</li><li>When converting a floating point number to an integer, the fractional
digits are not truncated, but the value is rounded.
</li><li>Concatenating <code>NULL</code> with another value
......@@ -944,8 +944,7 @@ or the SQL statement <code>SET MODE Oracle</code>.
<h3>PostgreSQL Compatibility Mode</h3>
<p>
To use the PostgreSQL mode, use the database URL <code>jdbc:h2:~/test;MODE=PostgreSQL</code>
or the SQL statement <code>SET MODE PostgreSQL</code>.
To use the PostgreSQL mode, use the database URL <code>jdbc:h2:~/test;MODE=PostgreSQL;DATABASE_TO_LOWER=TRUE</code>.
</p>
<ul><li>For aliased columns, <code>ResultSetMetaData.getColumnName()</code>
returns the alias name and <code>getTableName()</code> returns
......
......@@ -1275,7 +1275,7 @@ public class Database implements DataHandler {
* @return the role or null
*/
public Role findRole(String roleName) {
return roles.get(roleName);
return roles.get(StringUtils.toUpperEnglish(roleName));
}
/**
......@@ -1309,7 +1309,7 @@ public class Database implements DataHandler {
* @return the user or null
*/
public User findUser(String name) {
return users.get(name);
return users.get(StringUtils.toUpperEnglish(name));
}
/**
......
......@@ -357,6 +357,9 @@ public class DbSettings extends SettingsBase {
}
databaseToLower = lower;
databaseToUpper = upper;
HashMap<String, String> settings = getSettings();
settings.put("DATABASE_TO_LOWER", Boolean.toString(lower));
settings.put("DATABASE_TO_UPPER", Boolean.toString(upper));
}
/**
......
......@@ -11,6 +11,7 @@ import java.util.List;
import java.util.Map.Entry;
import org.h2.table.Table;
import org.h2.util.StringUtils;
/**
* A right owner (sometimes called principal).
......@@ -27,9 +28,13 @@ public abstract class RightOwner extends DbObjectBase {
*/
private HashMap<DbObject, Right> grantedRights;
protected RightOwner(Database database, int id, String name,
int traceModuleId) {
super(database, id, name, traceModuleId);
protected RightOwner(Database database, int id, String name, int traceModuleId) {
super(database, id, StringUtils.toUpperEnglish(name), traceModuleId);
}
@Override
public void rename(String newName) {
super.rename(StringUtils.toUpperEnglish(newName));
}
/**
......
......@@ -66,8 +66,53 @@ import org.h2.value.ValueString;
* used in one thread at any time.
* </p>
*/
public class JdbcConnection extends TraceObject
implements Connection, JdbcConnectionBackwardsCompat {
public class JdbcConnection extends TraceObject implements Connection, JdbcConnectionBackwardsCompat {
/**
* Database settings.
*/
static final class Settings {
/**
* The database mode.
*/
final Mode mode;
/**
* Whether unquoted identifiers are converted to upper case.
*/
final boolean databaseToUpper;
/**
* Whether unquoted identifiers are converted to lower case.
*/
final boolean databaseToLower;
/**
* Whether all identifiers are case insensitive.
*/
final boolean caseInsensitiveIdentifiers;
/**
* Creates new instance of database settings.
*
* @param mode
* the database mode
* @param databaseToUpper
* whether unquoted identifiers are converted to upper case
* @param databaseToLower
* whether unquoted identifiers are converted to lower case
* @param caseInsensitiveIdentifiers
* whether all identifiers are case insensitive
*/
Settings(Mode mode, boolean databaseToUpper, boolean databaseToLower, boolean caseInsensitiveIdentifiers) {
this.mode = mode;
this.databaseToUpper = databaseToUpper;
this.databaseToLower = databaseToLower;
this.caseInsensitiveIdentifiers = caseInsensitiveIdentifiers;
}
}
private static final String NUM_SERVERS = "numServers";
private static final String PREFIX_SERVER = "server";
......@@ -93,7 +138,7 @@ public class JdbcConnection extends TraceObject
private int queryTimeoutCache = -1;
private Map<String, String> clientInfo;
private volatile Mode mode;
private volatile Settings settings;
private final boolean scopeGeneratedKeys;
/**
......@@ -2088,31 +2133,58 @@ public class JdbcConnection extends TraceObject
}
Mode getMode() throws SQLException {
Mode mode = this.mode;
if (mode == null) {
String name;
return getSettings().mode;
}
Settings getSettings() throws SQLException {
Settings settings = this.settings;
if (settings == null) {
String modeName = ModeEnum.REGULAR.name();
boolean databaseToUpper = true, databaseToLower = false, caseInsensitiveIdentifiers = false;
try (PreparedStatement prep = prepareStatement(
"SELECT VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME=?")) {
"SELECT NAME, VALUE FROM INFORMATION_SCHEMA.SETTINGS WHERE NAME IN (?, ?, ?, ?)")) {
prep.setString(1, "MODE");
prep.setString(2, "DATABASE_TO_UPPER");
prep.setString(3, "DATABASE_TO_LOWER");
prep.setString(4, "CASE_INSENSITIVE_IDENTIFIERS");
ResultSet rs = prep.executeQuery();
rs.next();
name = rs.getString(1);
while (rs.next()) {
String value = rs.getString(2);
switch (rs.getString(1)) {
case "MODE":
modeName = value;
break;
case "DATABASE_TO_UPPER":
databaseToUpper = Boolean.valueOf(value);
break;
case "DATABASE_TO_LOWER":
databaseToLower = Boolean.valueOf(value);
break;
case "CASE_INSENSITIVE_IDENTIFIERS":
caseInsensitiveIdentifiers = Boolean.valueOf(value);
}
mode = Mode.getInstance(name);
}
}
Mode mode = Mode.getInstance(modeName);
if (mode == null) {
mode = Mode.getRegular();
}
this.mode = mode;
if (session instanceof SessionRemote
&& ((SessionRemote) session).getClientVersion() < Constants.TCP_PROTOCOL_VERSION_18) {
caseInsensitiveIdentifiers = !databaseToUpper;
}
settings = new Settings(mode, databaseToUpper, databaseToLower, caseInsensitiveIdentifiers);
this.settings = settings;
}
return mode;
return settings;
}
/**
* INTERNAL
*/
public boolean isRegularMode() throws SQLException {
// Clear cached mode if any (required by tests)
mode = null;
// Clear cached settings if any (required by tests)
settings = null;
return getMode().getEnum() == ModeEnum.REGULAR;
}
}
......@@ -16,7 +16,6 @@ import java.util.Map.Entry;
import java.util.Properties;
import org.h2.engine.Constants;
import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.SessionInterface;
import org.h2.engine.SessionRemote;
import org.h2.engine.SysProperties;
......@@ -1539,7 +1538,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements
/**
* Gets the comma-separated list of all SQL keywords that are not supported as
* table/column/index name, in addition to the SQL-2003 keywords. The list
* table/column/index name, in addition to the SQL:2003 keywords. The list
* returned is:
* <pre>
* IF,ILIKE,INTERSECTS,
......@@ -1551,7 +1550,7 @@ public class JdbcDatabaseMetaData extends TraceObject implements
* SYSDATE,SYSTIME,SYSTIMESTAMP,
* TODAY,TOP
* </pre>
* The complete list of keywords (including SQL-2003 keywords) is:
* The complete list of keywords (including SQL:2003 keywords) is:
* <pre>
* ALL, AND, ARRAY, AS,
* BETWEEN,
......@@ -2594,98 +2593,100 @@ public class JdbcDatabaseMetaData extends TraceObject implements
/**
* Checks if for CREATE TABLE Test(ID INT), getTables returns Test as the
* table name.
* table name and identifiers are case sensitive.
*
* @return false
* @return true is so, false otherwise
*/
@Override
public boolean supportsMixedCaseIdentifiers() {
public boolean supportsMixedCaseIdentifiers() throws SQLException{
debugCodeCall("supportsMixedCaseIdentifiers");
return false;
}
/**
* Checks if a table created with CREATE TABLE "Test"(ID INT) is a different
* table than a table created with CREATE TABLE TEST(ID INT).
*
* @return true usually, and false in MySQL mode
*/
@Override
public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
debugCodeCall("supportsMixedCaseQuotedIdentifiers");
return conn.getMode().getEnum() != ModeEnum.MySQL;
JdbcConnection.Settings settings = conn.getSettings();
return !settings.databaseToUpper && !settings.databaseToLower && !settings.caseInsensitiveIdentifiers;
}
/**
* Checks if for CREATE TABLE Test(ID INT), getTables returns TEST as the
* table name.
*
* @return true usually, and false in MySQL mode
* @return true is so, false otherwise
*/
@Override
public boolean storesUpperCaseIdentifiers() throws SQLException {
debugCodeCall("storesUpperCaseIdentifiers");
return conn.getMode().getEnum() != ModeEnum.MySQL;
return conn.getSettings().databaseToUpper;
}
/**
* Checks if for CREATE TABLE Test(ID INT), getTables returns test as the
* table name.
*
* @return false usually, and true in MySQL mode
* @return true is so, false otherwise
*/
@Override
public boolean storesLowerCaseIdentifiers() throws SQLException {
debugCodeCall("storesLowerCaseIdentifiers");
return conn.getMode().getEnum() == ModeEnum.MySQL;
return conn.getSettings().databaseToLower;
}
/**
* Checks if for CREATE TABLE Test(ID INT), getTables returns Test as the
* table name.
* table name and identifiers are not case sensitive.
*
* @return false
* @return true is so, false otherwise
*/
@Override
public boolean storesMixedCaseIdentifiers() {
public boolean storesMixedCaseIdentifiers() throws SQLException {
debugCodeCall("storesMixedCaseIdentifiers");
return false;
JdbcConnection.Settings settings = conn.getSettings();
return !settings.databaseToUpper && !settings.databaseToLower && settings.caseInsensitiveIdentifiers;
}
/**
* Checks if a table created with CREATE TABLE "Test"(ID INT) is a different
* table than a table created with CREATE TABLE "TEST"(ID INT).
*
* @return true is so, false otherwise
*/
@Override
public boolean supportsMixedCaseQuotedIdentifiers() throws SQLException {
debugCodeCall("supportsMixedCaseQuotedIdentifiers");
return !conn.getSettings().caseInsensitiveIdentifiers;
}
/**
* Checks if for CREATE TABLE "Test"(ID INT), getTables returns TEST as the
* table name.
*
* @return false usually, and true in MySQL mode
* @return false
*/
@Override
public boolean storesUpperCaseQuotedIdentifiers() throws SQLException {
debugCodeCall("storesUpperCaseQuotedIdentifiers");
return conn.getMode().getEnum() == ModeEnum.MySQL;
return false;
}
/**
* Checks if for CREATE TABLE "Test"(ID INT), getTables returns test as the
* table name.
*
* @return false usually, and true in MySQL mode
* @return false
*/
@Override
public boolean storesLowerCaseQuotedIdentifiers() throws SQLException {
debugCodeCall("storesLowerCaseQuotedIdentifiers");
return conn.getMode().getEnum() == ModeEnum.MySQL;
return false;
}
/**
* Checks if for CREATE TABLE "Test"(ID INT), getTables returns Test as the
* table name.
* table name and identifiers are case insensitive.
*
* @return true usually, and false in MySQL mode
* @return true is so, false otherwise
*/
@Override
public boolean storesMixedCaseQuotedIdentifiers() throws SQLException {
debugCodeCall("storesMixedCaseQuotedIdentifiers");
return conn.getMode().getEnum() != ModeEnum.MySQL;
return conn.getSettings().caseInsensitiveIdentifiers;
}
/**
......
......@@ -315,13 +315,15 @@ public class TestCompatibility extends TestDb {
}
private void testMySQL() throws SQLException {
// need to reconnect to change DATABASE_TO_LOWER
conn.close();
conn = getConnection("compatibility;MODE=MYSQL;DATABASE_TO_LOWER=TRUE");
Statement stat = conn.createStatement();
stat.execute("set mode mysql");
stat.execute("create schema test_schema");
stat.execute("use test_schema");
assertResult("TEST_SCHEMA", stat, "select schema()");
assertResult("test_schema", stat, "select schema()");
stat.execute("use public");
assertResult("PUBLIC", stat, "select schema()");
assertResult("public", stat, "select schema()");
stat.execute("SELECT 1");
stat.execute("DROP TABLE IF EXISTS TEST");
......@@ -372,17 +374,17 @@ public class TestCompatibility extends TestDb {
}
// need to reconnect, because meta data tables may be initialized
conn.close();
conn = getConnection("compatibility;MODE=MYSQL");
conn = getConnection("compatibility;MODE=MYSQL;DATABASE_TO_LOWER=TRUE");
stat = conn.createStatement();
testLog(Math.log(10), stat);
DatabaseMetaData meta = conn.getMetaData();
assertTrue(meta.storesLowerCaseIdentifiers());
assertTrue(meta.storesLowerCaseQuotedIdentifiers());
assertFalse(meta.storesLowerCaseQuotedIdentifiers());
assertFalse(meta.storesMixedCaseIdentifiers());
assertFalse(meta.storesMixedCaseQuotedIdentifiers());
assertFalse(meta.storesUpperCaseIdentifiers());
assertTrue(meta.storesUpperCaseQuotedIdentifiers());
assertFalse(meta.storesUpperCaseQuotedIdentifiers());
stat = conn.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
ResultSet.CONCUR_UPDATABLE);
......@@ -422,7 +424,7 @@ public class TestCompatibility extends TestDb {
// Check if mysql comments are supported, ensure clean connection
conn.close();
conn = getConnection("compatibility;MODE=MYSQL");
conn = getConnection("compatibility;MODE=MYSQL;DATABASE_TO_LOWER=TRUE");
stat = conn.createStatement();
stat.execute("DROP TABLE IF EXISTS TEST_NO_COMMENT");
stat.execute("CREATE table TEST_NO_COMMENT " +
......@@ -450,6 +452,8 @@ public class TestCompatibility extends TestDb {
stat.execute("CREATE INDEX IDX_ATTACHMENT_ID ON TEST_COMMENT_ENGINE (ATTACHMENT_ID)");
stat.execute("DROP INDEX IDX_ATTACHMENT_ID ON TEST_COMMENT_ENGINE");
stat.execute("DROP ALL OBJECTS");
conn.close();
conn = getConnection("compatibility");
}
......
......@@ -527,7 +527,7 @@ public class TestMetaData extends TestDb {
assertFalse(meta.storesLowerCaseIdentifiers());
assertFalse(meta.storesLowerCaseQuotedIdentifiers());
assertFalse(meta.storesMixedCaseIdentifiers());
assertTrue(meta.storesMixedCaseQuotedIdentifiers());
assertFalse(meta.storesMixedCaseQuotedIdentifiers());
assertTrue(meta.storesUpperCaseIdentifiers());
assertFalse(meta.storesUpperCaseQuotedIdentifiers());
assertTrue(meta.supportsAlterTableWithAddColumn());
......
......@@ -39,7 +39,7 @@ public class TestBnf extends TestDb {
testModes(conn);
testProcedures(conn, false);
}
try (Connection conn = getConnection("bnf;mode=mysql")) {
try (Connection conn = getConnection("bnf;mode=mysql;database_to_lower=true")) {
testProcedures(conn, true);
}
}
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论