Index: java/tools/org/apache/derby/impl/tools/ij/ij.jj =================================================================== --- java/tools/org/apache/derby/impl/tools/ij/ij.jj (revision 321268) +++ java/tools/org/apache/derby/impl/tools/ij/ij.jj (working copy) @@ -32,6 +32,7 @@ import java.lang.reflect.*; import java.sql.Connection; +import java.sql.DatabaseMetaData; import java.sql.DriverManager; import java.sql.Statement; import java.sql.PreparedStatement; @@ -298,19 +299,32 @@ haveConnection(); aStatement = theConnection.createStatement(); - // for JCC or DNC - remove comments at the beginning of the statement - // and trim - if ((currentConnEnv != null) && - ((currentConnEnv.getSession().getIsJCC()) || - currentConnEnv.getSession().getIsDNC())) - { - int nextline; - while(stmt.startsWith("--")) - { - nextline = stmt.indexOf('\n')+1; - stmt = stmt.substring(nextline); + // for JCC - remove comments at the beginning of the statement + // and trim; do the same for Derby Clients that have versions + // earlier than 10.2. + if (currentConnEnv != null) { + boolean trimForDNC = currentConnEnv.getSession().getIsDNC(); + if (trimForDNC) { + // we're using the Derby Client, but we only want to trim + // if the version is earlier than 10.2. + DatabaseMetaData dbmd = theConnection.getMetaData(); + int majorVersion = dbmd.getDriverMajorVersion(); + if ((majorVersion > 10) || ((majorVersion == 10) && + (dbmd.getDriverMinorVersion() > 1))) + { // 10.2 or later, so don't trim/remove comments. + trimForDNC = false; + } } - stmt = stmt.trim(); + if (currentConnEnv.getSession().getIsJCC() || trimForDNC) { + // remove comments and trim. + int nextline; + while(stmt.startsWith("--")) + { + nextline = stmt.indexOf('\n')+1; + stmt = stmt.substring(nextline); + } + stmt = stmt.trim(); + } } aStatement.execute(stmt); Index: java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj =================================================================== --- java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (revision 321268) +++ java/engine/org/apache/derby/impl/sql/compile/sqlgrammar.jj (working copy) @@ -1583,7 +1583,7 @@ SKIP : { /* comments */ - + } /* Index: java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/nullSQLText.java =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/nullSQLText.java (revision 321268) +++ java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/nullSQLText.java (working copy) @@ -31,11 +31,13 @@ import java.sql.Types; import org.apache.derby.tools.ij; +import org.apache.derbyTesting.functionTests.util.TestUtil; import org.apache.derbyTesting.functionTests.util.JDBCTestDisplayUtil; /** * Test of null strings in prepareStatement and execute - * result set + * result set. Also test comments in SQL text that is + * passed to an "execute" call. * * @author peachey */ @@ -98,6 +100,10 @@ System.out.println("FAIL -- expected exception"); dumpSQLExceptions(e); } + + // Test comments in statements. + derby522(s); + con.close(); } catch (SQLException e) { @@ -118,4 +124,134 @@ } } + + /* **** + * Derby-522: When a statement with comments at the front + * is passed through to an "execute" call, the client throws + * error X0Y79 ("executeUpdate cannot be called with a statement + * that returns a result set"). The same thing works fine + * against Derby embedded. This method executes several + * statements that have comments preceding them; with the + * fix for DERBY-522, these should all either pass or + * throw the correct syntax errors (i.e. the client should + * behave the same way as embedded). + */ + private static void derby522(Statement st) throws Exception + { + System.out.println("Starting test for DERBY-522."); + + st.execute("create table t1 (i int)"); + st.execute("insert into t1 values 1, 2, 3, 4, 5, 6, 7"); + st.execute("create procedure proc1() language java " + + "parameter style java dynamic result sets 1 " + + "external name 'org.apache.derbyTesting.functionTests." + + "tests.jdbcapi.nullSQLText.sp1'"); + + // These we expect to fail with syntax errors, as in embedded mode. + testCommentStmt(st, " --", true); + testCommentStmt(st, " -- ", true); + testCommentStmt(st, " -- This is a comment \n --", true); + testCommentStmt( + st, + " -- This is a comment\n --And another\n -- Andonemore", + true); + + // These we expect to return valid results for embedded and + // Derby Client (as of DERBY-522 fix); for JCC, these will + // fail. + testCommentStmt(st, " --\nvalues 2, 4, 8", TestUtil.isJCCFramework()); + testCommentStmt( + st, + " -- This is \n -- \n --3 comments\nvalues 8", + TestUtil.isJCCFramework()); + testCommentStmt( + st, + " -- This is a comment\n --And another\n -- Andonemore\nvalues (2,3)", + TestUtil.isJCCFramework()); + testCommentStmt(st, + " -- This is a comment\n select i from t1", + TestUtil.isJCCFramework()); + testCommentStmt(st, + " --singleword\n insert into t1 values (8)", + TestUtil.isJCCFramework()); + testCommentStmt(st, + " --singleword\ncall proc1()", + TestUtil.isJCCFramework()); + testCommentStmt(st, + " -- leading comment\n(\nvalues 4, 8)", + TestUtil.isJCCFramework()); + testCommentStmt(st, + " -- leading comment\n\n(\n\n\rvalues 4, 8)", + TestUtil.isJCCFramework()); + + // While we're at it, test comments in the middle and end of the + // statement. Prior to the patch for DERBY-522, statements + // ending with a comment threw syntax errors; that problem + // was fixed with DERBY-522, as well, so all of these should now + // succeed in all modes (embedded, Derby Client, and JCC). + testCommentStmt(st, "select i from t1 -- This is a comment", false); + testCommentStmt(st, "select i from t1\n -- This is a comment", false); + testCommentStmt(st, "values 8, 4, 2\n --", false); + testCommentStmt(st, "values 8, 4,\n -- middle comment\n2\n -- end", false); + testCommentStmt(st, "values 8, 4,\n -- middle comment\n2\n -- end\n", false); + + // Clean-up. + try { + st.execute("drop table t1"); + } catch (SQLException se) {} + try { + st.execute("drop procedure proc1"); + } catch (SQLException se) {} + + st.close(); + System.out.println("DERBY-522 test completed."); + } + + /* **** + * Helper method for derby522. + */ + private static void testCommentStmt(Statement st, String sql, + boolean expectError) throws SQLException + { + + try { + + System.out.println("[ Test Statement ]:\n" + sql); + st.execute(sql); + System.out.print("[ Results ]: "); + ResultSet rs = st.getResultSet(); + if (rs != null) { + while (rs.next()) + System.out.print(" " + rs.getInt(1)); + System.out.println(); + } + else + System.out.println("(NO RESULT SET)"); + + } catch (SQLException se) { + + if (expectError) + System.out.print("[ EXPECTED ERROR ]: "); + else + System.out.print("[ FAILED ]: "); + dumpSQLExceptions(se); + + } + + } + + /* **** + * Helper method for derby522. + */ + public static void sp1(ResultSet [] rs) throws SQLException { + + Connection conn = DriverManager.getConnection( + "jdbc:default:connection"); + + Statement st = conn.createStatement(); + rs[0] = st.executeQuery("select i from t1"); + return; + + } + } Index: java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/nullSQLText.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/nullSQLText.out (revision 0) +++ java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/nullSQLText.out (revision 0) @@ -0,0 +1,92 @@ +Test nullSQLText starting +Test prepareStatement with null argument +FAIL -- expected exception +Null SQL String Exception +Test execute with null argument +FAIL -- expected exception +Null SQL String Exception +Test executeQuery with null argument +FAIL -- expected exception +Null SQL String Exception +Test executeUpdate with null argument +FAIL -- expected exception +Null SQL String Exception +Starting test for DERBY-522. +[ Test Statement ]: + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 1, column 2. +[ Test Statement ]: + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 1, column 2. +[ Test Statement ]: + -- This is a comment + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 2, column 3. +[ Test Statement ]: + -- This is a comment + --And another + -- Andonemore +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 3, column 14. +[ Test Statement ]: + -- +values 2, 4, 8 +[ EXPECTED ERROR ]: Invalid Method Returning a ResultSet or Row Count SQL Exception +[ Test Statement ]: + -- This is + -- + --3 comments +values 8 +[ EXPECTED ERROR ]: Invalid Method Returning a ResultSet or Row Count SQL Exception +[ Test Statement ]: + -- This is a comment + --And another + -- Andonemore +values (2,3) +[ EXPECTED ERROR ]: Invalid Method Returning a ResultSet or Row Count SQL Exception +[ Test Statement ]: + -- This is a comment + select i from t1 +[ EXPECTED ERROR ]: Invalid Method Returning a ResultSet or Row Count SQL Exception +[ Test Statement ]: + --singleword + insert into t1 values (8) +[ Results ]: (NO RESULT SET) +[ Test Statement ]: + --singleword +call proc1() +[ Results ]: (NO RESULT SET) +[ Test Statement ]: + -- leading comment +( +values 4, 8) +[ EXPECTED ERROR ]: Invalid Method Returning a ResultSet or Row Count SQL Exception +[ Test Statement ]: + -- leading comment +( +values 4, 8) +[ EXPECTED ERROR ]: Invalid Method Returning a ResultSet or Row Count SQL Exception +[ Test Statement ]: +select i from t1 -- This is a comment +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: +select i from t1 + -- This is a comment +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: +values 8, 4, 2 + -- +[ Results ]: 8 4 2 +[ Test Statement ]: +values 8, 4, + -- middle comment +2 + -- end +[ Results ]: 8 4 2 +[ Test Statement ]: +values 8, 4, + -- middle comment +2 + -- end +[ Results ]: 8 4 2 +DERBY-522 test completed. +Test nullSQLText finished Property changes on: java/testing/org/apache/derbyTesting/functionTests/master/DerbyNet/nullSQLText.out ___________________________________________________________________ Name: svn:eol-style + native Index: java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/syscat.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/syscat.out (revision 321268) +++ java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/syscat.out (working copy) @@ -536,7 +536,23 @@ ----- verify the consistency of the indexes on the system catalogs select tablename, SYSCS_UTIL.SYSCS_CHECK_TABLE('SYS', tablename) from sys.systables where tabletype = 'S' and tablename != 'SYSDUMMY1'; -ERROR X0Y79: Statement.executeUpdate() cannot be called with a statement that returns a ResultSet. +TABLENAME |2 +----- +SYSCONGLOMERATES |1 +SYSTABLES |1 +SYSCOLUMNS |1 +SYSSCHEMAS |1 +SYSCONSTRAINTS |1 +SYSKEYS |1 +SYSDEPENDS |1 +SYSALIASES |1 +SYSVIEWS |1 +SYSCHECKS |1 +SYSFOREIGNKEYS |1 +SYSSTATEMENTS |1 +SYSFILES |1 +SYSTRIGGERS |1 +SYSSTATISTICS |1 ij> -- drop views drop view dummyview; 0 rows inserted/updated/deleted Index: java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out (revision 321268) +++ java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/forupdate.out (working copy) @@ -20,7 +20,7 @@ ij> -- . leave out some keywords (for, update, read, only) ----- results: all of these should get syntax errors for missing/inappropriate keywords select i, v from t1 for; -ERROR 42X01: Syntax error: Encountered "" at line 1, column 23. +ERROR 42X01: Syntax error: Encountered "" at line 3, column 23. ij> select i, v from t1 for read; ERROR 42X01: Syntax error: Encountered "" at line 1, column 28. ij> select i, v from t1 for only; @@ -177,7 +177,7 @@ ij> -- . try using qualified column name ----- expect an error, only unqualified names are expected (SQL92 spec): select i from t1 for update of t1.v, t1.i, t1.d; -ERROR 42X01: Syntax error: Encountered "." at line 1, column 34. +ERROR 42X01: Syntax error: Encountered "." at line 3, column 34. ij> -- . for update when select list has expressions and correlation name in use, ----- and column is repeated ----- this is allowed: Index: java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/nullSQLText.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/nullSQLText.out (revision 0) +++ java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/nullSQLText.out (revision 0) @@ -0,0 +1,92 @@ +Test nullSQLText starting +Test prepareStatement with null argument +FAIL -- expected exception +Null SQL String Exception +Test execute with null argument +FAIL -- expected exception +Null SQL String Exception +Test executeQuery with null argument +FAIL -- expected exception +Null SQL String Exception +Test executeUpdate with null argument +FAIL -- expected exception +Null SQL String Exception +Starting test for DERBY-522. +[ Test Statement ]: + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 1, column 2. +[ Test Statement ]: + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 1, column 2. +[ Test Statement ]: + -- This is a comment + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 2, column 3. +[ Test Statement ]: + -- This is a comment + --And another + -- Andonemore +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 3, column 14. +[ Test Statement ]: + -- +values 2, 4, 8 +[ Results ]: 2 4 8 +[ Test Statement ]: + -- This is + -- + --3 comments +values 8 +[ Results ]: 8 +[ Test Statement ]: + -- This is a comment + --And another + -- Andonemore +values (2,3) +[ Results ]: 2 +[ Test Statement ]: + -- This is a comment + select i from t1 +[ Results ]: 1 2 3 4 5 6 7 +[ Test Statement ]: + --singleword + insert into t1 values (8) +[ Results ]: (NO RESULT SET) +[ Test Statement ]: + --singleword +call proc1() +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: + -- leading comment +( +values 4, 8) +[ Results ]: 4 8 +[ Test Statement ]: + -- leading comment +( +values 4, 8) +[ Results ]: 4 8 +[ Test Statement ]: +select i from t1 -- This is a comment +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: +select i from t1 + -- This is a comment +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: +values 8, 4, 2 + -- +[ Results ]: 8 4 2 +[ Test Statement ]: +values 8, 4, + -- middle comment +2 + -- end +[ Results ]: 8 4 2 +[ Test Statement ]: +values 8, 4, + -- middle comment +2 + -- end +[ Results ]: 8 4 2 +DERBY-522 test completed. +Test nullSQLText finished Property changes on: java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/nullSQLText.out ___________________________________________________________________ Name: svn:eol-style + native Index: java/testing/org/apache/derbyTesting/functionTests/master/nullSQLText.out =================================================================== --- java/testing/org/apache/derbyTesting/functionTests/master/nullSQLText.out (revision 321268) +++ java/testing/org/apache/derbyTesting/functionTests/master/nullSQLText.out (working copy) @@ -11,4 +11,82 @@ Test executeUpdate with null argument FAIL -- expected exception Null SQL String Exception -Test nullSQLText finished \ No newline at end of file +Starting test for DERBY-522. +[ Test Statement ]: + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 1, column 3. +[ Test Statement ]: + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 1, column 4. +[ Test Statement ]: + -- This is a comment + -- +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 2, column 3. +[ Test Statement ]: + -- This is a comment + --And another + -- Andonemore +[ EXPECTED ERROR ]: ERROR 42X01: Syntax error: Encountered "" at line 3, column 14. +[ Test Statement ]: + -- +values 2, 4, 8 +[ Results ]: 2 4 8 +[ Test Statement ]: + -- This is + -- + --3 comments +values 8 +[ Results ]: 8 +[ Test Statement ]: + -- This is a comment + --And another + -- Andonemore +values (2,3) +[ Results ]: 2 +[ Test Statement ]: + -- This is a comment + select i from t1 +[ Results ]: 1 2 3 4 5 6 7 +[ Test Statement ]: + --singleword + insert into t1 values (8) +[ Results ]: (NO RESULT SET) +[ Test Statement ]: + --singleword +call proc1() +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: + -- leading comment +( +values 4, 8) +[ Results ]: 4 8 +[ Test Statement ]: + -- leading comment +( +values 4, 8) +[ Results ]: 4 8 +[ Test Statement ]: +select i from t1 -- This is a comment +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: +select i from t1 + -- This is a comment +[ Results ]: 1 2 3 4 5 6 7 8 +[ Test Statement ]: +values 8, 4, 2 + -- +[ Results ]: 8 4 2 +[ Test Statement ]: +values 8, 4, + -- middle comment +2 + -- end +[ Results ]: 8 4 2 +[ Test Statement ]: +values 8, 4, + -- middle comment +2 + -- end +[ Results ]: 8 4 2 +DERBY-522 test completed. +Test nullSQLText finished Index: java/client/org/apache/derby/client/am/Statement.java =================================================================== --- java/client/org/apache/derby/client/am/Statement.java (revision 321268) +++ java/client/org/apache/derby/client/am/Statement.java (working copy) @@ -1799,13 +1799,58 @@ // Should investigate if it can be optimized.. if we can avoid this parsing.. // void parseSqlAndSetSqlModes(String sql) throws SqlException { - java.util.StringTokenizer tokenizer = new java.util.StringTokenizer(sql, "\t\n\r\f=? ("); + String delims = "\t\n\r\f=? ("; + java.util.StringTokenizer tokenizer = null; + String firstToken = null; + + // See if the statement starts with a comment; if so, move + // past the comment and get the first token of the actual + // statement to be executed. Note: must use "startsWith" + // when looking for the comment delimiters instead of + // "equals" because there may not be whitespace between the + // the delimiter and the comment itself, ex "--my comment". + if (sql.trim().startsWith("--")) { + + // Read each line of the statement until we find a + // line that is NOT a comment. + int lastEndLine = -1; + String endline = "\n\r\f"; + tokenizer = new java.util.StringTokenizer(sql, endline, true); + while (tokenizer.hasMoreTokens()) { + firstToken = tokenizer.nextToken(); + if (endline.indexOf(firstToken) != -1) + // this is some sort of newline ("\n", "\r", or "\f"). + lastEndLine = sql.indexOf(firstToken, lastEndLine+1); + else if (!firstToken.trim().startsWith("--")) + break; + } + + if (firstToken.startsWith("--")) { + // entire statement was just one or more comments; pass it as + // a query to the server and let the server deal with it. + sqlMode_ = isQuery__; + return; + } + else { + // we have a non-comment line; get a tokenizer for the + // statement beginning at the start of this line. + tokenizer = new java.util.StringTokenizer( + sql.substring(lastEndLine+1), delims); + } + + } + else { + // there aren't any leading comments, so just get the first token + // in the SQL statement. + tokenizer = new java.util.StringTokenizer(sql, delims); + } + if (!tokenizer.hasMoreTokens()) { throw new SqlException(agent_.logWriter_, "SQL passed with no tokens"); } sqlUpdateMode_ = 0; - String firstToken = tokenizer.nextToken(); + firstToken = tokenizer.nextToken(); if (firstToken.equalsIgnoreCase("select") || // captures production firstToken.equalsIgnoreCase("values")) // captures production