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