提交 dc8b67b8 authored 作者: thomasmueller's avatar thomasmueller

Formatting

上级 e24546ea
...@@ -5291,8 +5291,9 @@ public class Parser { ...@@ -5291,8 +5291,9 @@ public class Parser {
ArrayList<Expression> withExpressions = theQuery.getExpressions(); ArrayList<Expression> withExpressions = theQuery.getExpressions();
for (int i = 0; i < withExpressions.size(); ++i) { for (int i = 0; i < withExpressions.size(); ++i) {
Expression columnExp = withExpressions.get(i); Expression columnExp = withExpressions.get(i);
// use the passed in column name if supplied, otherwise use alias (if found) otherwise use column name // use the passed in column name if supplied, otherwise use alias
// derived from column expression // (if found) otherwise use column name derived from column
// expression
String columnName = columnNamer.getColumnName(columnExp,i,cols); String columnName = columnNamer.getColumnName(columnExp,i,cols);
columnTemplateList.add(new Column(columnName, columnTemplateList.add(new Column(columnName,
columnExp.getType())); columnExp.getType()));
......
...@@ -329,9 +329,10 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -329,9 +329,10 @@ public class AlterTableAddConstraint extends SchemaCommand {
} }
return null; return null;
} }
// all cols must be in the index key, the order doesn't matter and there must be no other fields in the index key
// all cols must be in the index key, the order doesn't matter and there
// must be no other fields in the index key
private static boolean canUseUniqueIndex(Index idx, Table table, private static boolean canUseUniqueIndex(Index idx, Table table,
IndexColumn[] cols) { IndexColumn[] cols) {
if (idx.getTable() != table || !idx.getIndexType().isUnique()) { if (idx.getTable() != table || !idx.getIndexType().isUnique()) {
...@@ -350,9 +351,9 @@ public class AlterTableAddConstraint extends SchemaCommand { ...@@ -350,9 +351,9 @@ public class AlterTableAddConstraint extends SchemaCommand {
for (IndexColumn c : cols) { for (IndexColumn c : cols) {
colsSet.add(c.column); colsSet.add(c.column);
} }
return colsSet.equals(indexColsSet); return colsSet.equals(indexColsSet);
} }
private static boolean canUseIndex(Index existingIndex, Table table, private static boolean canUseIndex(Index existingIndex, Table table,
IndexColumn[] cols, boolean moreColumnsOk) { IndexColumn[] cols, boolean moreColumnsOk) {
......
...@@ -245,7 +245,8 @@ public class MergeUsing extends Prepared { ...@@ -245,7 +245,8 @@ public class MergeUsing extends Prepared {
// throw and exception if we have processed this _ROWID_ before... // throw and exception if we have processed this _ROWID_ before...
if (targetRowidsRemembered.containsKey(targetRowIdValue[0])) { if (targetRowidsRemembered.containsKey(targetRowIdValue[0])) {
throw DbException.get(ErrorCode.DUPLICATE_KEY_1, throw DbException.get(ErrorCode.DUPLICATE_KEY_1,
"Merge using ON column expression, duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_=" "Merge using ON column expression, " +
"duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_="
+ targetRowIdValue[0].toString() + ":in:" + targetRowIdValue[0].toString() + ":in:"
+ targetTableFilter.getTable() + targetTableFilter.getTable()
+ ":conflicting source row number:" + ":conflicting source row number:"
......
...@@ -472,7 +472,8 @@ public class Constants { ...@@ -472,7 +472,8 @@ public class Constants {
public static final String SUFFIX_TRACE_FILE = ".trace.db"; public static final String SUFFIX_TRACE_FILE = ".trace.db";
/** /**
* How often we check to see if we need to apply a throttling delay if SET THROTTLE has been used. * How often we check to see if we need to apply a throttling delay if SET
* THROTTLE has been used.
*/ */
public static final int THROTTLE_DELAY = 50; public static final int THROTTLE_DELAY = 50;
......
...@@ -944,6 +944,12 @@ public class Database implements DataHandler { ...@@ -944,6 +944,12 @@ public class Database implements DataHandler {
session.unlock(meta); session.unlock(meta);
} }
/**
* This method doesn't actually unlock the metadata table, all it does it
* reset the debugging flags.
*
* @param session the session
*/
public void unlockMetaDebug(Session session) { public void unlockMetaDebug(Session session) {
if (SysProperties.CHECK2) { if (SysProperties.CHECK2) {
if (metaLockDebugging.get() == session) { if (metaLockDebugging.get() == session) {
......
...@@ -376,7 +376,8 @@ public class Session extends SessionWithState { ...@@ -376,7 +376,8 @@ public class Session extends SessionWithState {
* @param table the table * @param table the table
*/ */
public void removeLocalTempTable(Table table) { public void removeLocalTempTable(Table table) {
// Exception thrown in org.h2.engine.Database.removeMeta if line below is missing with TestGeneralCommonTableQueries // Exception thrown in org.h2.engine.Database.removeMeta if line below
// is missing with TestGeneralCommonTableQueries
database.lockMeta(this); database.lockMeta(this);
modificationId++; modificationId++;
localTempTables.remove(table.getName()); localTempTables.remove(table.getName());
...@@ -985,7 +986,8 @@ public class Session extends SessionWithState { ...@@ -985,7 +986,8 @@ public class Session extends SessionWithState {
modificationId++; modificationId++;
table.setModified(); table.setModified();
it.remove(); it.remove();
// Exception thrown in org.h2.engine.Database.removeMeta if line below is missing with TestDeadlock // Exception thrown in org.h2.engine.Database.removeMeta
// if line below is missing with TestDeadlock
database.lockMeta(this); database.lockMeta(this);
table.removeChildrenAndResources(this); table.removeChildrenAndResources(this);
if (closeSession) { if (closeSession) {
......
...@@ -1739,11 +1739,12 @@ public class JdbcConnection extends TraceObject ...@@ -1739,11 +1739,12 @@ public class JdbcConnection extends TraceObject
+ ");"); + ");");
} }
checkClosed(); checkClosed();
// no change to property: Ignore call. This early exit fixes a problem with websphere liberty // no change to property: Ignore call. This early exit fixes a
// resetting the client info of a pooled connection to its initial values. // problem with websphere liberty resetting the client info of a
// pooled connection to its initial values.
if (Objects.equals(value, getClientInfo(name))) { if (Objects.equals(value, getClientInfo(name))) {
return; return;
} }
if (isInternalProperty(name)) { if (isInternalProperty(name)) {
......
...@@ -23,7 +23,7 @@ org.h2.tools.Console=Starts the H2 Console (web-) server, as well as the TCP and ...@@ -23,7 +23,7 @@ org.h2.tools.Console=Starts the H2 Console (web-) server, as well as the TCP and
org.h2.tools.Console.main=When running without options, -tcp, -web, -browser and -pg are started.\nOptions are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-url] Start a browser and connect to this URL\n[-driver] Used together with -url\: the driver\n[-user] Used together with -url\: the user name\n[-password] Used together with -url\: the password\n[-web] Start the web server with the H2 Console\n[-tool] Start the icon or window that allows to start a browser\n[-browser] Start a browser connecting to the web server\n[-tcp] Start the TCP server\n[-pg] Start the PG server\nFor each Server, additional options are available;\n for details, see the Server tool.\nIf a service can not be started, the program\n terminates with an exit code of 1. org.h2.tools.Console.main=When running without options, -tcp, -web, -browser and -pg are started.\nOptions are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-url] Start a browser and connect to this URL\n[-driver] Used together with -url\: the driver\n[-user] Used together with -url\: the user name\n[-password] Used together with -url\: the password\n[-web] Start the web server with the H2 Console\n[-tool] Start the icon or window that allows to start a browser\n[-browser] Start a browser connecting to the web server\n[-tcp] Start the TCP server\n[-pg] Start the PG server\nFor each Server, additional options are available;\n for details, see the Server tool.\nIf a service can not be started, the program\n terminates with an exit code of 1.
org.h2.tools.ConvertTraceFile=Converts a .trace.db file to a SQL script and Java source code.\nSQL statement statistics are listed as well. org.h2.tools.ConvertTraceFile=Converts a .trace.db file to a SQL script and Java source code.\nSQL statement statistics are listed as well.
org.h2.tools.ConvertTraceFile.main=Options are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-traceFile <file>] The trace file name (default\: test.trace.db)\n[-script <file>] The script file name (default\: test.sql)\n[-javaClass <file>] The Java directory and class file name (default\: Test) org.h2.tools.ConvertTraceFile.main=Options are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-traceFile <file>] The trace file name (default\: test.trace.db)\n[-script <file>] The script file name (default\: test.sql)\n[-javaClass <file>] The Java directory and class file name (default\: Test)
org.h2.tools.CreateCluster=Creates a cluster from a standalone database.\nCopies a database to another location if required. org.h2.tools.CreateCluster=Creates a cluster from a stand-alone database.\nCopies a database to another location if required.
org.h2.tools.CreateCluster.main=Options are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-urlSource "<url>"] The database URL of the source database (jdbc\:h2\:...)\n[-urlTarget "<url>"] The database URL of the target database (jdbc\:h2\:...)\n[-user <user>] The user name (default\: sa)\n[-password <pwd>] The password\n[-serverList <list>] The comma separated list of host names or IP addresses org.h2.tools.CreateCluster.main=Options are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-urlSource "<url>"] The database URL of the source database (jdbc\:h2\:...)\n[-urlTarget "<url>"] The database URL of the target database (jdbc\:h2\:...)\n[-user <user>] The user name (default\: sa)\n[-password <pwd>] The password\n[-serverList <list>] The comma separated list of host names or IP addresses
org.h2.tools.DeleteDbFiles=Deletes all files belonging to a database.\nThe database must be closed before calling this tool. org.h2.tools.DeleteDbFiles=Deletes all files belonging to a database.\nThe database must be closed before calling this tool.
org.h2.tools.DeleteDbFiles.main=Options are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-dir <dir>] The directory (default\: .)\n[-db <database>] The database name\n[-quiet] Do not print progress information org.h2.tools.DeleteDbFiles.main=Options are case sensitive. Supported options are\:\n[-help] or [-?] Print the list of options\n[-dir <dir>] The directory (default\: .)\n[-db <database>] The database name\n[-quiet] Do not print progress information
......
...@@ -29,6 +29,7 @@ public class ColumnNamer { ...@@ -29,6 +29,7 @@ public class ColumnNamer {
} }
} }
} }
/** /**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it. * Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param expr the column expression * @param expr the column expression
...@@ -37,6 +38,7 @@ public class ColumnNamer { ...@@ -37,6 +38,7 @@ public class ColumnNamer {
public String getColumnName(Expression expr, int indexOfColumn) { public String getColumnName(Expression expr, int indexOfColumn) {
return getColumnName(expr,indexOfColumn,(String) null); return getColumnName(expr,indexOfColumn,(String) null);
} }
/** /**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it. * Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param columnExp the column expression * @param columnExp the column expression
...@@ -44,9 +46,9 @@ public class ColumnNamer { ...@@ -44,9 +46,9 @@ public class ColumnNamer {
* @param columnNameOverides array of overriding column names * @param columnNameOverides array of overriding column names
* @return the new column name * @return the new column name
*/ */
public String getColumnName(Expression columnExp, int indexOfColumn, String[] columnNameOverides){ public String getColumnName(Expression columnExp, int indexOfColumn, String[] columnNameOverides) {
String columnNameOverride = null; String columnNameOverride = null;
if (columnNameOverides != null && columnNameOverides.length > indexOfColumn){ if (columnNameOverides != null && columnNameOverides.length > indexOfColumn) {
columnNameOverride = columnNameOverides[indexOfColumn]; columnNameOverride = columnNameOverides[indexOfColumn];
} }
return getColumnName(columnExp, indexOfColumn, columnNameOverride); return getColumnName(columnExp, indexOfColumn, columnNameOverride);
...@@ -72,40 +74,43 @@ public class ColumnNamer { ...@@ -72,40 +74,43 @@ public class ColumnNamer {
} }
} }
// try a name from the column alias // try a name from the column alias
if (columnName==null && columnExp.getAlias()!=null && !DEFAULT_COLUMN_NAME.equals(columnExp.getAlias())){ if (columnName==null && columnExp.getAlias()!=null &&
!DEFAULT_COLUMN_NAME.equals(columnExp.getAlias())) {
columnName = columnExp.getAlias(); columnName = columnExp.getAlias();
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
} }
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = null; columnName = null;
} }
} }
// try a name derived from the column expression SQL // try a name derived from the column expression SQL
if (columnName==null && columnExp.getColumnName()!=null && !DEFAULT_COLUMN_NAME.equals(columnExp.getColumnName())){ if (columnName == null && columnExp.getColumnName() != null &&
!DEFAULT_COLUMN_NAME.equals(columnExp.getColumnName())) {
columnName = columnExp.getColumnName(); columnName = columnExp.getColumnName();
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
} }
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = null; columnName = null;
} }
} }
// try a name derived from the column expression plan SQL // try a name derived from the column expression plan SQL
if (columnName==null && columnExp.getSQL()!=null && !DEFAULT_COLUMN_NAME.equals(columnExp.getSQL())){ if (columnName == null && columnExp.getSQL() != null &&
!DEFAULT_COLUMN_NAME.equals(columnExp.getSQL())) {
columnName = columnExp.getSQL(); columnName = columnExp.getSQL();
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName); columnName = fixColumnName(columnName);
} }
if(!isAllowableColumnName(columnName)){ if (!isAllowableColumnName(columnName)) {
columnName = null; columnName = null;
} }
} }
// go with a innocuous default name pattern // go with a innocuous default name pattern
if (columnName==null){ if (columnName == null) {
columnName = configuration.getDefaultColumnNamePattern().replace("$$", ""+(indexOfColumn+1)); columnName = configuration.getDefaultColumnNamePattern().replace("$$", "" + (indexOfColumn + 1));
} }
if(existingColumnNames.contains(columnName) && configuration.isGenerateUniqueColumnNames()){ if (existingColumnNames.contains(columnName) && configuration.isGenerateUniqueColumnNames()) {
columnName = generateUniqueName(columnName); columnName = generateUniqueName(columnName);
} }
existingColumnNames.add(columnName); existingColumnNames.add(columnName);
...@@ -115,11 +120,11 @@ public class ColumnNamer { ...@@ -115,11 +120,11 @@ public class ColumnNamer {
private String generateUniqueName(String columnName) { private String generateUniqueName(String columnName) {
String newColumnName = columnName; String newColumnName = columnName;
int loopCount = 2; int loopCount = 2;
while(existingColumnNames.contains(newColumnName)){ while (existingColumnNames.contains(newColumnName)) {
String loopCountString = "_"+loopCount; String loopCountString = "_"+loopCount;
newColumnName = columnName.substring(0,Math.min(columnName.length(), configuration.getMaxIdentiferLength()-loopCountString.length()))+loopCountString; newColumnName = columnName.substring(0,
Math.min(columnName.length(), configuration.getMaxIdentiferLength() - loopCountString.length()))
+ loopCountString;
loopCount++; loopCount++;
} }
return newColumnName; return newColumnName;
...@@ -132,11 +137,11 @@ public class ColumnNamer { ...@@ -132,11 +137,11 @@ public class ColumnNamer {
return false; return false;
} }
// check size limits // check size limits
if (proposedName.length() > configuration.getMaxIdentiferLength() || proposedName.length()==0){ if (proposedName.length() > configuration.getMaxIdentiferLength() || proposedName.length() == 0) {
return false; return false;
} }
Matcher match = configuration.getCompiledRegularExpressionMatchAllowed().matcher(proposedName); Matcher match = configuration.getCompiledRegularExpressionMatchAllowed().matcher(proposedName);
if(!match.matches()){ if (!match.matches()) {
return false; return false;
} }
return true; return true;
......
...@@ -13,7 +13,7 @@ public class ColumnNamerConfiguration { ...@@ -13,7 +13,7 @@ public class ColumnNamerConfiguration {
private static final String MAX_IDENTIFIER_LENGTH = "MAX_IDENTIFIER_LENGTH = "; private static final String MAX_IDENTIFIER_LENGTH = "MAX_IDENTIFIER_LENGTH = ";
private static final String EMULATE_COMMAND = "EMULATE = "; private static final String EMULATE_COMMAND = "EMULATE = ";
private static final String GENERATE_UNIQUE_COLUMN_NAMES = "GENERATE_UNIQUE_COLUMN_NAMES = "; private static final String GENERATE_UNIQUE_COLUMN_NAMES = "GENERATE_UNIQUE_COLUMN_NAMES = ";
private int maxIdentiferLength; private int maxIdentiferLength;
private String regularExpressionMatchAllowed; private String regularExpressionMatchAllowed;
private String regularExpressionMatchDisallowed; private String regularExpressionMatchDisallowed;
...@@ -23,14 +23,15 @@ public class ColumnNamerConfiguration { ...@@ -23,14 +23,15 @@ public class ColumnNamerConfiguration {
private Pattern compiledRegularExpressionMatchDisallowed; private Pattern compiledRegularExpressionMatchDisallowed;
public ColumnNamerConfiguration(int maxIdentiferLength, String regularExpressionMatchAllowed, public ColumnNamerConfiguration(int maxIdentiferLength, String regularExpressionMatchAllowed,
String regularExpressionMatchDisallowed, String defaultColumnNamePattern, boolean generateUniqueColumnNames) { String regularExpressionMatchDisallowed, String defaultColumnNamePattern,
boolean generateUniqueColumnNames) {
this.maxIdentiferLength = maxIdentiferLength; this.maxIdentiferLength = maxIdentiferLength;
this.regularExpressionMatchAllowed = regularExpressionMatchAllowed; this.regularExpressionMatchAllowed = regularExpressionMatchAllowed;
this.regularExpressionMatchDisallowed = regularExpressionMatchDisallowed; this.regularExpressionMatchDisallowed = regularExpressionMatchDisallowed;
this.defaultColumnNamePattern = defaultColumnNamePattern; this.defaultColumnNamePattern = defaultColumnNamePattern;
this.generateUniqueColumnNames = generateUniqueColumnNames; this.generateUniqueColumnNames = generateUniqueColumnNames;
compiledRegularExpressionMatchAllowed = Pattern.compile(regularExpressionMatchAllowed); compiledRegularExpressionMatchAllowed = Pattern.compile(regularExpressionMatchAllowed);
compiledRegularExpressionMatchDisallowed = Pattern.compile(regularExpressionMatchDisallowed); compiledRegularExpressionMatchDisallowed = Pattern.compile(regularExpressionMatchDisallowed);
} }
...@@ -41,8 +42,9 @@ public class ColumnNamerConfiguration { ...@@ -41,8 +42,9 @@ public class ColumnNamerConfiguration {
public void setMaxIdentiferLength(int maxIdentiferLength) { public void setMaxIdentiferLength(int maxIdentiferLength) {
this.maxIdentiferLength = Math.max(30,maxIdentiferLength); this.maxIdentiferLength = Math.max(30,maxIdentiferLength);
if(maxIdentiferLength!=getMaxIdentiferLength()){ if (maxIdentiferLength != getMaxIdentiferLength()) {
throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES","MAX_IDENTIFIER_LENGTH="+maxIdentiferLength); throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES",
"MAX_IDENTIFIER_LENGTH=" + maxIdentiferLength);
} }
} }
...@@ -85,32 +87,35 @@ public class ColumnNamerConfiguration { ...@@ -85,32 +87,35 @@ public class ColumnNamerConfiguration {
public void setCompiledRegularExpressionMatchDisallowed(Pattern compiledRegularExpressionMatchDisallowed) { public void setCompiledRegularExpressionMatchDisallowed(Pattern compiledRegularExpressionMatchDisallowed) {
this.compiledRegularExpressionMatchDisallowed = compiledRegularExpressionMatchDisallowed; this.compiledRegularExpressionMatchDisallowed = compiledRegularExpressionMatchDisallowed;
} }
public void configure(String stringValue) { public void configure(String stringValue) {
try{ try{
if(stringValue.equalsIgnoreCase(DEFAULT_COMMAND)){ if (stringValue.equalsIgnoreCase(DEFAULT_COMMAND)) {
configure(REGULAR); configure(REGULAR);
} else if(stringValue.startsWith(EMULATE_COMMAND)){ } else if (stringValue.startsWith(EMULATE_COMMAND)) {
configure(ModeEnum.valueOf(unquoteString(stringValue.substring(EMULATE_COMMAND.length())))); configure(ModeEnum.valueOf(
} else if(stringValue.startsWith(MAX_IDENTIFIER_LENGTH)){ unquoteString(stringValue.substring(EMULATE_COMMAND.length()))));
} else if (stringValue.startsWith(MAX_IDENTIFIER_LENGTH)) {
int maxLength = Integer.parseInt(stringValue.substring(MAX_IDENTIFIER_LENGTH.length())); int maxLength = Integer.parseInt(stringValue.substring(MAX_IDENTIFIER_LENGTH.length()));
setMaxIdentiferLength(maxLength); setMaxIdentiferLength(maxLength);
} else if(stringValue.startsWith(GENERATE_UNIQUE_COLUMN_NAMES)){ } else if (stringValue.startsWith(GENERATE_UNIQUE_COLUMN_NAMES)) {
setGenerateUniqueColumnNames(Integer.parseInt(stringValue.substring(GENERATE_UNIQUE_COLUMN_NAMES.length()))==1); setGenerateUniqueColumnNames(
} else if(stringValue.startsWith(DEFAULT_COLUMN_NAME_PATTERN)){ Integer.parseInt(stringValue.substring(GENERATE_UNIQUE_COLUMN_NAMES.length())) == 1);
setDefaultColumnNamePattern(unquoteString(stringValue.substring(DEFAULT_COLUMN_NAME_PATTERN.length()))); } else if (stringValue.startsWith(DEFAULT_COLUMN_NAME_PATTERN)) {
} else if(stringValue.startsWith(REGULAR_EXPRESSION_MATCH_ALLOWED)){ setDefaultColumnNamePattern(
setRegularExpressionMatchAllowed(unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_ALLOWED.length()))); unquoteString(stringValue.substring(DEFAULT_COLUMN_NAME_PATTERN.length())));
} else if(stringValue.startsWith(REGULAR_EXPRESSION_MATCH_DISALLOWED)){ } else if (stringValue.startsWith(REGULAR_EXPRESSION_MATCH_ALLOWED)) {
setRegularExpressionMatchDisallowed(unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_DISALLOWED.length()))); setRegularExpressionMatchAllowed(
} unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_ALLOWED.length())));
else } else if (stringValue.startsWith(REGULAR_EXPRESSION_MATCH_DISALLOWED)) {
{ setRegularExpressionMatchDisallowed(
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:"+stringValue, unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_DISALLOWED.length())));
} else {
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:" + stringValue,
stringValue); stringValue);
} }
recompilePatterns(); recompilePatterns();
} }
//Including NumberFormatException|PatternSyntaxException //Including NumberFormatException|PatternSyntaxException
...@@ -118,7 +123,7 @@ public class ColumnNamerConfiguration { ...@@ -118,7 +123,7 @@ public class ColumnNamerConfiguration {
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES:"+e.getMessage(), throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES:"+e.getMessage(),
stringValue); stringValue);
} }
} }
private void recompilePatterns() { private void recompilePatterns() {
...@@ -131,12 +136,12 @@ public class ColumnNamerConfiguration { ...@@ -131,12 +136,12 @@ public class ColumnNamerConfiguration {
configure(REGULAR); configure(REGULAR);
throw e; throw e;
} }
} }
public static ColumnNamerConfiguration getDefault(){ public static ColumnNamerConfiguration getDefault(){
return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$",false); return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$",false);
} }
private static String unquoteString(String s){ private static String unquoteString(String s){
if(s.startsWith("'") && s.endsWith("'")){ if(s.startsWith("'") && s.endsWith("'")){
s = s.substring(1, s.length()-1); s = s.substring(1, s.length()-1);
...@@ -156,30 +161,31 @@ public class ColumnNamerConfiguration { ...@@ -156,30 +161,31 @@ public class ColumnNamerConfiguration {
public void configure(ModeEnum modeEnum) { public void configure(ModeEnum modeEnum) {
switch(modeEnum){ switch(modeEnum){
case Oracle: case Oracle:
// Nonquoted identifiers can contain only alphanumeric characters // Nonquoted identifiers can contain only alphanumeric characters
// from your database character set and the underscore (_), dollar sign ($), and pound sign (#). // from your database character set and the underscore (_), dollar
// sign ($), and pound sign (#).
setMaxIdentiferLength(128); setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)\"?[A-Za-z0-9_\\$#]+\"?"); setRegularExpressionMatchAllowed("(?m)(?s)\"?[A-Za-z0-9_\\$#]+\"?");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\"\\$#]"); setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\"\\$#]");
setDefaultColumnNamePattern("_UNNAMED_$$"); setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false); setGenerateUniqueColumnNames(false);
break; break;
case MSSQLServer: case MSSQLServer:
// https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server // https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
setMaxIdentiferLength(128); setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\[\\]]+");// allows [] around names setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\[\\]]+");// allows [] around names
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\[\\]]"); setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\[\\]]");
setDefaultColumnNamePattern("_UNNAMED_$$"); setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false); setGenerateUniqueColumnNames(false);
break; break;
case PostgreSQL: case PostgreSQL:
setMaxIdentiferLength(63);// this default can be changed to 128 by postgres config setMaxIdentiferLength(63);// this default can be changed to 128 by postgres config
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\$]+"); setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\$]+");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\$]"); setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\$]");
setDefaultColumnNamePattern("_UNNAMED_$$"); setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false); setGenerateUniqueColumnNames(false);
break; break;
case MySQL: case MySQL:
...@@ -190,7 +196,7 @@ public class ColumnNamerConfiguration { ...@@ -190,7 +196,7 @@ public class ColumnNamerConfiguration {
setDefaultColumnNamePattern("_UNNAMED_$$"); setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false); setGenerateUniqueColumnNames(false);
break; break;
default: default:
case REGULAR: case REGULAR:
case DB2: case DB2:
...@@ -204,7 +210,7 @@ public class ColumnNamerConfiguration { ...@@ -204,7 +210,7 @@ public class ColumnNamerConfiguration {
setGenerateUniqueColumnNames(false); setGenerateUniqueColumnNames(false);
break; break;
} }
recompilePatterns(); recompilePatterns();
} }
} }
\ No newline at end of file
...@@ -55,17 +55,19 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -55,17 +55,19 @@ public class TestCompatibilityOracle extends TestBase {
stat.execute("insert into T values(1)"); stat.execute("insert into T values(1)");
stat.execute("drop table T"); stat.execute("drop table T");
// can set NULL // can set NULL
stat.execute("create table T (C int not null disable)"); // can set NULL even with 'not null syntax' (oracle) // can set NULL even with 'not null syntax' (oracle)
stat.execute("create table T (C int not null disable)");
stat.execute("insert into T values(null)"); stat.execute("insert into T values(null)");
stat.execute("drop table T"); 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) // can set NULL even with 'not null syntax' (oracle)
stat.execute("create table T (C int not null enable novalidate)");
stat.execute("insert into T values(null)"); stat.execute("insert into T values(null)");
stat.execute("drop table T"); stat.execute("drop table T");
// Some other variation with oracle syntax // Some other variation with oracle syntax
stat.execute("create table T (C int not null)"); stat.execute("create table T (C int not null)");
stat.execute("insert into T values(1)"); stat.execute("insert into T values(1)");
stat.execute("alter table T modify C not null"); stat.execute("alter table T modify C not null");
stat.execute("insert into T values(1)"); stat.execute("insert into T values(1)");
stat.execute("alter table T modify C not null enable"); stat.execute("alter table T modify C not null enable");
stat.execute("insert into T values(1)"); stat.execute("insert into T values(1)");
...@@ -78,17 +80,19 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -78,17 +80,19 @@ public class TestCompatibilityOracle extends TestBase {
stat.execute("alter table T modify C null enable"); stat.execute("alter table T modify C null enable");
stat.execute("alter table T modify C null enable validate"); stat.execute("alter table T modify C null enable validate");
stat.execute("insert into T values(null)"); 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) // can set NULL even with 'not null syntax' (oracle)
stat.execute("alter table T modify C not null disable");
stat.execute("insert into T values(null)"); 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) // can set NULL even with 'not null syntax' (oracle)
stat.execute("alter table T modify C not null enable novalidate");
stat.execute("insert into T values(null)"); stat.execute("insert into T values(null)");
stat.execute("drop table T"); stat.execute("drop table T");
conn.close(); conn.close();
} }
private void testSpecialTypes() throws SQLException { private void testSpecialTypes() throws SQLException {
// Test VARCHAR, VARCHAR2 with CHAR and BYTE // Test VARCHAR, VARCHAR2 with CHAR and BYTE
deleteDb("oracle"); deleteDb("oracle");
Connection conn = getConnection("oracle;MODE=Oracle"); Connection conn = getConnection("oracle;MODE=Oracle");
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
...@@ -96,7 +100,7 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -96,7 +100,7 @@ public class TestCompatibilityOracle extends TestBase {
stat.execute("alter table T add A_1 VARCHAR(1)"); stat.execute("alter table T add A_1 VARCHAR(1)");
stat.execute("alter table T add A_2 VARCHAR2(1)"); stat.execute("alter table T add A_2 VARCHAR2(1)");
stat.execute("alter table T add B_1 VARCHAR(1 byte)"); // with BYTE stat.execute("alter table T add B_1 VARCHAR(1 byte)"); // with BYTE
stat.execute("alter table T add B_2 VARCHAR2(1 byte)"); stat.execute("alter table T add B_2 VARCHAR2(1 byte)");
stat.execute("alter table T add C_1 VARCHAR(1 char)"); // with CHAR stat.execute("alter table T add C_1 VARCHAR(1 char)"); // with CHAR
stat.execute("alter table T add C_2 VARCHAR2(1 char)"); stat.execute("alter table T add C_2 VARCHAR2(1 char)");
stat.execute("alter table T add B_255 VARCHAR(255 byte)"); stat.execute("alter table T add B_255 VARCHAR(255 byte)");
...@@ -104,7 +108,7 @@ public class TestCompatibilityOracle extends TestBase { ...@@ -104,7 +108,7 @@ public class TestCompatibilityOracle extends TestBase {
stat.execute("drop table T"); stat.execute("drop table T");
conn.close(); 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");
......
...@@ -390,7 +390,7 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -390,7 +390,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
private void testNestedSQL() throws Exception { private void testNestedSQL() throws Exception {
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries"); Connection conn = getConnection("commonTableExpressionQueries");
...@@ -438,7 +438,7 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -438,7 +438,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
} }
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
private void testColumnNames() throws Exception { private void testColumnNames() throws Exception {
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
...@@ -469,18 +469,37 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -469,18 +469,37 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
private void testRecursiveTable() throws Exception { private void testRecursiveTable() throws Exception {
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"}; String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
String[] expectedColumnNames =new String[]{"VAL", String[] expectedColumnNames =new String[]{"VAL",
"SUM(SELECT\n X\nFROM PUBLIC.\"\" BB\n /* SELECT\n SUM(1) AS X,\n A\n FROM PUBLIC.B\n /++ PUBLIC.B.tableScan ++/\n /++ WHERE A IS ?1\n ++/\n /++ scanCount: 4 ++/\n INNER JOIN PUBLIC.C\n /++ PUBLIC.C.tableScan ++/\n ON 1=1\n WHERE (A IS ?1)\n AND (B.VAL = C.B)\n GROUP BY A: A IS A.VAL\n */\n /* scanCount: 1 */\nWHERE BB.A IS A.VAL)"}; "SUM(SELECT\n" +
" X\n" +
"FROM PUBLIC.\"\" BB\n" +
" /* SELECT\n" +
" SUM(1) AS X,\n" +
" A\n" +
" FROM PUBLIC.B\n" +
" /++ PUBLIC.B.tableScan ++/\n" +
" /++ WHERE A IS ?1\n" +
" ++/\n" +
" /++ scanCount: 4 ++/\n" +
" INNER JOIN PUBLIC.C\n" +
" /++ PUBLIC.C.tableScan ++/\n" +
" ON 1=1\n" +
" WHERE (A IS ?1)\n" +
" AND (B.VAL = C.B)\n" +
" GROUP BY A: A IS A.VAL\n" +
" */\n" +
" /* scanCount: 1 */\n" +
"WHERE BB.A IS A.VAL)"};
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries"); Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep; PreparedStatement prep;
ResultSet rs; ResultSet rs;
String SETUP_SQL = String SETUP_SQL =
"DROP TABLE IF EXISTS A; " "DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; " +"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; " +"DROP TABLE IF EXISTS C; "
...@@ -527,7 +546,7 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -527,7 +546,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null); assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null);
assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex)); assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex));
} }
int rowNdx=0; int rowNdx=0;
while (rs.next()) { while (rs.next()) {
StringBuffer buf = new StringBuffer(); StringBuffer buf = new StringBuffer();
...@@ -544,5 +563,5 @@ public class TestGeneralCommonTableQueries extends TestBase { ...@@ -544,5 +563,5 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close(); conn.close();
deleteDb("commonTableExpressionQueries"); deleteDb("commonTableExpressionQueries");
} }
} }
\ No newline at end of file
...@@ -38,89 +38,122 @@ public class TestMergeUsing extends TestBase implements Trigger { ...@@ -38,89 +38,122 @@ public class TestMergeUsing extends TestBase implements Trigger {
// Simple ID,NAME inserts, target table with PK initially empty // Simple ID,NAME inserts, target table with PK initially empty
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );", "CREATE TABLE PARENT(ID INT, NAME VARCHAR, PRIMARY KEY(ID) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)", "MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME " +
"FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) " +
"WHEN MATCHED THEN " +
"UPDATE SET P.NAME = S.NAME WHERE 2 = 2 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 2); "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 2);
// Simple NAME updates, target table missing PK // Simple NAME updates, target table missing PK
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE 1 = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S " +
"ON (P.ID = S.ID AND 1=1 AND S.ID = P.ID) " +
"WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE 1 = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)",
2); 2);
// No NAME updates, WHERE clause is always false, insert clause missing // No NAME updates, WHERE clause is always false, insert clause missing
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE 1 = 2", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) " +
"WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE 1 = 2",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 0); "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 0);
// No NAME updates, no WHERE clause, insert clause missing // No NAME updates, no WHERE clause, insert clause missing
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) " +
"WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)",
2); 2);
// Two delete updates done, no WHERE clause, insert clause missing // Two delete updates done, no WHERE clause, insert clause missing
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN DELETE", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) ) AS S ON (P.ID = S.ID) " +
"WHEN MATCHED THEN DELETE",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) WHERE 1=0", "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) WHERE 1=0",
2); 2);
// One insert, one update one delete happens, target table missing PK // One insert, one update one delete happens, target table missing PK
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) " +
"WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 " +
"DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3); 3);
// No updates happen: No insert defined, no update or delete happens due // No updates happen: No insert defined, no update or delete happens due
// to ON condition failing always, target table missing PK // to ON condition failing always, target table missing PK
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID AND 1=0) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID AND 1=0) " +
"WHEN MATCHED THEN " +
"UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 0); "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 0);
// One insert, one update one delete happens, target table missing PK // One insert, one update one delete happens, target table missing PK
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );" +
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT AS P USING SOURCE AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)", "MERGE INTO PARENT AS P USING SOURCE AS S ON (P.ID = S.ID) WHEN MATCHED THEN " +
"UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3); 3);
// One insert, one update one delete happens, target table missing PK, // One insert, one update one delete happens, target table missing PK,
// no source alias // no source alias
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );" +
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT AS P USING SOURCE ON (P.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET P.NAME = SOURCE.NAME||SOURCE.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT AS P USING SOURCE ON (P.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET P.NAME = SOURCE.NAME||SOURCE.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 " +
"WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3); 3);
// One insert, one update one delete happens, target table missing PK, // One insert, one update one delete happens, target table missing PK,
// no source or target alias // no source or target alias
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );" +
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3); 3);
// Only insert clause, no update or delete clauses // Only insert clause, no update or delete clauses
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" +
+ "DELETE FROM PARENT;", "DELETE FROM PARENT;",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) " +
"WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3)", 3); "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3)", 3);
// no insert, no update, no delete clauses - essentially a no-op // no insert, no update, no delete clauses - essentially a no-op
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );"
+ "DELETE FROM PARENT;", + "DELETE FROM PARENT;",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID)", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) WHERE X<0", "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) WHERE X<0",
0, 0,
...@@ -129,7 +162,10 @@ public class TestMergeUsing extends TestBase implements Trigger { ...@@ -129,7 +162,10 @@ public class TestMergeUsing extends TestBase implements Trigger {
// parent table // parent table
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) )", "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) )",
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = P.NAME||S.ID WHERE P.ID = 1 DELETE WHERE P.ID = 1 AND P.NAME = 'Marcy11'", "MERGE INTO PARENT AS P USING (" +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) ) AS S ON (P.ID = S.ID) " +
"WHEN MATCHED THEN " +
"UPDATE SET P.NAME = P.NAME||S.ID WHERE P.ID = 1 DELETE WHERE P.ID = 1 AND P.NAME = 'Marcy11'",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) WHERE X<0", "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) WHERE X<0",
2); 2);
...@@ -141,9 +177,12 @@ public class TestMergeUsing extends TestBase implements Trigger { ...@@ -141,9 +177,12 @@ public class TestMergeUsing extends TestBase implements Trigger {
// One insert, one update one delete happens (on same row) , target // One insert, one update one delete happens (on same row) , target
// table missing PK, no source or target alias // table missing PK, no source or target alias
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" +
+ "CREATE TABLE SOURCE AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );", "CREATE TABLE SOURCE AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'", "SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'",
2); 2);
...@@ -157,41 +196,61 @@ public class TestMergeUsing extends TestBase implements Trigger { ...@@ -157,41 +196,61 @@ public class TestMergeUsing extends TestBase implements Trigger {
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );"
+ "CREATE TABLE SOURCE AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", + "CREATE TABLE SOURCE AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'", "SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'",
3, 3,
"Unique index or primary key violation: \"Merge using ON column expression, duplicate _ROWID_ target record already updated, deleted or inserted:_ROWID_=2:in:PUBLIC.PARENT:conflicting source row number:2"); "Unique index or primary key violation: \"Merge using " +
"ON column expression, duplicate _ROWID_ target record " +
"already updated, deleted or inserted:_ROWID_=2:in:PUBLIC.PARENT:conflicting source row number:2");
// Duplicate key updated 3 rows at once, only 1 expected // Duplicate key updated 3 rows at once, only 1 expected
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );" "CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );"
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", + "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3, "Duplicate key updated 3 rows at once, only 1 expected"); 3, "Duplicate key updated 3 rows at once, only 1 expected");
// Missing target columns in ON expression // Missing target columns in ON expression
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );" "CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );"
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", + "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (1 = SOURCE.ID) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (1 = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3, "No references to target columns found in ON clause"); 3, "No references to target columns found in ON clause");
// Missing source columns in ON expression // Missing source columns in ON expression
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );" "CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );"
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", + "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = 1) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (PARENT.ID = 1) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)", "SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(2,2) UNION ALL " +
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(3,3)",
3, "No references to source columns found in ON clause"); 3, "No references to source columns found in ON clause");
// Insert does not insert correct values with respect to ON condition // Insert does not insert correct values with respect to ON condition
// (inserts ID value above 100, instead) // (inserts ID value above 100, instead)
testMergeUsingException( testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(4,4) );" "CREATE TABLE PARENT AS (SELECT 1 AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(4,4) );"
+ "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );", + "CREATE TABLE SOURCE AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) );",
"MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (SOURCE.ID+100, SOURCE.NAME)", "MERGE INTO PARENT USING SOURCE ON (PARENT.ID = SOURCE.ID) WHEN MATCHED THEN " +
"UPDATE SET PARENT.NAME = SOURCE.NAME||SOURCE.ID WHERE PARENT.ID = 2 " +
"DELETE WHERE PARENT.ID = 1 WHEN NOT MATCHED THEN " +
"INSERT (ID, NAME) VALUES (SOURCE.ID+100, SOURCE.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(4,4)", 1, "SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(4,4)", 1,
"Expected to find key after row inserted, but none found. Insert does not match ON condition."); "Expected to find key after row inserted, but none found. Insert does not match ON condition.");
...@@ -201,9 +260,13 @@ public class TestMergeUsing extends TestBase implements Trigger { ...@@ -201,9 +260,13 @@ public class TestMergeUsing extends TestBase implements Trigger {
testMergeUsing( testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2));" "CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2));"
+ getCreateTriggerSQL(), + getCreateTriggerSQL(),
"MERGE INTO PARENT AS P USING (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,4) ) AS S ON (P.ID = S.ID) WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)", "MERGE INTO PARENT AS P USING " +
"(SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,4) ) AS S ON (P.ID = S.ID) " +
"WHEN MATCHED THEN UPDATE SET P.NAME = S.NAME||S.ID WHERE P.ID = 2 " +
"DELETE WHERE P.ID = 1 WHEN NOT MATCHED THEN INSERT (ID, NAME) VALUES (S.ID, S.NAME)",
GATHER_ORDERED_RESULTS_SQL, GATHER_ORDERED_RESULTS_SQL,
"SELECT 2 AS ID, 'Marcy22-updated2' AS NAME UNION ALL SELECT X AS ID, 'Marcy'||X||'-inserted'||X AS NAME FROM SYSTEM_RANGE(3,4)", "SELECT 2 AS ID, 'Marcy22-updated2' AS NAME UNION ALL " +
"SELECT X AS ID, 'Marcy'||X||'-inserted'||X AS NAME FROM SYSTEM_RANGE(3,4)",
4); 4);
} }
......
...@@ -50,24 +50,24 @@ public class TestConnection extends TestBase { ...@@ -50,24 +50,24 @@ public class TestConnection extends TestBase {
assertThrows(SQLClientInfoException.class, conn).setClientInfo("server23", "SomeValue"); assertThrows(SQLClientInfoException.class, conn).setClientInfo("server23", "SomeValue");
conn.close(); conn.close();
} }
/** /**
* Test that no exception is thrown if the client info of a connection managed in a connection pool is reset * Test that no exception is thrown if the client info of a connection
* to its initial values. * managed in a connection pool is reset to its initial values.
* *
* This is needed when using h2 in websphere liberty. * This is needed when using h2 in websphere liberty.
*/ */
private void testSetInternalPropertyToInitialValue() throws SQLException { private void testSetInternalPropertyToInitialValue() throws SQLException {
// Use MySQL-mode since this allows all property names // Use MySQL-mode since this allows all property names
// (apart from h2 internal names). // (apart from h2 internal names).
Connection conn = getConnection("clientInfoMySQL;MODE=MySQL"); Connection conn = getConnection("clientInfoMySQL;MODE=MySQL");
String numServersPropertyName = "numServers"; String numServersPropertyName = "numServers";
String numServers = conn.getClientInfo(numServersPropertyName); String numServers = conn.getClientInfo(numServersPropertyName);
conn.setClientInfo(numServersPropertyName, numServers); conn.setClientInfo(numServersPropertyName, numServers);
assertEquals(conn.getClientInfo(numServersPropertyName), numServers); assertEquals(conn.getClientInfo(numServersPropertyName), numServers);
conn.close(); conn.close();
......
...@@ -1495,7 +1495,8 @@ public class TestMVTableEngine extends TestBase { ...@@ -1495,7 +1495,8 @@ public class TestMVTableEngine extends TestBase {
String dbName = getTestName() + ";MV_STORE=TRUE"; String dbName = getTestName() + ";MV_STORE=TRUE";
try (Connection conn = getConnection(dbName)) { try (Connection conn = getConnection(dbName)) {
Statement stat = conn.createStatement(); Statement stat = conn.createStatement();
stat.execute("CREATE TABLE test(id INT PRIMARY KEY, name VARCHAR) AS SELECT x, x || space(1024) || x FROM system_range(1, 1000)"); stat.execute("CREATE TABLE test(id INT PRIMARY KEY, name VARCHAR) AS " +
"SELECT x, x || space(1024) || x FROM system_range(1, 1000)");
conn.setAutoCommit(false); conn.setAutoCommit(false);
PreparedStatement prep = conn.prepareStatement("DELETE FROM test WHERE id = ?"); PreparedStatement prep = conn.prepareStatement("DELETE FROM test WHERE id = ?");
long start = System.nanoTime(); long start = System.nanoTime();
......
...@@ -106,7 +106,8 @@ public class TestFileLockProcess extends TestBase { ...@@ -106,7 +106,8 @@ public class TestFileLockProcess extends TestBase {
} }
proc.waitFor(); proc.waitFor();
// The travis build somehow generates messages like this from javac. No idea where it is coming from. // The travis build somehow generates messages like this from javac.
// No idea where it is coming from.
String processOutput = buff.toString(); String processOutput = buff.toString();
processOutput = processOutput.replaceAll("Picked up _JAVA_OPTIONS: -Xmx2048m -Xms512m", "").trim(); processOutput = processOutput.replaceAll("Picked up _JAVA_OPTIONS: -Xmx2048m -Xms512m", "").trim();
......
...@@ -368,7 +368,8 @@ public class TestPgServer extends TestBase { ...@@ -368,7 +368,8 @@ public class TestPgServer extends TestBase {
return; return;
} }
// Sometimes the previous pg server has not finished shutting and we get "port in use", so sleep for a bit. // Sometimes the previous pg server has not finished shutting and we get
// "port in use", so sleep for a bit.
Thread.sleep(100); Thread.sleep(100);
Server server = Server.createPgServer( Server server = Server.createPgServer(
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论