提交 6aca33dc authored 作者: Noel Grandin's avatar Noel Grandin

Merge branch 'plus33-master'

...@@ -96,7 +96,7 @@ import org.h2.engine.Constants; ...@@ -96,7 +96,7 @@ 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.FunctionAlias; import org.h2.engine.FunctionAlias;
import org.h2.engine.Mode; import org.h2.engine.Mode.ModeEnum;
import org.h2.engine.Procedure; import org.h2.engine.Procedure;
import org.h2.engine.Right; import org.h2.engine.Right;
import org.h2.engine.Session; import org.h2.engine.Session;
...@@ -869,7 +869,7 @@ public class Parser { ...@@ -869,7 +869,7 @@ public class Parser {
} }
currentPrepared = command; currentPrepared = command;
int start = lastParseIndex; int start = lastParseIndex;
if (!readIf("FROM") && database.getMode() == Mode.getMySQL()) { if (!readIf("FROM") && database.getMode().getEnum() == ModeEnum.MySQL) {
readIdentifierWithSchema(); readIdentifierWithSchema();
read("FROM"); read("FROM");
} }
...@@ -4284,14 +4284,21 @@ public class Parser { ...@@ -4284,14 +4284,21 @@ public class Parser {
} else if (readIf("VISIBLE")) { } else if (readIf("VISIBLE")) {
column.setVisible(true); column.setVisible(true);
} }
if (readIf("NOT")) { NullConstraintType nullConstraint = parseNotNullConstraint();
read("NULL"); switch (nullConstraint) {
column.setNullable(false); case NULL_IS_ALLOWED:
} else if (readIf("NULL")) {
column.setNullable(true); column.setNullable(true);
} else { break;
case NULL_IS_NOT_ALLOWED:
column.setNullable(false);
break;
case NO_NULL_CONSTRAINT_FOUND:
// domains may be defined as not nullable // domains may be defined as not nullable
column.setNullable(defaultNullable & column.isNullable()); column.setNullable(defaultNullable & column.isNullable());
break;
default:
throw DbException.get(ErrorCode.UNKNOWN_MODE_1,
"Internal Error - unhandled case: " + nullConstraint.name());
} }
if (readIf("AS")) { if (readIf("AS")) {
if (isIdentity) { if (isIdentity) {
...@@ -4324,23 +4331,16 @@ public class Parser { ...@@ -4324,23 +4331,16 @@ public class Parser {
column.setPrimaryKey(true); column.setPrimaryKey(true);
column.setAutoIncrement(true, start, increment); column.setAutoIncrement(true, start, increment);
} }
if (readIf("NOT")) { if (NullConstraintType.NULL_IS_NOT_ALLOWED == parseNotNullConstraint()) {
read("NULL");
column.setNullable(false); column.setNullable(false);
} else {
readIf("NULL");
} }
if (readIf("AUTO_INCREMENT") || readIf("BIGSERIAL") || readIf("SERIAL")) { if (readIf("AUTO_INCREMENT") || readIf("BIGSERIAL") || readIf("SERIAL")) {
parseAutoIncrement(column); parseAutoIncrement(column);
if (readIf("NOT")) { parseNotNullConstraint();
read("NULL");
}
} else if (readIf("IDENTITY")) { } else if (readIf("IDENTITY")) {
parseAutoIncrement(column); parseAutoIncrement(column);
column.setPrimaryKey(true); column.setPrimaryKey(true);
if (readIf("NOT")) { parseNotNullConstraint();
read("NULL");
}
} }
if (readIf("NULL_TO_DEFAULT")) { if (readIf("NULL_TO_DEFAULT")) {
column.setConvertNullToDefault(true); column.setConvertNullToDefault(true);
...@@ -6107,25 +6107,32 @@ public class Parser { ...@@ -6107,25 +6107,32 @@ public class Parser {
return command; return command;
} else if (readIf("MODIFY")) { } else if (readIf("MODIFY")) {
// MySQL compatibility // MySQL compatibility
readIf("COLUMN"); readIf("COLUMN"); // optional
String columnName = readColumnIdentifier(); String columnName = readColumnIdentifier();
if ((isToken("NOT") || isToken("NULL"))) { AlterTableAlterColumn command = null;
AlterTableAlterColumn command = new AlterTableAlterColumn( NullConstraintType nullConstraint = parseNotNullConstraint();
session, schema); switch (nullConstraint) {
case NULL_IS_ALLOWED:
case NULL_IS_NOT_ALLOWED:
command = new AlterTableAlterColumn(session, schema);
command.setTableName(tableName); command.setTableName(tableName);
command.setIfTableExists(ifTableExists); command.setIfTableExists(ifTableExists);
Column column = columnIfTableExists(schema, tableName, columnName, ifTableExists); Column column = columnIfTableExists(schema, tableName, columnName, ifTableExists);
command.setOldColumn(column); command.setOldColumn(column);
if (readIf("NOT")) { if (nullConstraint == NullConstraintType.NULL_IS_ALLOWED) {
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL);
} else {
read("NULL");
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL);
}
return command;
} else { } else {
return parseAlterTableAlterColumnType(schema, tableName, columnName, ifTableExists); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL);
}
break;
case NO_NULL_CONSTRAINT_FOUND:
command = parseAlterTableAlterColumnType(schema, tableName, columnName, ifTableExists);
break;
default:
throw DbException.get(ErrorCode.UNKNOWN_MODE_1,
"Internal Error - unhandled case: " + nullConstraint.name());
} }
return command;
} else if (readIf("ALTER")) { } else if (readIf("ALTER")) {
readIf("COLUMN"); readIf("COLUMN");
String columnName = readColumnIdentifier(); String columnName = readColumnIdentifier();
...@@ -6177,27 +6184,34 @@ public class Parser { ...@@ -6177,27 +6184,34 @@ public class Parser {
command.setTableName(tableName); command.setTableName(tableName);
command.setIfTableExists(ifTableExists); command.setIfTableExists(ifTableExists);
command.setOldColumn(column); command.setOldColumn(column);
if (readIf("NULL")) { NullConstraintType nullConstraint = parseNotNullConstraint();
switch (nullConstraint) {
case NULL_IS_ALLOWED:
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NULL);
return command; break;
} else if (readIf("NOT")) { case NULL_IS_NOT_ALLOWED:
read("NULL");
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_NOT_NULL);
return command; break;
} else if (readIf("DEFAULT")) { case NO_NULL_CONSTRAINT_FOUND:
if (readIf("DEFAULT")) {
Expression defaultExpression = readExpression(); Expression defaultExpression = readExpression();
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_DEFAULT);
command.setDefaultExpression(defaultExpression); command.setDefaultExpression(defaultExpression);
return command;
} else if (readIf("INVISIBLE")) { } else if (readIf("INVISIBLE")) {
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY);
command.setVisible(false); command.setVisible(false);
return command;
} else if (readIf("VISIBLE")) { } else if (readIf("VISIBLE")) {
command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY); command.setType(CommandInterface.ALTER_TABLE_ALTER_COLUMN_VISIBILITY);
command.setVisible(true); command.setVisible(true);
return command;
} }
break;
default:
throw DbException.get(ErrorCode.UNKNOWN_MODE_1,
"Internal Error - unhandled case: " + nullConstraint.name());
}
return command;
} else if (readIf("RESTART")) { } else if (readIf("RESTART")) {
readIf("WITH"); readIf("WITH");
Expression start = readExpression(); Expression start = readExpression();
...@@ -6592,11 +6606,8 @@ public class Parser { ...@@ -6592,11 +6606,8 @@ public class Parser {
unique.setTableName(tableName); unique.setTableName(tableName);
command.addConstraintCommand(unique); command.addConstraintCommand(unique);
} }
if (readIf("NOT")) { if (NullConstraintType.NULL_IS_NOT_ALLOWED == parseNotNullConstraint()) {
read("NULL");
column.setNullable(false); column.setNullable(false);
} else {
readIf("NULL");
} }
if (readIf("CHECK")) { if (readIf("CHECK")) {
Expression expr = readExpression(); Expression expr = readExpression();
...@@ -6699,6 +6710,36 @@ public class Parser { ...@@ -6699,6 +6710,36 @@ public class Parser {
return command; return command;
} }
private enum NullConstraintType {
NULL_IS_ALLOWED, NULL_IS_NOT_ALLOWED, NO_NULL_CONSTRAINT_FOUND
}
private NullConstraintType parseNotNullConstraint() {
NullConstraintType nullConstraint = NullConstraintType.NO_NULL_CONSTRAINT_FOUND;
if ((isToken("NOT") || isToken("NULL"))) {
if (readIf("NOT")) {
read("NULL");
nullConstraint = NullConstraintType.NULL_IS_NOT_ALLOWED;
} else {
read("NULL");
nullConstraint = NullConstraintType.NULL_IS_ALLOWED;
}
if (database.getMode().getEnum() == ModeEnum.Oracle) {
if (readIf("ENABLE")) {
readIf("VALIDATE"); // Leave constraint 'as is'
if (readIf("NOVALIDATE")) { // Turn off constraint, allow NULLs
nullConstraint = NullConstraintType.NULL_IS_ALLOWED;
}
}
if (readIf("DISABLE")) { // Turn off constraint, allow NULLs
nullConstraint = NullConstraintType.NULL_IS_ALLOWED;
readIf("VALIDATE"); // ignore validate
readIf("NOVALIDATE"); // ignore novalidate
}
}
}
return nullConstraint;
}
private CreateSynonym parseCreateSynonym(boolean orReplace) { private CreateSynonym parseCreateSynonym(boolean orReplace) {
boolean ifNotExists = readIfNotExists(); boolean ifNotExists = readIfNotExists();
......
...@@ -19,9 +19,14 @@ import org.h2.util.StringUtils; ...@@ -19,9 +19,14 @@ import org.h2.util.StringUtils;
public class Mode { public class Mode {
public enum ModeEnum { public enum ModeEnum {
REGULAR, DB2, Derby, MSSQLServer, HSQLDB, MySQL, Oracle, PostgreSQL, Ignite REGULAR, DB2, Derby, MSSQLServer, HSQLDB, MySQL, Oracle, PostgreSQL, Ignite,
} }
/**
* The name of the default mode.
*/
static final String REGULAR = ModeEnum.REGULAR.name();
private static final HashMap<String, Mode> MODES = New.hashMap(); private static final HashMap<String, Mode> MODES = New.hashMap();
// Modes are also documented in the features section // Modes are also documented in the features section
...@@ -177,14 +182,16 @@ public class Mode { ...@@ -177,14 +182,16 @@ public class Mode {
*/ */
public Set<String> disallowedTypes = Collections.emptySet(); public Set<String> disallowedTypes = Collections.emptySet();
private final String name;
private ModeEnum modeEnum; private ModeEnum modeEnum;
static { static {
Mode mode = new Mode(ModeEnum.REGULAR); Mode mode = new Mode(ModeEnum.REGULAR.name());
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.DB2); mode = new Mode(ModeEnum.DB2.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
mode.sysDummy1 = true; mode.sysDummy1 = true;
...@@ -199,7 +206,7 @@ public class Mode { ...@@ -199,7 +206,7 @@ public class Mode {
mode.allowDB2TimestampFormat = true; mode.allowDB2TimestampFormat = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.Derby); mode = new Mode(ModeEnum.Derby.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.uniqueIndexSingleNull = true; mode.uniqueIndexSingleNull = true;
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
...@@ -209,7 +216,7 @@ public class Mode { ...@@ -209,7 +216,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode(ModeEnum.HSQLDB); mode = new Mode(ModeEnum.HSQLDB.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.convertOnlyToSmallerScale = true; mode.convertOnlyToSmallerScale = true;
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
...@@ -222,7 +229,7 @@ public class Mode { ...@@ -222,7 +229,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode(ModeEnum.MSSQLServer); mode = new Mode(ModeEnum.MSSQLServer.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.squareBracketQuotedNames = true; mode.squareBracketQuotedNames = true;
mode.uniqueIndexSingleNull = true; mode.uniqueIndexSingleNull = true;
...@@ -234,7 +241,7 @@ public class Mode { ...@@ -234,7 +241,7 @@ public class Mode {
mode.supportedClientInfoPropertiesRegEx = null; mode.supportedClientInfoPropertiesRegEx = null;
add(mode); add(mode);
mode = new Mode(ModeEnum.MySQL); mode = new Mode(ModeEnum.MySQL.name());
mode.convertInsertNullToZero = true; mode.convertInsertNullToZero = true;
mode.indexDefinitionInCreateTable = true; mode.indexDefinitionInCreateTable = true;
mode.lowerCaseIdentifiers = true; mode.lowerCaseIdentifiers = true;
...@@ -248,7 +255,7 @@ public class Mode { ...@@ -248,7 +255,7 @@ public class Mode {
mode.prohibitEmptyInPredicate = true; mode.prohibitEmptyInPredicate = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.Oracle); mode = new Mode(ModeEnum.Oracle.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.convertOnlyToSmallerScale = true; mode.convertOnlyToSmallerScale = true;
mode.uniqueIndexSingleNullExceptAllColumnsAreNull = true; mode.uniqueIndexSingleNullExceptAllColumnsAreNull = true;
...@@ -261,7 +268,7 @@ public class Mode { ...@@ -261,7 +268,7 @@ public class Mode {
mode.prohibitEmptyInPredicate = true; mode.prohibitEmptyInPredicate = true;
add(mode); add(mode);
mode = new Mode(ModeEnum.PostgreSQL); mode = new Mode(ModeEnum.PostgreSQL.name());
mode.aliasColumnName = true; mode.aliasColumnName = true;
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
mode.supportOffsetFetch = true; mode.supportOffsetFetch = true;
...@@ -284,19 +291,20 @@ public class Mode { ...@@ -284,19 +291,20 @@ public class Mode {
mode.disallowedTypes = disallowedTypes; mode.disallowedTypes = disallowedTypes;
add(mode); add(mode);
mode = new Mode(ModeEnum.Ignite); mode = new Mode(ModeEnum.Ignite.name());
mode.nullConcatIsNull = true; mode.nullConcatIsNull = true;
mode.allowAffinityKey = true; mode.allowAffinityKey = true;
mode.indexDefinitionInCreateTable = true; mode.indexDefinitionInCreateTable = true;
add(mode); add(mode);
} }
private Mode(ModeEnum modeEnum) { private Mode(String name) {
this.modeEnum = modeEnum; this.name = name;
this.modeEnum = ModeEnum.valueOf(name);
} }
private static void add(Mode mode) { private static void add(Mode mode) {
MODES.put(StringUtils.toUpperEnglish(mode.modeEnum.name()), mode); MODES.put(StringUtils.toUpperEnglish(mode.name), mode);
} }
/** /**
...@@ -309,10 +317,6 @@ public class Mode { ...@@ -309,10 +317,6 @@ public class Mode {
return MODES.get(StringUtils.toUpperEnglish(name)); return MODES.get(StringUtils.toUpperEnglish(name));
} }
public static Mode getRegular() {
return getInstance(ModeEnum.REGULAR.name());
}
public static Mode getMySQL() { public static Mode getMySQL() {
return getInstance(ModeEnum.MySQL.name()); return getInstance(ModeEnum.MySQL.name());
} }
...@@ -321,12 +325,25 @@ public class Mode { ...@@ -321,12 +325,25 @@ public class Mode {
return getInstance(ModeEnum.Oracle.name()); return getInstance(ModeEnum.Oracle.name());
} }
public static Mode getRegular() {
return getInstance(ModeEnum.REGULAR.name());
}
public String getName() { public String getName() {
return modeEnum.name(); return name;
} }
public ModeEnum getEnum() { public ModeEnum getEnum() {
return this.modeEnum; return this.modeEnum;
} }
public boolean isDbTypeOneOf(Mode.ModeEnum... dbTypes) {
for (Mode.ModeEnum dbType : dbTypes) {
if (this.modeEnum == dbType) {
return true;
}
}
return false;
}
} }
...@@ -304,7 +304,7 @@ public class TestAlter extends TestBase { ...@@ -304,7 +304,7 @@ public class TestAlter extends TestBase {
// This failed in v1.4.196 // This failed in v1.4.196
stat.execute("create table T (C int not null)"); stat.execute("create table T (C int not null)");
stat.execute("alter table T modify C null"); // Silently corrupted column C stat.execute("alter table T modify C null"); // Silently corrupted column C
stat.execute("insert into T values(null)"); // <- ERROR: NULL not allowed stat.execute("insert into T values(null)"); // <- Fixed in v1.4.196 - NULL is allowed
stat.execute("drop table T"); stat.execute("drop table T");
} }
} }
...@@ -34,6 +34,7 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -34,6 +34,7 @@ public class TestCompatibilityOracle extends TestBase {
@Override @Override
public void test() throws Exception { public void test() throws Exception {
testNotNullSyntax();
testTreatEmptyStringsAsNull(); testTreatEmptyStringsAsNull();
testDecimalScale(); testDecimalScale();
testPoundSymbolInColumnName(); testPoundSymbolInColumnName();
...@@ -41,6 +42,51 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -41,6 +42,51 @@ public class TestCompatibilityOracle extends TestBase {
testForbidEmptyInClause(); testForbidEmptyInClause();
} }
private void testNotNullSyntax() throws SQLException {
deleteDb("oracle");
Connection conn = getConnection("oracle;MODE=Oracle");
Statement stat = conn.createStatement();
// Some other variation (oracle syntax)
stat.execute("create table T (C int not null enable)");
stat.execute("insert into T values(1)");
stat.execute("drop table T");
stat.execute("create table T (C int not null enable validate)");
stat.execute("insert into T values(1)");
stat.execute("drop table T");
// can set NULL
stat.execute("create table T (C int not null disable)"); // can set NULL even with 'not null syntax' (oracle)
stat.execute("insert into T values(null)");
stat.execute("drop table T");
stat.execute("create table T (C int not null enable novalidate)"); // can set NULL even with 'not null syntax' (oracle)
stat.execute("insert into T values(null)");
stat.execute("drop table T");
// Some other variation with oracle syntax
stat.execute("create table T (C int not null)");
stat.execute("insert into T values(1)");
stat.execute("alter table T modify C not null");
stat.execute("insert into T values(1)");
stat.execute("alter table T modify C not null enable");
stat.execute("insert into T values(1)");
stat.execute("alter table T modify C not null enable validate");
stat.execute("insert into T values(1)");
stat.execute("drop table T");
// can set NULL
stat.execute("create table T (C int null)");
stat.execute("insert into T values(null)");
stat.execute("alter table T modify C null enable");
stat.execute("alter table T modify C null enable validate");
stat.execute("insert into T values(null)");
stat.execute("alter table T modify C not null disable"); // can set NULL even with 'not null syntax' (oracle)
stat.execute("insert into T values(null)");
stat.execute("alter table T modify C not null enable novalidate"); // can set NULL even with 'not null syntax' (oracle)
stat.execute("insert into T values(null)");
stat.execute("drop table T");
conn.close();
}
private void testTreatEmptyStringsAsNull() throws SQLException { private void testTreatEmptyStringsAsNull() throws SQLException {
deleteDb("oracle"); deleteDb("oracle");
Connection conn = getConnection("oracle;MODE=Oracle"); Connection conn = getConnection("oracle;MODE=Oracle");
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论