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

Formatting

上级 e24546ea
......@@ -5291,8 +5291,9 @@ public class Parser {
ArrayList<Expression> withExpressions = theQuery.getExpressions();
for (int i = 0; i < withExpressions.size(); ++i) {
Expression columnExp = withExpressions.get(i);
// use the passed in column name if supplied, otherwise use alias (if found) otherwise use column name
// derived from column expression
// use the passed in column name if supplied, otherwise use alias
// (if found) otherwise use column name derived from column
// expression
String columnName = columnNamer.getColumnName(columnExp,i,cols);
columnTemplateList.add(new Column(columnName,
columnExp.getType()));
......
......@@ -329,9 +329,10 @@ public class AlterTableAddConstraint extends SchemaCommand {
}
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,
IndexColumn[] cols) {
if (idx.getTable() != table || !idx.getIndexType().isUnique()) {
......@@ -350,9 +351,9 @@ public class AlterTableAddConstraint extends SchemaCommand {
for (IndexColumn c : cols) {
colsSet.add(c.column);
}
return colsSet.equals(indexColsSet);
}
}
private static boolean canUseIndex(Index existingIndex, Table table,
IndexColumn[] cols, boolean moreColumnsOk) {
......
......@@ -245,7 +245,8 @@ public class MergeUsing extends Prepared {
// throw and exception if we have processed this _ROWID_ before...
if (targetRowidsRemembered.containsKey(targetRowIdValue[0])) {
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:"
+ targetTableFilter.getTable()
+ ":conflicting source row number:"
......
......@@ -472,7 +472,8 @@ public class Constants {
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;
......
......@@ -944,6 +944,12 @@ public class Database implements DataHandler {
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) {
if (SysProperties.CHECK2) {
if (metaLockDebugging.get() == session) {
......
......@@ -376,7 +376,8 @@ public class Session extends SessionWithState {
* @param table the 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);
modificationId++;
localTempTables.remove(table.getName());
......@@ -985,7 +986,8 @@ public class Session extends SessionWithState {
modificationId++;
table.setModified();
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);
table.removeChildrenAndResources(this);
if (closeSession) {
......
......@@ -1739,11 +1739,12 @@ public class JdbcConnection extends TraceObject
+ ");");
}
checkClosed();
// no change to property: Ignore call. This early exit fixes a problem with websphere liberty
// resetting the client info of a pooled connection to its initial values.
// no change to property: Ignore call. This early exit fixes a
// problem with websphere liberty resetting the client info of a
// pooled connection to its initial values.
if (Objects.equals(value, getClientInfo(name))) {
return;
return;
}
if (isInternalProperty(name)) {
......
......@@ -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.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.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.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
......
......@@ -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.
* @param expr the column expression
......@@ -37,6 +38,7 @@ public class ColumnNamer {
public String getColumnName(Expression expr, int indexOfColumn) {
return getColumnName(expr,indexOfColumn,(String) null);
}
/**
* Create a standardized column name that isn't null and doesn't have a CR/LF in it.
* @param columnExp the column expression
......@@ -44,9 +46,9 @@ public class ColumnNamer {
* @param columnNameOverides array of overriding column names
* @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;
if (columnNameOverides != null && columnNameOverides.length > indexOfColumn){
if (columnNameOverides != null && columnNameOverides.length > indexOfColumn) {
columnNameOverride = columnNameOverides[indexOfColumn];
}
return getColumnName(columnExp, indexOfColumn, columnNameOverride);
......@@ -72,40 +74,43 @@ public class ColumnNamer {
}
}
// 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();
if(!isAllowableColumnName(columnName)){
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// 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();
if(!isAllowableColumnName(columnName)){
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
columnName = null;
}
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// 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();
if(!isAllowableColumnName(columnName)){
columnName = fixColumnName(columnName);
}
if(!isAllowableColumnName(columnName)){
columnName = null;
}
if (!isAllowableColumnName(columnName)) {
columnName = fixColumnName(columnName);
}
if (!isAllowableColumnName(columnName)) {
columnName = null;
}
}
// go with a innocuous default name pattern
if (columnName==null){
columnName = configuration.getDefaultColumnNamePattern().replace("$$", ""+(indexOfColumn+1));
if (columnName == null) {
columnName = configuration.getDefaultColumnNamePattern().replace("$$", "" + (indexOfColumn + 1));
}
if(existingColumnNames.contains(columnName) && configuration.isGenerateUniqueColumnNames()){
if (existingColumnNames.contains(columnName) && configuration.isGenerateUniqueColumnNames()) {
columnName = generateUniqueName(columnName);
}
existingColumnNames.add(columnName);
......@@ -115,11 +120,11 @@ public class ColumnNamer {
private String generateUniqueName(String columnName) {
String newColumnName = columnName;
int loopCount = 2;
while(existingColumnNames.contains(newColumnName)){
while (existingColumnNames.contains(newColumnName)) {
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++;
}
return newColumnName;
......@@ -132,11 +137,11 @@ public class ColumnNamer {
return false;
}
// check size limits
if (proposedName.length() > configuration.getMaxIdentiferLength() || proposedName.length()==0){
if (proposedName.length() > configuration.getMaxIdentiferLength() || proposedName.length() == 0) {
return false;
}
Matcher match = configuration.getCompiledRegularExpressionMatchAllowed().matcher(proposedName);
if(!match.matches()){
if (!match.matches()) {
return false;
}
return true;
......
......@@ -13,7 +13,7 @@ public class ColumnNamerConfiguration {
private static final String MAX_IDENTIFIER_LENGTH = "MAX_IDENTIFIER_LENGTH = ";
private static final String EMULATE_COMMAND = "EMULATE = ";
private static final String GENERATE_UNIQUE_COLUMN_NAMES = "GENERATE_UNIQUE_COLUMN_NAMES = ";
private int maxIdentiferLength;
private String regularExpressionMatchAllowed;
private String regularExpressionMatchDisallowed;
......@@ -23,14 +23,15 @@ public class ColumnNamerConfiguration {
private Pattern compiledRegularExpressionMatchDisallowed;
public ColumnNamerConfiguration(int maxIdentiferLength, String regularExpressionMatchAllowed,
String regularExpressionMatchDisallowed, String defaultColumnNamePattern, boolean generateUniqueColumnNames) {
String regularExpressionMatchDisallowed, String defaultColumnNamePattern,
boolean generateUniqueColumnNames) {
this.maxIdentiferLength = maxIdentiferLength;
this.regularExpressionMatchAllowed = regularExpressionMatchAllowed;
this.regularExpressionMatchDisallowed = regularExpressionMatchDisallowed;
this.defaultColumnNamePattern = defaultColumnNamePattern;
this.generateUniqueColumnNames = generateUniqueColumnNames;
compiledRegularExpressionMatchAllowed = Pattern.compile(regularExpressionMatchAllowed);
compiledRegularExpressionMatchDisallowed = Pattern.compile(regularExpressionMatchDisallowed);
}
......@@ -41,8 +42,9 @@ public class ColumnNamerConfiguration {
public void setMaxIdentiferLength(int maxIdentiferLength) {
this.maxIdentiferLength = Math.max(30,maxIdentiferLength);
if(maxIdentiferLength!=getMaxIdentiferLength()){
throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES","MAX_IDENTIFIER_LENGTH="+maxIdentiferLength);
if (maxIdentiferLength != getMaxIdentiferLength()) {
throw DbException.getInvalidValueException("Illegal value (<30) in SET COLUMN_NAME_RULES",
"MAX_IDENTIFIER_LENGTH=" + maxIdentiferLength);
}
}
......@@ -85,32 +87,35 @@ public class ColumnNamerConfiguration {
public void setCompiledRegularExpressionMatchDisallowed(Pattern compiledRegularExpressionMatchDisallowed) {
this.compiledRegularExpressionMatchDisallowed = compiledRegularExpressionMatchDisallowed;
}
public void configure(String stringValue) {
try{
if(stringValue.equalsIgnoreCase(DEFAULT_COMMAND)){
if (stringValue.equalsIgnoreCase(DEFAULT_COMMAND)) {
configure(REGULAR);
} else if(stringValue.startsWith(EMULATE_COMMAND)){
configure(ModeEnum.valueOf(unquoteString(stringValue.substring(EMULATE_COMMAND.length()))));
} else if(stringValue.startsWith(MAX_IDENTIFIER_LENGTH)){
} else if (stringValue.startsWith(EMULATE_COMMAND)) {
configure(ModeEnum.valueOf(
unquoteString(stringValue.substring(EMULATE_COMMAND.length()))));
} else if (stringValue.startsWith(MAX_IDENTIFIER_LENGTH)) {
int maxLength = Integer.parseInt(stringValue.substring(MAX_IDENTIFIER_LENGTH.length()));
setMaxIdentiferLength(maxLength);
} else if(stringValue.startsWith(GENERATE_UNIQUE_COLUMN_NAMES)){
setGenerateUniqueColumnNames(Integer.parseInt(stringValue.substring(GENERATE_UNIQUE_COLUMN_NAMES.length()))==1);
} else if(stringValue.startsWith(DEFAULT_COLUMN_NAME_PATTERN)){
setDefaultColumnNamePattern(unquoteString(stringValue.substring(DEFAULT_COLUMN_NAME_PATTERN.length())));
} else if(stringValue.startsWith(REGULAR_EXPRESSION_MATCH_ALLOWED)){
setRegularExpressionMatchAllowed(unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_ALLOWED.length())));
} else if(stringValue.startsWith(REGULAR_EXPRESSION_MATCH_DISALLOWED)){
setRegularExpressionMatchDisallowed(unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_DISALLOWED.length())));
}
else
{
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:"+stringValue,
} else if (stringValue.startsWith(GENERATE_UNIQUE_COLUMN_NAMES)) {
setGenerateUniqueColumnNames(
Integer.parseInt(stringValue.substring(GENERATE_UNIQUE_COLUMN_NAMES.length())) == 1);
} else if (stringValue.startsWith(DEFAULT_COLUMN_NAME_PATTERN)) {
setDefaultColumnNamePattern(
unquoteString(stringValue.substring(DEFAULT_COLUMN_NAME_PATTERN.length())));
} else if (stringValue.startsWith(REGULAR_EXPRESSION_MATCH_ALLOWED)) {
setRegularExpressionMatchAllowed(
unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_ALLOWED.length())));
} else if (stringValue.startsWith(REGULAR_EXPRESSION_MATCH_DISALLOWED)) {
setRegularExpressionMatchDisallowed(
unquoteString(stringValue.substring(REGULAR_EXPRESSION_MATCH_DISALLOWED.length())));
} else {
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES: unknown id:" + stringValue,
stringValue);
}
recompilePatterns();
}
//Including NumberFormatException|PatternSyntaxException
......@@ -118,7 +123,7 @@ public class ColumnNamerConfiguration {
throw DbException.getInvalidValueException("SET COLUMN_NAME_RULES:"+e.getMessage(),
stringValue);
}
}
}
private void recompilePatterns() {
......@@ -131,12 +136,12 @@ public class ColumnNamerConfiguration {
configure(REGULAR);
throw e;
}
}
}
public static ColumnNamerConfiguration getDefault(){
return new ColumnNamerConfiguration(Integer.MAX_VALUE, "(?m)(?s).+", "(?m)(?s)[\\x00]", "_UNNAMED_$$",false);
}
private static String unquoteString(String s){
if(s.startsWith("'") && s.endsWith("'")){
s = s.substring(1, s.length()-1);
......@@ -156,30 +161,31 @@ public class ColumnNamerConfiguration {
public void configure(ModeEnum modeEnum) {
switch(modeEnum){
case Oracle:
// Nonquoted identifiers can contain only alphanumeric characters
// from your database character set and the underscore (_), dollar sign ($), and pound sign (#).
// Nonquoted identifiers can contain only alphanumeric characters
// from your database character set and the underscore (_), dollar
// sign ($), and pound sign (#).
setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)\"?[A-Za-z0-9_\\$#]+\"?");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\"\\$#]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
case MSSQLServer:
// https://docs.microsoft.com/en-us/sql/sql-server/maximum-capacity-specifications-for-sql-server
setMaxIdentiferLength(128);
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\[\\]]+");// allows [] around names
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\[\\]]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
setGenerateUniqueColumnNames(false);
break;
case PostgreSQL:
setMaxIdentiferLength(63);// this default can be changed to 128 by postgres config
setRegularExpressionMatchAllowed("(?m)(?s)[A-Za-z0-9_\\$]+");
setRegularExpressionMatchDisallowed("(?m)(?s)[^A-Za-z0-9_\\$]");
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
setGenerateUniqueColumnNames(false);
break;
case MySQL:
......@@ -190,7 +196,7 @@ public class ColumnNamerConfiguration {
setDefaultColumnNamePattern("_UNNAMED_$$");
setGenerateUniqueColumnNames(false);
break;
default:
case REGULAR:
case DB2:
......@@ -204,7 +210,7 @@ public class ColumnNamerConfiguration {
setGenerateUniqueColumnNames(false);
break;
}
recompilePatterns();
recompilePatterns();
}
}
\ No newline at end of file
......@@ -55,17 +55,19 @@ public class TestCompatibilityOracle extends TestBase {
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)
// 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("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("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("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)");
......@@ -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 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)
// 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("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("drop table T");
conn.close();
}
private void testSpecialTypes() throws SQLException {
// Test VARCHAR, VARCHAR2 with CHAR and BYTE
// Test VARCHAR, VARCHAR2 with CHAR and BYTE
deleteDb("oracle");
Connection conn = getConnection("oracle;MODE=Oracle");
Statement stat = conn.createStatement();
......@@ -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_2 VARCHAR2(1)");
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_2 VARCHAR2(1 char)");
stat.execute("alter table T add B_255 VARCHAR(255 byte)");
......@@ -104,7 +108,7 @@ public class TestCompatibilityOracle extends TestBase {
stat.execute("drop table T");
conn.close();
}
private void testTreatEmptyStringsAsNull() throws SQLException {
deleteDb("oracle");
Connection conn = getConnection("oracle;MODE=Oracle");
......
......@@ -390,7 +390,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close();
deleteDb("commonTableExpressionQueries");
}
private void testNestedSQL() throws Exception {
deleteDb("commonTableExpressionQueries");
Connection conn = getConnection("commonTableExpressionQueries");
......@@ -438,7 +438,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
}
conn.close();
deleteDb("commonTableExpressionQueries");
}
}
private void testColumnNames() throws Exception {
deleteDb("commonTableExpressionQueries");
......@@ -469,18 +469,37 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close();
deleteDb("commonTableExpressionQueries");
}
private void testRecursiveTable() throws Exception {
String[] expectedRowData =new String[]{"|meat|null","|fruit|3","|veg|2"};
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");
Connection conn = getConnection("commonTableExpressionQueries");
PreparedStatement prep;
ResultSet rs;
String SETUP_SQL =
String SETUP_SQL =
"DROP TABLE IF EXISTS A; "
+"DROP TABLE IF EXISTS B; "
+"DROP TABLE IF EXISTS C; "
......@@ -527,7 +546,7 @@ public class TestGeneralCommonTableQueries extends TestBase {
assertTrue(rs.getMetaData().getColumnLabel(columnIndex)!=null);
assertEquals(expectedColumnNames[columnIndex-1],rs.getMetaData().getColumnLabel(columnIndex));
}
int rowNdx=0;
while (rs.next()) {
StringBuffer buf = new StringBuffer();
......@@ -544,5 +563,5 @@ public class TestGeneralCommonTableQueries extends TestBase {
conn.close();
deleteDb("commonTableExpressionQueries");
}
}
}
\ No newline at end of file
......@@ -38,89 +38,122 @@ public class TestMergeUsing extends TestBase implements Trigger {
// Simple ID,NAME inserts, target table with PK initially empty
testMergeUsing(
"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,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 2);
// Simple NAME updates, target table missing PK
testMergeUsing(
"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,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)",
2);
// No NAME updates, WHERE clause is always false, insert clause missing
testMergeUsing(
"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,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2)", 0);
// No NAME updates, no WHERE clause, insert clause missing
testMergeUsing(
"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,
"SELECT X AS ID, 'Marcy'||X||X AS NAME FROM SYSTEM_RANGE(1,2)",
2);
// Two delete updates done, no WHERE clause, insert clause missing
testMergeUsing(
"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,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2) WHERE 1=0",
2);
// One insert, one update one delete happens, target table missing PK
testMergeUsing(
"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,
"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 updates happen: No insert defined, no update or delete happens due
// to ON condition failing always, target table missing PK
testMergeUsing(
"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,
"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
testMergeUsing(
"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) );",
"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)",
"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) );",
"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,
"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);
// One insert, one update one delete happens, target table missing PK,
// no source alias
testMergeUsing(
"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) );",
"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)",
"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) );",
"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,
"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);
// One insert, one update one delete happens, target table missing PK,
// no source or target alias
testMergeUsing(
"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) );",
"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)",
"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) );",
"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,
"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);
// Only insert clause, no update or delete clauses
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );"
+ "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)",
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );" +
"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)",
GATHER_ORDERED_RESULTS_SQL,
"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
testMergeUsingException(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) );"
+ "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,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,3) WHERE X<0",
0,
......@@ -129,7 +162,10 @@ public class TestMergeUsing extends TestBase implements Trigger {
// parent table
testMergeUsing(
"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,
"SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,1) WHERE X<0",
2);
......@@ -141,9 +177,12 @@ public class TestMergeUsing extends TestBase implements Trigger {
// One insert, one update one delete happens (on same row) , target
// table missing PK, no source or target alias
testMergeUsing(
"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) );",
"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)",
"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) );",
"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,
"SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'",
2);
......@@ -157,41 +196,61 @@ public class TestMergeUsing extends TestBase implements Trigger {
testMergeUsingException(
"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) );",
"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,
"SELECT 1 AS ID, 'Marcy'||X||X UNION ALL SELECT 1 AS ID, 'Marcy2'",
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
testMergeUsingException(
"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) );",
"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,
"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");
// Missing target columns in ON expression
testMergeUsingException(
"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) );",
"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,
"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");
// Missing source columns in ON expression
testMergeUsingException(
"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) );",
"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,
"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");
// Insert does not insert correct values with respect to ON condition
// (inserts ID value above 100, instead)
testMergeUsingException(
"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) );",
"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,
"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.");
......@@ -201,9 +260,13 @@ public class TestMergeUsing extends TestBase implements Trigger {
testMergeUsing(
"CREATE TABLE PARENT AS (SELECT X AS ID, 'Marcy'||X AS NAME FROM SYSTEM_RANGE(1,2));"
+ 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,
"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);
}
......
......@@ -50,24 +50,24 @@ public class TestConnection extends TestBase {
assertThrows(SQLClientInfoException.class, conn).setClientInfo("server23", "SomeValue");
conn.close();
}
/**
* Test that no exception is thrown if the client info of a connection managed in a connection pool is reset
* to its initial values.
*
* Test that no exception is thrown if the client info of a connection
* managed in a connection pool is reset to its initial values.
*
* This is needed when using h2 in websphere liberty.
*/
private void testSetInternalPropertyToInitialValue() throws SQLException {
// Use MySQL-mode since this allows all property names
// (apart from h2 internal names).
Connection conn = getConnection("clientInfoMySQL;MODE=MySQL");
String numServersPropertyName = "numServers";
String numServers = conn.getClientInfo(numServersPropertyName);
conn.setClientInfo(numServersPropertyName, numServers);
assertEquals(conn.getClientInfo(numServersPropertyName), numServers);
conn.close();
......
......@@ -1495,7 +1495,8 @@ public class TestMVTableEngine extends TestBase {
String dbName = getTestName() + ";MV_STORE=TRUE";
try (Connection conn = getConnection(dbName)) {
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);
PreparedStatement prep = conn.prepareStatement("DELETE FROM test WHERE id = ?");
long start = System.nanoTime();
......
......@@ -106,7 +106,8 @@ public class TestFileLockProcess extends TestBase {
}
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();
processOutput = processOutput.replaceAll("Picked up _JAVA_OPTIONS: -Xmx2048m -Xms512m", "").trim();
......
......@@ -368,7 +368,8 @@ public class TestPgServer extends TestBase {
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);
Server server = Server.createPgServer(
......
Markdown 格式
0%
您添加了 0 到此讨论。请谨慎行事。
请先完成此评论的编辑!
注册 或者 后发表评论