You are viewing a plain text version of this content. The canonical link for it is here.
Posted to derby-commits@db.apache.org by ba...@apache.org on 2005/04/02 07:32:32 UTC
svn commit: r159758 - in incubator/derby/code/trunk/java:
engine/org/apache/derby/iapi/reference/ engine/org/apache/derby/impl/jdbc/
engine/org/apache/derby/impl/sql/compile/ engine/org/apache/derby/loc/
testing/org/apache/derbyTesting/functionTests/master/
testing/org/apache/derbyTesting/functionTests/master/jdk14/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: bandaram
Date: Fri Apr 1 21:32:30 2005
New Revision: 159758
URL: http://svn.apache.org/viewcvs?view=rev&rev=159758
Log:
Move some updatable Resultset checking to compile time, instead of at runtime.
Submitted by Mamta Satoor. (msatoor@gmail.com)
Modified:
incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java
incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java
incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatableResultSet.out
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/updatableResultSet.java
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java Fri Apr 1 21:32:30 2005
@@ -737,6 +737,7 @@
String LANG_CURSOR_UPDATE_MISMATCH = "42X29";
String LANG_CURSOR_NOT_FOUND = "42X30";
String LANG_COLUMN_NOT_UPDATABLE_IN_CURSOR = "42X31";
+ String LANG_CORRELATION_NAME_FOR_UPDATABLE_COLUMN_DISALLOWED_IN_CURSOR = "42X42";
String LANG_DERIVED_COLUMN_LIST_MISMATCH = "42X32";
String LANG_DUPLICATE_COLUMN_NAME_DERIVED = "42X33";
String LANG_PARAM_IN_SELECT_LIST = "42X34";
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java Fri Apr 1 21:32:30 2005
@@ -155,8 +155,6 @@
private int fetchDirection;
private int fetchSize;
- //td will be used to ensure the column selected for updateXXX is part of the table.
- private TableDescriptor td = null;
/**
* This class provides the glue between the Cloudscape
@@ -2038,15 +2036,25 @@
return false;
}
+ //do following few checks before accepting updateXXX resultset api
+ protected void checksBeforeUpdateXXX(String methodName, int columnIndex) throws SQLException {
+ checksBeforeUpdateOrDelete(methodName, columnIndex);
+
+ //1)Make sure for updateXXX methods, the column position is not out of range
+ ResultDescription rd = theResults.getResultDescription();
+ if (columnIndex < 1 || columnIndex > rd.getColumnCount())
+ throw Util.generateCsSQLException(SQLState.LANG_INVALID_COLUMN_POSITION, new Integer(columnIndex), String.valueOf(rd.getColumnCount()));
+
+ //2)Make sure the column corresponds to a column in the base table and it is not a derived column
+ if (rd.getColumnDescriptor(columnIndex).getSourceTableName() == null)
+ throw Util.generateCsSQLException(SQLState.COLUMN_NOT_FROM_BASE_TABLE, methodName);
+ }
+
//do following few checks before accepting updatable resultset api
//1)Make sure this is an updatable ResultSet
//2)Make sure JDBC ResultSet is not closed
//3)Make sure JDBC ResultSet is positioned on a row
//4)Make sure underneath language resultset is not closed
- //5)Make sure for updateXXX methods, the column position is not out of range
- //6)Make sure the column corresponds to a column in the base table and it is not a derived column
- //7)Make sure correlation names are not used for base table column names in updateXXXX. This is because the mapping
- // of correlation name to base table column position is not available at runtime.
protected void checksBeforeUpdateOrDelete(String methodName, int columnIndex) throws SQLException {
//1)Make sure this is an updatable ResultSet
@@ -2065,57 +2073,11 @@
//4)Make sure underneath language resultset is not closed
if (theResults.isClosed())
throw Util.generateCsSQLException(SQLState.LANG_RESULT_SET_NOT_OPEN, methodName);
-
- //the remaining checks only apply to updateXXX methods
- if (methodName.equals("updateRow") || methodName.equals("deleteRow") || methodName.equals("cancelRowUpdates"))
- return;
-
- //5)Make sure for updateXXX methods, the column position is not out of range
- ResultDescription rd = theResults.getResultDescription();
- if (columnIndex < 1 || columnIndex > rd.getColumnCount())
- throw Util.generateCsSQLException(SQLState.LANG_INVALID_COLUMN_POSITION, new Integer(columnIndex), String.valueOf(rd.getColumnCount()));
-
- //6)Make sure the column corresponds to a column in the base table and it is not a derived column
- if (rd.getColumnDescriptor(columnIndex).getSourceTableName() == null)
- throw Util.generateCsSQLException(SQLState.COLUMN_NOT_FROM_BASE_TABLE, methodName);
-
- //7)Make sure correlation names are not used for base table column names in updateXXX. This is because the mapping
- // of correlation name to base table column position is not available at runtime.
- //If can't find the column in the base table, then throw exception. This will happen if correlation name is used for column names
- if (td == null) getTargetTableDescriptor();
- if (td.getColumnDescriptor(rd.getColumnDescriptor(columnIndex).getName()) == null)
- throw Util.generateCsSQLException(SQLState.COLUMN_NOT_FROM_BASE_TABLE, methodName);
- }
-
- //Get the table descriptor for the target table for updateXXX. td will be used to ensure the column selected for updateXXX
- //is part of the table.
- private void getTargetTableDescriptor() throws SQLException {
- setupContextStack();
- try {
- LanguageConnectionContext lcc = getEmbedConnection().getLanguageConnection();
- CursorActivation activation = lcc.lookupCursorActivation(getCursorName());
- ExecCursorTableReference targetTable = activation.getPreparedStatement().getTargetTable();
- SchemaDescriptor sd = null;
- if (targetTable.getSchemaName() != null)
- sd = lcc.getDataDictionary().getSchemaDescriptor(targetTable.getSchemaName(),null, false);
- else
- sd = lcc.getDataDictionary().getSchemaDescriptor(lcc.getCurrentSchemaName(),null, false);
-
- if ((sd != null) && sd.getSchemaName().equals(SchemaDescriptor.STD_DECLARED_GLOBAL_TEMPORARY_TABLES_SCHEMA_NAME))
- td = lcc.getTableDescriptorForDeclaredGlobalTempTable(targetTable.getBaseName()); //check if this is a temp table before checking data dictionary
-
- if (td == null) //td null here means it is not a temporary table. Look for table in physical SESSION schema
- td = lcc.getDataDictionary().getTableDescriptor(targetTable.getBaseName(), sd);
- } catch (StandardException t) {
- throw noStateChangeException(t);
- } finally {
- restoreContextStack();
- }
}
//mark the column as updated and return DataValueDescriptor for it. It will be used by updateXXX methods to put new values
protected DataValueDescriptor getDVDforColumnToBeUpdated(int columnIndex, String updateMethodName) throws StandardException, SQLException {
- checksBeforeUpdateOrDelete(updateMethodName, columnIndex);
+ checksBeforeUpdateXXX(updateMethodName, columnIndex);
if (columnGotUpdated[columnIndex-1] == false) {//this is the first updateXXX call on this column
//this is the first updateXXX method call on this column. Save the original content of the column into copyOfDatabaseRow
//The saved copy of the column will be needed if cancelRowUpdates is issued
@@ -2473,7 +2435,7 @@
*/
public void updateAsciiStream(int columnIndex, java.io.InputStream x,
int length) throws SQLException {
- checksBeforeUpdateOrDelete("updateAsciiStream", columnIndex);
+ checksBeforeUpdateXXX("updateAsciiStream", columnIndex);
int colType = getColumnType(columnIndex);
switch (colType) {
@@ -2519,7 +2481,7 @@
*/
public void updateBinaryStream(int columnIndex, java.io.InputStream x,
int length) throws SQLException {
- checksBeforeUpdateOrDelete("updateBinaryStream", columnIndex);
+ checksBeforeUpdateXXX("updateBinaryStream", columnIndex);
int colType = getColumnType(columnIndex);
switch (colType) {
case Types.BINARY:
@@ -2576,8 +2538,8 @@
int length) throws SQLException {
//If the column type is the right datatype, this method will eventually call getDVDforColumnToBeUpdated which will check for
//the read only resultset. But for other datatypes, we want to catch if this updateCharacterStream is being issued
- //against a read only resultset. And that is the reason for call to checksBeforeUpdateOrDelete here.
- checksBeforeUpdateOrDelete("updateCharacterStream", columnIndex);
+ //against a read only resultset. And that is the reason for call to checksBeforeUpdateXXX here.
+ checksBeforeUpdateXXX("updateCharacterStream", columnIndex);
int colType = getColumnType(columnIndex);
switch (colType) {
case Types.CHAR:
@@ -2680,7 +2642,7 @@
* if a database-access error occurs
*/
public void updateObject(int columnIndex, Object x) throws SQLException {
- checksBeforeUpdateOrDelete("updateObject", columnIndex);
+ checksBeforeUpdateXXX("updateObject", columnIndex);
int colType = getColumnType(columnIndex);
if (colType == org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT) {
try {
@@ -3522,7 +3484,7 @@
* Feature not implemented for now.
*/
public void updateBlob(int columnIndex, Blob x) throws SQLException {
- checksBeforeUpdateOrDelete("updateBlob", columnIndex);
+ checksBeforeUpdateXXX("updateBlob", columnIndex);
int colType = getColumnType(columnIndex);
if (colType != Types.BLOB)
throw dataTypeConversion(columnIndex, "java.sql.Blob");
@@ -3568,7 +3530,7 @@
* Feature not implemented for now.
*/
public void updateClob(int columnIndex, Clob x) throws SQLException {
- checksBeforeUpdateOrDelete("updateClob", columnIndex);
+ checksBeforeUpdateXXX("updateClob", columnIndex);
int colType = getColumnType(columnIndex);
if (colType != Types.CLOB)
throw dataTypeConversion(columnIndex, "java.sql.Clob");
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/sql/compile/CursorNode.java Fri Apr 1 21:32:30 2005
@@ -716,6 +716,7 @@
int size = updatableColumns.size();
TableDescriptor tableDescriptor;
String columnName;
+ ResultColumnList rcls = resultSet.getResultColumns();
for (int index = 0; index < size; index++)
{
@@ -723,9 +724,22 @@
tableDescriptor = targetTable.getTableDescriptor();
if ( tableDescriptor.getColumnDescriptor(columnName) == null)
{
- throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, columnName);
+ throw StandardException.newException(SQLState.LANG_COLUMN_NOT_FOUND, columnName);
}
+ ResultColumn rc;
+ //make sure that we are not using correlation names for updatable columns.
+ //eg select c11 as col1, 2, c13 as col3 from t1 for update of c11, c12
+ //In the eg above, correlation name for c11 will cause exception because Derby does not support correlation name for updatable columns
+ //But correlation name for c13 is ok because it is a read only column
+ for (int rclsIndex = 0; rclsIndex < rcls.size(); rclsIndex++) {//look through each column in the resultset for cursor
+ rc = ((ResultColumn) rcls.elementAt(rclsIndex));
+ if (rc.getSourceTableName() == null) //continue to look at the next column because this is derived column in the select list
+ continue;
+ if (rc.getExpression() != null && rc.getExpression().getColumnName().equals(columnName) && !rc.getName().equals(columnName)) {
+ throw StandardException.newException(SQLState.LANG_CORRELATION_NAME_FOR_UPDATABLE_COLUMN_DISALLOWED_IN_CURSOR, columnName);
+ }
+ }
}
}
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties Fri Apr 1 21:32:30 2005
@@ -443,6 +443,7 @@
42X29=Update table ''{0}'' is not target of cursor ''{1}''.
42X30=Cursor ''{0}'' not found. Verify that autocommit is OFF.
42X31=Column ''{0}'' is not in FOR UPDATE list of cursor ''{1}''.
+42X42=Correlation name not allowed for column ''{0}'' because it is part of the FOR UPDATE list.
42X32=The number of columns in the derived column list must match the number of columns in table ''{0}''.
42X33=The derived column list contains a duplicate column name ''{0}''.
42X34=There is a ? parameter in the select list. This is not allowed.
Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out (original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out Fri Apr 1 21:32:30 2005
@@ -247,17 +247,28 @@
Positive Test9a - using correlation name for the table in the select sql is not a problem
column 1 on this row is 1
now try to deleteRow
-Positive Test9b - using correlation name for column names is not allowed with updateXXX
+Positive Test9b - using correlation name for updatable column name is not allowed
Table t1 has following rows
C1,C2
-- --
{1,aa }
{2,bb }
{3,cc }
-column 1 on this row is 1
-attempt to send updateXXX on correlation name column will fail
-SQL State : XJ084
-Got expected exception Column does not correspond to a column in the base table. Cant issue {0} on this column.
+attempt to get an updatable resultset using correlation name for an updatable column
+The sql is SELECT c1 as col1, c2 as col2 FROM t1 abcde FOR UPDATE of c1
+SQL State : 42X42
+Got expected exception Correlation name not allowed for column 'C1' because it is part of the FOR UPDATE list.
+attempt to get an updatable resultset using correlation name for an readonly column. It should work
+The sql is SELECT c1, c2 as col2 FROM t1 abcde FOR UPDATE of c1
+Table t1 after updateRow has following rows
+ C1,C2
+ -- --
+ {11,aa }
+ {2,bb }
+ {3,cc }
+Positive Test9c - try to updateXXX on a readonly column. Should get error
+SQL State : 42X31
+Got expected exception Column 'C2' is not in FOR UPDATE list of cursor 'SQLCUR15'.
Table t1 after updateRow has following rows
C1,C2
-- --
@@ -268,7 +279,7 @@
delete using first resultset
attempt to send deleteRow on the same row through a different resultset should throw an exception
SQL State : XCL08
-Got expected exception Cursor 'SQLCUR16' is not on a row.
+Got expected exception Cursor 'SQLCUR17' is not on a row.
Move to next row in the 2nd resultset and then delete using the second resultset
Positive Test11 - setting the fetch size to > 1 will be ignored by updatable resultset. Same as updatable cursors
Notice the Fetch Size in run time statistics output.
@@ -3035,7 +3046,7 @@
{2,bb }
{3,cc }
SQL State : 42X31
-Got expected exception Column 'C2' is not in FOR UPDATE list of cursor 'SQLCUR1191'.
+Got expected exception Column 'C2' is not in FOR UPDATE list of cursor 'SQLCUR536'.
Make sure the contents of table are unchanged
C1,C2
-- --
Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatableResultSet.out
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatableResultSet.out?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatableResultSet.out (original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatableResultSet.out Fri Apr 1 21:32:30 2005
@@ -247,17 +247,28 @@
Positive Test9a - using correlation name for the table in the select sql is not a problem
column 1 on this row is 1
now try to deleteRow
-Positive Test9b - using correlation name for column names is not allowed with updateXXX
+Positive Test9b - using correlation name for updatable column name is not allowed
Table t1 has following rows
C1,C2
-- --
{1,aa }
{2,bb }
{3,cc }
-column 1 on this row is 1
-attempt to send updateXXX on correlation name column will fail
-SQL State : XJ084
-Got expected exception Column does not correspond to a column in the base table. Cant issue {0} on this column.
+attempt to get an updatable resultset using correlation name for an updatable column
+The sql is SELECT c1 as col1, c2 as col2 FROM t1 abcde FOR UPDATE of c1
+SQL State : 42X42
+Got expected exception Correlation name not allowed for column 'C1' because it is part of the FOR UPDATE list.
+attempt to get an updatable resultset using correlation name for an readonly column. It should work
+The sql is SELECT c1, c2 as col2 FROM t1 abcde FOR UPDATE of c1
+Table t1 after updateRow has following rows
+ C1,C2
+ -- --
+ {11,aa }
+ {2,bb }
+ {3,cc }
+Positive Test9c - try to updateXXX on a readonly column. Should get error
+SQL State : 42X31
+Got expected exception Column 'C2' is not in FOR UPDATE list of cursor 'SQLCUR15'.
Table t1 after updateRow has following rows
C1,C2
-- --
@@ -268,7 +279,7 @@
delete using first resultset
attempt to send deleteRow on the same row through a different resultset should throw an exception
SQL State : XCL08
-Got expected exception Cursor 'SQLCUR16' is not on a row.
+Got expected exception Cursor 'SQLCUR17' is not on a row.
Move to next row in the 2nd resultset and then delete using the second resultset
Positive Test11 - setting the fetch size to > 1 will be ignored by updatable resultset. Same as updatable cursors
Notice the Fetch Size in run time statistics output.
@@ -2761,7 +2772,7 @@
{2,bb }
{3,cc }
SQL State : 42X31
-Got expected exception Column 'C2' is not in FOR UPDATE list of cursor 'SQLCUR1055'.
+Got expected exception Column 'C2' is not in FOR UPDATE list of cursor 'SQLCUR528'.
Make sure the contents of table are unchanged
C1,C2
-- --
Modified: incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/updatableResultSet.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/updatableResultSet.java?view=diff&r1=159757&r2=159758
==============================================================================
--- incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/updatableResultSet.java (original)
+++ incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/updatableResultSet.java Fri Apr 1 21:32:30 2005
@@ -946,18 +946,39 @@
rs.deleteRow();
rs.close();
- System.out.println("Positive Test9b - using correlation name for column names is not allowed with updateXXX");
+ System.out.println("Positive Test9b - using correlation name for updatable column name is not allowed");
reloadData();
stmt = conn.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
System.out.println("Table t1 has following rows");
dumpRS(stmt.executeQuery("select * from t1"));
- rs = stmt.executeQuery("SELECT c1 as col1, c2 as col2 FROM t1 abcde FOR UPDATE of c1");
+ try {
+ System.out.println("attempt to get an updatable resultset using correlation name for an updatable column");
+ System.out.println("The sql is SELECT c1 as col1, c2 as col2 FROM t1 abcde FOR UPDATE of c1");
+ rs = stmt.executeQuery("SELECT c1 as col1, c2 as col2 FROM t1 abcde FOR UPDATE of c1");
+ System.out.println("FAIL!!! executeQuery should have failed");
+ }
+ catch (SQLException e) {
+ System.out.println("SQL State : " + e.getSQLState());
+ System.out.println("Got expected exception " + e.getMessage());
+ }
+ System.out.println("attempt to get an updatable resultset using correlation name for an readonly column. It should work");
+ System.out.println("The sql is SELECT c1, c2 as col2 FROM t1 abcde FOR UPDATE of c1");
+ rs = stmt.executeQuery("SELECT c1, c2 as col2 FROM t1 abcde FOR UPDATE of c1");
+ rs.next();
+ rs.updateInt(1,11);
+ rs.updateRow();
+ rs.close();
+ System.out.println("Table t1 after updateRow has following rows");
+ dumpRS(stmt.executeQuery("select * from t1"));
+
+ System.out.println("Positive Test9c - try to updateXXX on a readonly column. Should get error");
+ reloadData();
+ rs = stmt.executeQuery("SELECT c1, c2 FROM t1 abcde FOR UPDATE of c1");
rs.next();
- System.out.println("column 1 on this row is " + rs.getInt(1));
+ rs.updateString(2,"bbbb");
try {
- System.out.println("attempt to send updateXXX on correlation name column will fail");
- rs.updateShort(1, (new Integer(123)).shortValue());
- System.out.println("FAIL!!! updateXXX should have failed");
+ rs.updateRow();
+ System.out.println("FAIL!!! updateRow should have failed");
}
catch (SQLException e) {
System.out.println("SQL State : " + e.getSQLState());