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/03/15 22:54:40 UTC
svn commit: r157592 [1/6] - in incubator/derby/code/trunk/java:
engine/org/apache/derby/iapi/reference/ engine/org/apache/derby/iapi/types/
engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/loc/
testing/org/apache/derbyTesting/functionTests/master/
testing/org/apache/derbyTesting/functionTests/master/jdk14/
testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/
testing/org/apache/derbyTesting/functionTests/tests/lang/
Author: bandaram
Date: Tue Mar 15 13:54:36 2005
New Revision: 157592
URL: http://svn.apache.org/viewcvs?view=rev&rev=157592
Log:
Support update operation on updatable ResultSets.
Submitted by Mamta Satoor (msatoor@gmail.com)
Added:
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out (with props)
Modified:
incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/reference/SQLState.java
incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedDatabaseMetaData.java
incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet20.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/parameterMapping.out
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/resultsetJdbc30.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/jdbcapi/resultsetJdbc30.java
incubator/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/build.xml
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=157591&r2=157592
==============================================================================
--- 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 Tue Mar 15 13:54:36 2005
@@ -1234,6 +1234,7 @@
String LANG_OBSOLETE_PARAMETERS = "XCL10.S";
String LANG_DATA_TYPE_SET_MISMATCH = "XCL12.S";
String LANG_INVALID_PARAM_POSITION = "XCL13.S";
+ String LANG_INVALID_COLUMN_POSITION = "XCL14.S";
String LANG_INVALID_COMPARE_TO = "XCL15.S";
String LANG_RESULT_SET_NOT_OPEN = "XCL16.S";
String LANG_MISSING_ROW = "XCL19.S";
@@ -1380,6 +1381,7 @@
//updatable resultset related
String UPDATABLE_RESULTSET_API_DISALLOWED = "XJ083.U";
+ String COLUMN_NOT_FROM_BASE_TABLE = "XJ084.U";
//following are session severity.
String DATABASE_NOT_FOUND = "XJ004.C";
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java?view=diff&r1=157591&r2=157592
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/iapi/types/SQLClob.java Tue Mar 15 13:54:36 2005
@@ -242,7 +242,6 @@
public void setValue(byte theValue) throws StandardException
{
- new Throwable("FRED").printStackTrace(System.out);
throwLangSetMismatch("byte");
}
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedDatabaseMetaData.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedDatabaseMetaData.java?view=diff&r1=157591&r2=157592
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedDatabaseMetaData.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedDatabaseMetaData.java Tue Mar 15 13:54:36 2005
@@ -20,45 +20,31 @@
package org.apache.derby.impl.jdbc;
-import org.apache.derby.iapi.services.info.ProductGenusNames;
import org.apache.derby.iapi.services.info.ProductVersionHolder;
-import org.apache.derby.iapi.services.sanity.SanityManager;
import org.apache.derby.iapi.services.monitor.Monitor;
import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
import org.apache.derby.iapi.sql.dictionary.DataDictionary;
-import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
import org.apache.derby.iapi.sql.dictionary.SPSDescriptor;
-import org.apache.derby.iapi.sql.execute.ConstantAction;
-
-import org.apache.derby.iapi.store.access.TransactionController;
-
import org.apache.derby.iapi.error.StandardException;
-import org.apache.derby.impl.sql.catalog.DD_Version;
import org.apache.derby.impl.sql.execute.GenericConstantActionFactory;
import org.apache.derby.impl.sql.execute.GenericExecutionFactory;
-import org.apache.derby.catalog.UUID;
-
-import org.apache.derby.iapi.reference.SQLState;
import org.apache.derby.iapi.reference.DB2Limit;
import org.apache.derby.iapi.reference.JDBC20Translation;
import org.apache.derby.iapi.reference.JDBC30Translation;
import java.util.Properties;
-import java.util.Enumeration;
import java.sql.DatabaseMetaData;
import java.sql.Connection;
-import java.sql.Statement;
import java.sql.PreparedStatement;
import java.sql.SQLException;
import java.sql.ResultSet;
-import java.sql.ResultSetMetaData;
import java.sql.Types;
import java.io.IOException;
@@ -2618,7 +2604,7 @@
* @see Connection
*/
public boolean supportsResultSetConcurrency(int type, int concurrency) {
- //FORWARD_ONLY + CONCUR_UPDATABLE combination is supported (at this point, delete functionality only)
+ //FORWARD_ONLY + CONCUR_UPDATABLE combination is supported (at this point, delete and update functionality only)
if ((type == JDBC20Translation.TYPE_FORWARD_ONLY) &&
(concurrency == JDBC20Translation.CONCUR_UPDATABLE))
return true;
@@ -2658,7 +2644,7 @@
*/
//Since Derby materializes a forward only ResultSet incrementally, it is possible to see changes
//made by others and hence following 3 metadata calls will return true for forward only ResultSets.
- //Scroll insensitive ResultSet by their definition do not see chnages made by others.
+ //Scroll insensitive ResultSet by their definition do not see changes made by others.
//Derby does not yet implement scroll sensitive resultsets.
public boolean othersUpdatesAreVisible(int type) {
if (type == JDBC20Translation.TYPE_FORWARD_ONLY)
@@ -2687,6 +2673,8 @@
* @param result set type, i.e. ResultSet.TYPE_XXX
* @return true if changes are detected by the resultset type
*/
+ //updatable resultsets are supported for forward only resultset types only. And for forward only
+ //resultsets, we move to before the next row after a update and that is why updatesAreDetected returns false
public boolean updatesAreDetected(int type) {
return false;
}
@@ -2694,13 +2682,15 @@
/**
* JDBC 2.0
*
- * Determine whether or not a visible row delete can be detected by
+ * Determine whether or not a visible row delete can be detected by
* calling ResultSet.rowDeleted(). If deletesAreDetected()
* returns false, then deleted rows are removed from the result set.
*
* @param result set type, i.e. ResultSet.TYPE_XXX
* @return true if changes are detected by the resultset type
*/
+ //updatable resultsets are supported for forward only resultset types only. And for forward only
+ //resultsets, we move to before the next row after a delete and that is why deletesAreDetected returns false
public boolean deletesAreDetected(int type) {
return false;
}
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=157591&r2=157592
==============================================================================
--- 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 Tue Mar 15 13:54:36 2005
@@ -34,14 +34,20 @@
import org.apache.derby.iapi.sql.execute.ExecRow;
import org.apache.derby.iapi.sql.execute.NoPutResultSet;
+import org.apache.derby.iapi.sql.dictionary.TableDescriptor;
+import org.apache.derby.iapi.sql.dictionary.SchemaDescriptor;
+
import org.apache.derby.iapi.sql.Activation;
+import org.apache.derby.iapi.sql.execute.CursorActivation;
import org.apache.derby.iapi.types.DataValueDescriptor;
+import org.apache.derby.iapi.types.VariableSizeDataValue;
import org.apache.derby.iapi.sql.ResultDescription;
import org.apache.derby.iapi.services.io.StreamStorable;
import org.apache.derby.iapi.services.io.LimitInputStream;
import org.apache.derby.iapi.services.io.NewByteArrayInputStream;
+import org.apache.derby.iapi.services.io.LimitReader;
import org.apache.derby.iapi.error.ExceptionSeverity;
import org.apache.derby.iapi.reference.JDBC20Translation;
import org.apache.derby.iapi.reference.SQLState;
@@ -91,9 +97,8 @@
// mutable state
protected ExecRow currentRow;
- //rowData is protected so deleteRow in EmbedResultSet20.java can make it null.
- //This ensures that after deleteRow, ResultSet is not positioned on the deleted row.
- protected DataValueDescriptor[] rowData;
+ //deleteRow & updateRow make rowData null so that ResultSet is not positioned on deleted/updated row.
+ private DataValueDescriptor[] rowData;
protected boolean wasNull;
protected boolean isClosed;
private Object currentStream;
@@ -115,7 +120,7 @@
// Order of creation
final int order;
-
+
private final ResultDescription resultDescription;
// max rows limit for this result set
@@ -142,15 +147,23 @@
protected final int concurrencyOfThisResultSet;
+ //copyOfDatabaseRow will keep the original contents of the columns of the current row which got updated.
+ //These will be used if user decides to cancel the changes made to the row using cancelRowUpdates.
+ private DataValueDescriptor[] copyOfDatabaseRow;
+ private boolean[] columnGotUpdated; //these are the columns which have been updated so far. Used to build UPDATE...WHERE CURRENT OF sql
+ private boolean currentRowHasBeenUpdated; //Gets set to true after first updateXXX on a row. Gets reset to false when the cursor moves off the row
+
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
* resultset and the JDBC resultset, mapping calls-to-calls.
*/
public EmbedResultSet(EmbedConnection conn, ResultSet resultsToWrap,
- boolean forMetaData, EmbedStatement stmt, boolean isAtomic)
+ boolean forMetaData, EmbedStatement stmt, boolean isAtomic)
throws SQLException {
super(conn);
@@ -185,11 +198,15 @@
// Fill in the column types
resultDescription = theResults.getResultDescription();
+ //initialize arrays related to updateRow implementation
+ columnGotUpdated = new boolean[getMetaData().getColumnCount()];
+ copyOfDatabaseRow = new DataValueDescriptor[columnGotUpdated.length];
+
// assign the max rows and maxfiled size limit for this result set
if (stmt != null)
{
// At connectivity level we handle only for forward only cursor
- if (stmt.resultSetType == JDBC20Translation.TYPE_FORWARD_ONLY)
+ if (stmt.resultSetType == JDBC20Translation.TYPE_FORWARD_ONLY)
maxRows = stmt.maxRows;
maxFieldSize = stmt.MaxFieldSize;
@@ -276,6 +293,11 @@
}
}
+ //since we are moving off of the current row, need to initialize state corresponding to updateRow implementation
+ for (int i=0; i < columnGotUpdated.length; i++)
+ columnGotUpdated[i] = false;
+ currentRowHasBeenUpdated = false;
+
return movePosition(NEXT, 0, "next");
}
@@ -508,6 +530,10 @@
currentRow = null;
rowData = null;
rMetaData = null; // let it go, we can make a new one
+ //since we are moving off of the current row(by closing the resultset), need to initialize state corresponding to updateRow implementation
+ for (int i=0; i < columnGotUpdated.length; i++)
+ columnGotUpdated[i] = false;
+ currentRowHasBeenUpdated = false;
// we hang on to theResults and messenger
// in case more calls come in on this resultSet
@@ -1975,7 +2001,7 @@
* @see EmbedDatabaseMetaData#updatesAreDetected
*/
public boolean rowUpdated() throws SQLException {
- throw Util.notImplemented();
+ return false;
}
/**
@@ -1996,22 +2022,110 @@
/**
* JDBC 2.0
- *
+ *
* Determine if this row has been deleted. A deleted row may leave a visible
* "hole" in a result set. This method can be used to detect holes in a
* result set. The value returned depends on whether or not the result set
* can detect deletions.
- *
+ *
* @return true if deleted and deletes are detected
* @exception SQLException
* if a database-access error occurs
- *
+ *
* @see EmbedDatabaseMetaData#deletesAreDetected
*/
public boolean rowDeleted() throws SQLException {
return false;
}
+ //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
+ if (getConcurrency() != JDBC20Translation.CONCUR_UPDATABLE)//if not updatable resultset, then throw exception
+ throw Util.generateCsSQLException(SQLState.UPDATABLE_RESULTSET_API_DISALLOWED, methodName);
+
+ //2)Make sure JDBC ResultSet is not closed
+ checkIfClosed(methodName);
+
+ //3)Make sure JDBC ResultSet is positioned on a row
+ checkOnRow(); // first make sure there's a current row
+ //in case of autocommit on, if there was an exception which caused runtime rollback in this transaction prior to this call,
+ //the rollback code will mark the language resultset closed (it doesn't mark the JDBC ResultSet closed).
+ //That is why alongwith the earlier checkIfClosed call in this method, there is a check for language resultset close as well.
+
+ //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);
+ 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
+ copyOfDatabaseRow[columnIndex - 1] = currentRow.getColumn(columnIndex).getClone();
+ }
+ columnGotUpdated[columnIndex-1] = true;
+ currentRowHasBeenUpdated = true;
+ return currentRow.getColumn(columnIndex);
+ }
+
/**
* JDBC 2.0
*
@@ -2028,19 +2142,23 @@
* if a database-access error occurs
*/
public void updateNull(int columnIndex) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateNull").setToNull();
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a boolean value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2049,19 +2167,23 @@
* if a database-access error occurs
*/
public void updateBoolean(int columnIndex, boolean x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateBoolean").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a byte value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2070,19 +2192,23 @@
* if a database-access error occurs
*/
public void updateByte(int columnIndex, byte x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateByte").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a short value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2091,19 +2217,23 @@
* if a database-access error occurs
*/
public void updateShort(int columnIndex, short x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateShort").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with an integer value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2112,19 +2242,23 @@
* if a database-access error occurs
*/
public void updateInt(int columnIndex, int x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateInt").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a long value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2133,19 +2267,23 @@
* if a database-access error occurs
*/
public void updateLong(int columnIndex, long x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateLong").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a float value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2154,14 +2292,18 @@
* if a database-access error occurs
*/
public void updateFloat(int columnIndex, float x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateFloat").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a Double value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
@@ -2175,7 +2317,11 @@
* if a database-access error occurs
*/
public void updateDouble(int columnIndex, double x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateDouble").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
@@ -2196,7 +2342,11 @@
* if a database-access error occurs
*/
public void updateString(int columnIndex, String x) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateString").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
@@ -2217,19 +2367,23 @@
* if a database-access error occurs
*/
public void updateBytes(int columnIndex, byte x[]) throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateBytes").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a Date value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2239,19 +2393,23 @@
*/
public void updateDate(int columnIndex, java.sql.Date x)
throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateDate").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a Time value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2261,19 +2419,23 @@
*/
public void updateTime(int columnIndex, java.sql.Time x)
throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateTime").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a Timestamp value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2283,19 +2445,23 @@
*/
public void updateTimestamp(int columnIndex, java.sql.Timestamp x)
throws SQLException {
- throw Util.notImplemented();
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateTimestamp").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with an ascii stream value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2307,19 +2473,41 @@
*/
public void updateAsciiStream(int columnIndex, java.io.InputStream x,
int length) throws SQLException {
- throw Util.notImplemented();
+ checksBeforeUpdateOrDelete("updateAsciiStream", columnIndex);
+
+ int colType = getColumnType(columnIndex);
+ switch (colType) {
+ case Types.CHAR:
+ case Types.VARCHAR:
+ case Types.LONGVARCHAR:
+ case Types.CLOB:
+ break;
+ default:
+ throw dataTypeConversion(columnIndex, "java.io.InputStream");
+ }
+
+ java.io.Reader r = null;
+ if (x != null)
+ {
+ try {
+ r = new java.io.InputStreamReader(x, "ISO-8859-1");
+ } catch (java.io.UnsupportedEncodingException uee) {
+ throw new SQLException(uee.getMessage());
+ }
+ }
+ updateCharacterStream(columnIndex, r, length);
}
/**
* JDBC 2.0
- *
+ *
* Update a column with a binary stream value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2331,7 +2519,38 @@
*/
public void updateBinaryStream(int columnIndex, java.io.InputStream x,
int length) throws SQLException {
- throw Util.notImplemented();
+ checksBeforeUpdateOrDelete("updateBinaryStream", columnIndex);
+ int colType = getColumnType(columnIndex);
+ switch (colType) {
+ case Types.BINARY:
+ case Types.VARBINARY:
+ case Types.LONGVARBINARY:
+ case Types.BLOB:
+ break;
+ default:
+ throw dataTypeConversion(columnIndex, "java.io.InputStream");
+ }
+ if (length < 0) //we are doing the check here and not in updateBinaryStreamInternal becuase updateClob needs to pass -1 for length.
+ throw newSQLException(SQLState.NEGATIVE_STREAM_LENGTH);
+
+ if (x == null)
+ {
+ updateNull(columnIndex);
+ return;
+ }
+
+ updateBinaryStreamInternal(columnIndex, x, length,"updateBinaryStream");
+ }
+
+ protected void updateBinaryStreamInternal(int columnIndex,
+ java.io.InputStream x, int length, String updateMethodName)
+ throws SQLException
+ {
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, updateMethodName).setValue(new RawToBinaryFormatStream(x, length), length);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
@@ -2355,19 +2574,56 @@
*/
public void updateCharacterStream(int columnIndex, java.io.Reader x,
int length) throws SQLException {
- throw Util.notImplemented();
+ //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);
+ int colType = getColumnType(columnIndex);
+ switch (colType) {
+ case Types.CHAR:
+ case Types.VARCHAR:
+ case Types.LONGVARCHAR:
+ case Types.CLOB:
+ break;
+ default:
+ throw dataTypeConversion(columnIndex, "java.io.Reader");
+ }
+ if (length < 0) //we are doing the check here and not in updateCharacterStreamInternal becuase updateClob needs to pass -1 for length.
+ throw newSQLException(SQLState.NEGATIVE_STREAM_LENGTH);
+
+ if (x == null)
+ {
+ updateNull(columnIndex);
+ return;
+ }
+ updateCharacterStreamInternal(columnIndex, x, length, "updateCharacterStream");
+ }
+
+ protected void updateCharacterStreamInternal(int columnIndex,
+ java.io.Reader reader, int length, String updateMethodName)
+ throws SQLException
+ {
+ try {
+ LimitReader limitIn = new LimitReader(reader);
+ if (length != -1)
+ limitIn.setLimit(length);
+ ReaderToUTF8Stream utfIn = new ReaderToUTF8Stream(limitIn);
+ getDVDforColumnToBeUpdated(columnIndex, updateMethodName).setValue(utfIn, length);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with an Object value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2381,19 +2637,41 @@
*/
public void updateObject(int columnIndex, Object x, int scale)
throws SQLException {
- throw Util.notImplemented();
+ updateObject(columnIndex, x);
+ /*
+ * If the parameter type is DECIMAL or NUMERIC, then
+ * we need to set them to the passed scale.
+ */
+ int colType = getColumnType(columnIndex);
+ if ((colType == Types.DECIMAL) || (colType == Types.NUMERIC)) {
+ if (scale < 0)
+ throw newSQLException(SQLState.BAD_SCALE_VALUE, new Integer(scale));
+
+ try {
+ DataValueDescriptor value = currentRow.getColumn(columnIndex);
+
+ int origvaluelen = value.getLength();
+ ((VariableSizeDataValue)
+ value).setWidth(VariableSizeDataValue.IGNORE_PRECISION,
+ scale,
+ false);
+
+ } catch (StandardException t) {
+ throw EmbedResultSet.noStateChangeException(t);
+ }
+ }
}
/**
* JDBC 2.0
- *
+ *
* Update a column with an Object value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnIndex
* the first column is 1, the second is 2, ...
* @param x
@@ -2402,7 +2680,88 @@
* if a database-access error occurs
*/
public void updateObject(int columnIndex, Object x) throws SQLException {
- throw Util.notImplemented();
+ checksBeforeUpdateOrDelete("updateObject", columnIndex);
+ int colType = getColumnType(columnIndex);
+ if (colType == org.apache.derby.iapi.reference.JDBC20Translation.SQL_TYPES_JAVA_OBJECT) {
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateObject").setValue(x);
+ return;
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
+ }
+
+ if (x == null) {
+ updateNull(columnIndex);
+ return;
+ }
+
+ if (x instanceof String) {
+ updateString(columnIndex, (String) x);
+ return;
+ }
+
+ if (x instanceof Boolean) {
+ updateBoolean(columnIndex, ((Boolean) x).booleanValue());
+ return;
+ }
+
+ if (x instanceof Short) {
+ updateShort(columnIndex, ((Short) x).shortValue());
+ return;
+ }
+
+ if (x instanceof Integer) {
+ updateInt(columnIndex, ((Integer) x).intValue());
+ return;
+ }
+
+ if (x instanceof Long) {
+ updateLong(columnIndex, ((Long) x).longValue());
+ return;
+ }
+
+ if (x instanceof Float) {
+ updateFloat(columnIndex, ((Float) x).floatValue());
+ return;
+ }
+
+ if (x instanceof Double) {
+ updateDouble(columnIndex, ((Double) x).doubleValue());
+ return;
+ }
+
+ if (x instanceof byte[]) {
+ updateBytes(columnIndex, (byte[]) x);
+ return;
+ }
+
+ if (x instanceof Date) {
+ updateDate(columnIndex, (Date) x);
+ return;
+ }
+
+ if (x instanceof Time) {
+ updateTime(columnIndex, (Time) x);
+ return;
+ }
+
+ if (x instanceof Timestamp) {
+ updateTimestamp(columnIndex, (Timestamp) x);
+ return;
+ }
+
+ if (x instanceof Blob) {
+ updateBlob(columnIndex, (Blob) x);
+ return;
+ }
+
+ if (x instanceof Clob) {
+ updateClob(columnIndex, (Clob) x);
+ return;
+ }
+
+ throw dataTypeConversion(columnIndex, x.getClass().getName());
}
/**
@@ -2421,7 +2780,7 @@
* if a database-access error occurs
*/
public void updateNull(String columnName) throws SQLException {
- throw Util.notImplemented();
+ updateNull(findColumnName(columnName));
}
/**
@@ -2442,7 +2801,7 @@
* if a database-access error occurs
*/
public void updateBoolean(String columnName, boolean x) throws SQLException {
- throw Util.notImplemented();
+ updateBoolean(findColumnName(columnName), x);
}
/**
@@ -2463,7 +2822,7 @@
* if a database-access error occurs
*/
public void updateByte(String columnName, byte x) throws SQLException {
- throw Util.notImplemented();
+ updateByte(findColumnName(columnName), x);
}
/**
@@ -2484,7 +2843,7 @@
* if a database-access error occurs
*/
public void updateShort(String columnName, short x) throws SQLException {
- throw Util.notImplemented();
+ updateShort(findColumnName(columnName), x);
}
/**
@@ -2505,7 +2864,7 @@
* if a database-access error occurs
*/
public void updateInt(String columnName, int x) throws SQLException {
- throw Util.notImplemented();
+ updateInt(findColumnName(columnName), x);
}
/**
@@ -2526,7 +2885,7 @@
* if a database-access error occurs
*/
public void updateLong(String columnName, long x) throws SQLException {
- throw Util.notImplemented();
+ updateLong(findColumnName(columnName), x);
}
/**
@@ -2547,7 +2906,7 @@
* if a database-access error occurs
*/
public void updateFloat(String columnName, float x) throws SQLException {
- throw Util.notImplemented();
+ updateFloat(findColumnName(columnName), x);
}
/**
@@ -2568,7 +2927,7 @@
* if a database-access error occurs
*/
public void updateDouble(String columnName, double x) throws SQLException {
- throw Util.notImplemented();
+ updateDouble(findColumnName(columnName), x);
}
/**
@@ -2589,7 +2948,7 @@
* if a database-access error occurs
*/
public void updateString(String columnName, String x) throws SQLException {
- throw Util.notImplemented();
+ updateString(findColumnName(columnName), x);
}
/**
@@ -2610,7 +2969,7 @@
* if a database-access error occurs
*/
public void updateBytes(String columnName, byte x[]) throws SQLException {
- throw Util.notImplemented();
+ updateBytes(findColumnName(columnName), x);
}
/**
@@ -2632,7 +2991,7 @@
*/
public void updateDate(String columnName, java.sql.Date x)
throws SQLException {
- throw Util.notImplemented();
+ updateDate(findColumnName(columnName), x);
}
/**
@@ -2654,7 +3013,7 @@
*/
public void updateTime(String columnName, java.sql.Time x)
throws SQLException {
- throw Util.notImplemented();
+ updateTime(findColumnName(columnName), x);
}
/**
@@ -2676,7 +3035,7 @@
*/
public void updateTimestamp(String columnName, java.sql.Timestamp x)
throws SQLException {
- throw Util.notImplemented();
+ updateTimestamp(findColumnName(columnName), x);
}
/**
@@ -2700,7 +3059,7 @@
*/
public void updateAsciiStream(String columnName, java.io.InputStream x,
int length) throws SQLException {
- throw Util.notImplemented();
+ updateAsciiStream(findColumnName(columnName), x, length);
}
/**
@@ -2724,7 +3083,7 @@
*/
public void updateBinaryStream(String columnName, java.io.InputStream x,
int length) throws SQLException {
- throw Util.notImplemented();
+ updateBinaryStream(findColumnName(columnName), x, length);
}
/**
@@ -2748,45 +3107,41 @@
*/
public void updateCharacterStream(String columnName, java.io.Reader reader,
int length) throws SQLException {
- throw Util.notImplemented();
+ updateCharacterStream(findColumnName(columnName), reader, length);
}
/**
* JDBC 2.0
- *
+ *
* Update a column with an Object value.
- *
- * The updateXXX() methods are used to update column values in the current
- * row, or the insert row. The updateXXX() methods do not update the
- * underlying database, instead the updateRow() or insertRow() methods are
- * called to update the database.
- *
- * @param columnName
- * the name of the column
- * @param x
- * the new column value
- * @param scale
- * For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
- * this is the number of digits after the decimal. For all other
- * types this value will be ignored.
- * @exception SQLException
- * if a database-access error occurs
+ *
+ * The updateXXX() methods are used to update column values in the
+ * current row, or the insert row. The updateXXX() methods do not
+ * update the underlying database, instead the updateRow() or insertRow()
+ * methods are called to update the database.
+ *
+ * @param columnName the name of the column
+ * @param x the new column value
+ * @param scale For java.sql.Types.DECIMAL or java.sql.Types.NUMERIC types
+ * this is the number of digits after the decimal. For all other
+ * types this value will be ignored.
+ * @exception SQLException if a database-access error occurs
*/
public void updateObject(String columnName, Object x, int scale)
- throws SQLException {
- throw Util.notImplemented();
+ throws SQLException {
+ updateObject(findColumnName(columnName), x, scale);
}
/**
* JDBC 2.0
- *
+ *
* Update a column with an Object value.
- *
+ *
* The updateXXX() methods are used to update column values in the current
* row, or the insert row. The updateXXX() methods do not update the
* underlying database, instead the updateRow() or insertRow() methods are
* called to update the database.
- *
+ *
* @param columnName
* the name of the column
* @param x
@@ -2795,7 +3150,7 @@
* if a database-access error occurs
*/
public void updateObject(String columnName, Object x) throws SQLException {
- throw Util.notImplemented();
+ updateObject(findColumnName(columnName), x);
}
/**
@@ -2813,102 +3168,119 @@
throw Util.notImplemented();
}
- /**
- * JDBC 2.0
- *
- * Update the underlying database with the new contents of the current row.
- * Cannot be called when on the insert row.
- *
- * @exception SQLException
- * if a database-access error occurs, or if called when on
- * the insert row
- */
- public void updateRow() throws SQLException {
- throw Util.notImplemented();
- }
-
- /**
- * JDBC 2.0
- *
- * Delete the current row from the result set and the underlying database.
- * Cannot be called when on the insert row.
- *
- * @exception SQLException
- * if a database-access error occurs, or if called when on
- * the insert row.
- */
- public void deleteRow() throws SQLException {
- synchronized (getConnectionSynchronization()) {
- checkIfClosed("deleteRow");
- checkOnRow(); // first make sure there's a current row
-
- if (getConcurrency() != JDBC20Translation.CONCUR_UPDATABLE)//if not
- // updatable
- // resultset,
- // can't
- // issue
- // deleteRow
- throw Util.generateCsSQLException(
- SQLState.UPDATABLE_RESULTSET_API_DISALLOWED,
- "deleteRow");
-
- setupContextStack();
- try {
- //in case of autocommit on, if there was an exception which
- // caused runtime rollback in this transaction prior to this
- // deleteRow,
- //the rollback code will mark the language resultset closed (it
- // doesn't mark the JDBC ResultSet closed).
- //That is why alongwith the earlier checkIfClosed call in this
- // method, there is a check for language resultset close as
- // well.
- if (theResults.isClosed())
- throw Util.generateCsSQLException(
- SQLState.LANG_RESULT_SET_NOT_OPEN, "deleteRow");
- StringBuffer deleteWhereCurrentOfSQL = new StringBuffer(
- "DELETE FROM ");
- Activation activation = getEmbedConnection()
- .getLanguageConnection().lookupCursorActivation(
- getCursorName());
- deleteWhereCurrentOfSQL.append(getFullBaseTableName(activation
- .getPreparedStatement().getTargetTable()));//get the
- // underlying
- // (schema.)table
- // name
- //using quotes around the cursor name to preserve case
- // sensitivity
- deleteWhereCurrentOfSQL.append(" WHERE CURRENT OF \""
- + getCursorName() + "\"");
-
- LanguageConnectionContext lcc = getEmbedConnection()
- .getLanguageConnection();
- StatementContext statementContext = lcc.pushStatementContext(
- isAtomic, deleteWhereCurrentOfSQL.toString(), null,
- false);
- org.apache.derby.iapi.sql.PreparedStatement ps = lcc
- .prepareInternalStatement(deleteWhereCurrentOfSQL
- .toString());
- org.apache.derby.iapi.sql.ResultSet rs = ps.execute(lcc, true);
- rs.close();
- rs.finish();
- //For forward only resultsets, after a delete, the ResultSet
- // will be positioned right before the next row.
- rowData = null;
- lcc.popStatementContext(statementContext, null);
- } catch (StandardException t) {
- throw closeOnTransactionError(t);
- } finally {
- restoreContextStack();
+ /**
+ * JDBC 2.0
+ *
+ * Update the underlying database with the new contents of the
+ * current row. Cannot be called when on the insert row.
+ *
+ * @exception SQLException if a database-access error occurs, or
+ * if called when on the insert row
+ */
+ public void updateRow() throws SQLException {
+ synchronized (getConnectionSynchronization()) {
+ checksBeforeUpdateOrDelete("updateRow", -1);
+ setupContextStack();
+ LanguageConnectionContext lcc = null;
+ StatementContext statementContext = null;
+ try {
+ if (currentRowHasBeenUpdated == false) //nothing got updated on this row
+ return; //nothing to do since no updates were made to this row
+
+ //now construct the update where current of sql
+ boolean foundOneColumnAlready = false;
+ StringBuffer updateWhereCurrentOfSQL = new StringBuffer("UPDATE ");
+ CursorActivation activation = getEmbedConnection().getLanguageConnection().lookupCursorActivation(getCursorName());
+ ExecCursorTableReference targetTable = activation.getPreparedStatement().getTargetTable();
+ updateWhereCurrentOfSQL.append(getFullBaseTableName(targetTable));//got the underlying (schema.)table name
+ updateWhereCurrentOfSQL.append(" SET ");
+ ResultDescription rd = theResults.getResultDescription();
+
+ for (int i=1; i<=rd.getColumnCount(); i++) { //in this for loop we are constructing columnname=?,... part of the update sql
+ if (columnGotUpdated[i-1]) { //if the column got updated, do following
+ if (foundOneColumnAlready)
+ updateWhereCurrentOfSQL.append(",");
+ //using quotes around the column name to preserve case sensitivity
+ updateWhereCurrentOfSQL.append("\"" + rd.getColumnDescriptor(i).getName() + "\"=?");
+ foundOneColumnAlready = true;
+ }
+ }
+ //using quotes around the cursor name to preserve case sensitivity
+ updateWhereCurrentOfSQL.append(" WHERE CURRENT OF \"" + getCursorName() + "\"");
+ lcc = getEmbedConnection().getLanguageConnection();
+ statementContext = lcc.pushStatementContext(isAtomic, updateWhereCurrentOfSQL.toString(), null, false);
+ org.apache.derby.iapi.sql.PreparedStatement ps = lcc.prepareInternalStatement(updateWhereCurrentOfSQL.toString());
+ Activation act = ps.getActivation(lcc, false);
+
+ //in this for loop we are assigning values for parameters in sql constructed earlier with columnname=?,...
+ for (int i=1, paramPosition=0; i<=rd.getColumnCount(); i++) {
+ if (columnGotUpdated[i-1]) //if the column got updated, do following
+ act.getParameterValueSet().getParameterForSet(paramPosition++).setValue(currentRow.getColumn(i));
+ }
+ org.apache.derby.iapi.sql.ResultSet rs = ps.execute(act, false, true, true); //execute the update where current of sql
+ rs.close();
+ rs.finish();
+ //For forward only resultsets, after a update, the ResultSet will be positioned right before the next row.
+ rowData = null;
+ currentRow = null;
+ lcc.popStatementContext(statementContext, null);
+ } catch (StandardException t) {
+ throw closeOnTransactionError(t);
+ } finally {
+ if (statementContext != null)
+ lcc.popStatementContext(statementContext, null);
+ restoreContextStack();
+ }
}
- }
- }
+ }
+
+ /**
+ * JDBC 2.0
+ *
+ * Delete the current row from the result set and the underlying
+ * database. Cannot be called when on the insert row.
+ *
+ * @exception SQLException if a database-access error occurs, or if
+ * called when on the insert row.
+ */
+ public void deleteRow() throws SQLException {
+ synchronized (getConnectionSynchronization()) {
+ checksBeforeUpdateOrDelete("deleteRow", -1);
+
+ setupContextStack();
+ //now construct the delete where current of sql
+ try {
+ StringBuffer deleteWhereCurrentOfSQL = new StringBuffer("DELETE FROM ");
+ CursorActivation activation = getEmbedConnection().getLanguageConnection().lookupCursorActivation(getCursorName());
+ deleteWhereCurrentOfSQL.append(getFullBaseTableName(activation.getPreparedStatement().getTargetTable()));//get the underlying (schema.)table name
+ //using quotes around the cursor name to preserve case sensitivity
+ deleteWhereCurrentOfSQL.append(" WHERE CURRENT OF \"" + getCursorName() + "\"");
+
+ LanguageConnectionContext lcc = getEmbedConnection().getLanguageConnection();
+ StatementContext statementContext = lcc.pushStatementContext(isAtomic, deleteWhereCurrentOfSQL.toString(), null, false);
+ org.apache.derby.iapi.sql.PreparedStatement ps = lcc.prepareInternalStatement(deleteWhereCurrentOfSQL.toString());
+ org.apache.derby.iapi.sql.ResultSet rs = ps.execute(lcc, true); //execute delete where current of sql
+ rs.close();
+ rs.finish();
+ //For forward only resultsets, after a delete, the ResultSet will be positioned right before the next row.
+ rowData = null;
+ currentRow = null;
+ lcc.popStatementContext(statementContext, null);
+ } catch (StandardException t) {
+ throw closeOnTransactionError(t);
+ } finally {
+ restoreContextStack();
+ }
+ }
+ }
private String getFullBaseTableName(ExecCursorTableReference targetTable) {
+ //using quotes to preserve case sensitivity
if (targetTable.getSchemaName() != null)
- return targetTable.getSchemaName() + "."
- + targetTable.getBaseName();
+ return "\"" + targetTable.getSchemaName() + "\".\""
+ + targetTable.getBaseName() + "\"";
else
- return targetTable.getBaseName();
+ return "\"" + targetTable.getBaseName() + "\"";
}
/**
@@ -2937,22 +3309,31 @@
throw Util.notImplemented();
}
- /**
- * JDBC 2.0
- *
- * The cancelRowUpdates() method may be called after calling an updateXXX()
- * method(s) and before calling updateRow() to rollback the updates made to
- * a row. If no updates have been made or updateRow() has already been
- * called, then this method has no effect.
- *
- * @exception SQLException
- * if a database-access error occurs, or if called when on
- * the insert row.
- *
- */
- public void cancelRowUpdates() throws SQLException {
- throw Util.notImplemented();
- }
+ /**
+ * JDBC 2.0
+ *
+ * The cancelRowUpdates() method may be called after calling an
+ * updateXXX() method(s) and before calling updateRow() to rollback
+ * the updates made to a row. If no updates have been made or
+ * updateRow() has already been called, then this method has no
+ * effect.
+ *
+ * @exception SQLException if a database-access error occurs, or if
+ * called when on the insert row.
+ *
+ */
+ public void cancelRowUpdates () throws SQLException {
+ checksBeforeUpdateOrDelete("cancelRowUpdates", -1);
+ if (currentRowHasBeenUpdated == false) return; //nothing got updated on this row so cancelRowUpdates is a no-op in this case.
+
+ for (int i=0; i < columnGotUpdated.length; i++){
+ if (columnGotUpdated[i] == true) currentRow.setColumn(i+1, copyOfDatabaseRow[i]);//if column got updated, resotre the original data
+ columnGotUpdated[i] = false;
+ }
+ currentRowHasBeenUpdated = false;
+ //rowData needs to be refreshed with the currentRow otherwise it will continue to have changes made by updateXXX methods
+ rowData = currentRow.getRowArray();
+ }
/**
* JDBC 2.0
@@ -3141,7 +3522,15 @@
* Feature not implemented for now.
*/
public void updateBlob(int columnIndex, Blob x) throws SQLException {
- throw Util.notImplemented();
+ checksBeforeUpdateOrDelete("updateBlob", columnIndex);
+ int colType = getColumnType(columnIndex);
+ if (colType != Types.BLOB)
+ throw dataTypeConversion(columnIndex, "java.sql.Blob");
+
+ if (x == null)
+ updateNull(columnIndex);
+ else
+ updateBinaryStreamInternal(columnIndex, x.getBinaryStream(), -1, "updateBlob");
}
/**
@@ -3160,7 +3549,7 @@
* Feature not implemented for now.
*/
public void updateBlob(String columnName, Blob x) throws SQLException {
- throw Util.notImplemented();
+ updateBlob(findColumnName(columnName), x);
}
/**
@@ -3179,7 +3568,15 @@
* Feature not implemented for now.
*/
public void updateClob(int columnIndex, Clob x) throws SQLException {
- throw Util.notImplemented();
+ checksBeforeUpdateOrDelete("updateClob", columnIndex);
+ int colType = getColumnType(columnIndex);
+ if (colType != Types.CLOB)
+ throw dataTypeConversion(columnIndex, "java.sql.Clob");
+
+ if (x == null)
+ updateNull(columnIndex);
+ else
+ updateCharacterStreamInternal(columnIndex, x.getCharacterStream(), -1, "updateClob");
}
/**
@@ -3198,7 +3595,7 @@
* Feature not implemented for now.
*/
public void updateClob(String columnName, Clob x) throws SQLException {
- throw Util.notImplemented();
+ updateClob(findColumnName(columnName), x);
}
@@ -3504,6 +3901,11 @@
protected final SQLException dataTypeConversion(String targetType, int column) {
return newSQLException(SQLState.LANG_DATA_TYPE_GET_MISMATCH, targetType,
resultDescription.getColumnDescriptor(column).getType().getTypeId().getSQLTypeName());
+ }
+
+ protected final SQLException dataTypeConversion(int column, String targetType) {
+ return newSQLException(SQLState.LANG_DATA_TYPE_GET_MISMATCH,
+ resultDescription.getColumnDescriptor(column).getType().getTypeId().getSQLTypeName(), targetType);
}
}
Modified: incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet20.java
URL: http://svn.apache.org/viewcvs/incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet20.java?view=diff&r1=157591&r2=157592
==============================================================================
--- incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet20.java (original)
+++ incubator/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet20.java Tue Mar 15 13:54:36 2005
@@ -23,7 +23,6 @@
import org.apache.derby.iapi.reference.JDBC20Translation;
import org.apache.derby.iapi.reference.SQLState;
-import org.apache.derby.iapi.sql.Activation;
import org.apache.derby.iapi.sql.ResultSet;
import org.apache.derby.iapi.sql.execute.ExecCursorTableReference;
@@ -32,7 +31,7 @@
import org.apache.derby.impl.jdbc.Util;
import org.apache.derby.iapi.sql.conn.LanguageConnectionContext;
import org.apache.derby.iapi.sql.conn.StatementContext;
-
+
import org.apache.derby.iapi.types.DataValueDescriptor;
import java.sql.Statement;
@@ -71,7 +70,7 @@
//////////////////////////////////////////////////////////////
/**
- * This class provides the glue between the Cloudscape
+ * This class provides the glue between the Derby
* resultset and the JDBC resultset, mapping calls-to-calls.
*/
public EmbedResultSet20(org.apache.derby.impl.jdbc.EmbedConnection conn,
@@ -165,32 +164,49 @@
return getBigDecimal(findColumnName(columnName));
}
-
-
-
- /**
- * JDBC 2.0
- *
- * Update a column with a BigDecimal value.
- *
- * The updateXXX() methods are used to update column values in the
- * current row, or the insert row. The updateXXX() methods do not
- * update the underlying database, instead the updateRow() or insertRow()
- * methods are called to update the database.
- *
- * @param columnIndex the first column is 1, the second is 2, ...
- * @param x the new column value
- * @exception SQLException if a database-access error occurs
- */
public void updateBigDecimal(int columnIndex, BigDecimal x)
throws SQLException {
- throw Util.notImplemented();
- }
-
+ try {
+ getDVDforColumnToBeUpdated(columnIndex, "updateBigDecimal").setValue(x);
+ } catch (StandardException t) {
+ throw noStateChangeException(t);
+ }
+ }
+
+ /**
+ * JDBC 2.0
+ *
+ * Update a column with an Object value.
+ *
+ * The updateXXX() methods are used to update column values in the current
+ * row, or the insert row. The updateXXX() methods do not update the
+ * underlying database, instead the updateRow() or insertRow() methods are
+ * called to update the database.
+ *
+ * @param columnIndex
+ * the first column is 1, the second is 2, ...
+ * @param x
+ * the new column value
+ * @exception SQLException
+ * if a database-access error occurs
+ */
+ public void updateObject(int columnIndex, Object x) throws SQLException {
+ //If the Object x is the right datatype, this method will eventually call getDVDforColumnToBeUpdated which will check for
+ //the read only resultset. But for other datatypes of x, we want to catch if this updateObject is being
+ //issued against a read only resultset. And that is the reason for call to checksBeforeUpdateOrDelete here.
+ checksBeforeUpdateOrDelete("updateObject", columnIndex);
+ int colType = getColumnType(columnIndex);
+
+ if (x instanceof BigDecimal) {
+ updateBigDecimal(columnIndex, (BigDecimal) x);
+ return;
+ }
+ super.updateObject(columnIndex, x);
+ }
/**
* JDBC 2.0
- *
+ *
* Update a column with a BigDecimal value.
*
* The updateXXX() methods are used to update column values in the
@@ -204,15 +220,13 @@
*/
public void updateBigDecimal(String columnName, BigDecimal x)
throws SQLException {
- throw Util.notImplemented();
+ updateBigDecimal(findColumnName(columnName), x);
}
-
-
/**
* JDBC 2.0
*
- * Returns the value of column @i as a Java object. Use the
+ * Returns the value of column @i as a Java object. Use the
* param map to determine the class from which to construct data of
* SQL structured and distinct types.
*
@@ -355,7 +369,6 @@
{
throw Util.notImplemented();
}
-
/**
* JDBC 3.0
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=157591&r2=157592
==============================================================================
--- 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 Tue Mar 15 13:54:36 2005
@@ -967,6 +967,7 @@
XCL10.S=A PreparedStatement has been recompiled, and the parameters have changed. If you are using JDBC, you must re-prepare the statement.
XCL12.S=An attempt was made to put a data value of type ''{0}'' into a data value of type ''{1}''.
XCL13.S=The parameter position ''{0}'' is out of range. The number of parameters for this prepared statement is ''{1}''.
+XCL14.S=The column position ''{0}'' is out of range. The number of columns for this ResultSet is ''{1}''.
XCL15.S=A ClassCastException occurred when calling the compareTo() method on an object ''{0}''. The parameter to compareTo() is of class ''{1}''.
XCL16.S=ResultSet not open, operation ''{0}'' not permitted. Verify that autocommit is OFF.
XCL17.S=Statement not allowed in this database.
@@ -1081,6 +1082,7 @@
XJ077.S=Got an exception when trying to read the first byte/character of the Blob/Clob pattern using getBytes/getSubString.
XJ082.U=BLOB/CLOB values are not allowed as method parameters or receiver.
XJ083.U=''{0}'' not allowed because the ResultSet is not an updatable ResultSet.
+XJ084.U=Column does not correspond to a column in the base table. Can't issue {0} on this column.
0A000.S=Feature not implemented: {0}.