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 be...@apache.org on 2006/02/07 17:09:18 UTC

svn commit: r375635 [1/6] - in /db/derby/code/trunk/java: client/org/apache/derby/client/am/ engine/org/apache/derby/impl/jdbc/ engine/org/apache/derby/loc/ shared/org/apache/derby/shared/common/reference/ testing/org/apache/derbyTesting/functionTests/...

Author: bernt
Date: Tue Feb  7 08:09:10 2006
New Revision: 375635

URL: http://svn.apache.org/viewcvs?rev=375635&view=rev
Log:
DERBY-100 Add support for insert functionality using BC 2.0 updatable resultset apis. Submitted by Fernanda Pizzorno

Modified:
    db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
    db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_pt_BR.properties
    db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/jdk14/updatableResultSet.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/DerbyNetClient/updatableResultSet.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/jdk14/updatableResultSet.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/master/updatableResultSet.out
    db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/lang/updatableResultSet.java

Modified: db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java?rev=375635&r1=375634&r2=375635&view=diff
==============================================================================
--- db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java (original)
+++ db/derby/code/trunk/java/client/org/apache/derby/client/am/ResultSet.java Tue Feb  7 08:09:10 2006
@@ -178,6 +178,7 @@
 
     public PreparedStatement preparedStatementForUpdate_;
     public PreparedStatement preparedStatementForDelete_;
+    public PreparedStatement preparedStatementForInsert_;
 
     // Nesting level of the result set in a stored procedure
     public int nestingLevel_ = -1;
@@ -274,6 +275,11 @@
         checkForClosedResultSet();
         clearWarningsX();
 
+        if (isOnInsertRow_) {
+            isOnInsertRow_ = false;
+            isOnCurrentRow_ = true;
+        }
+        
         wasNull_ = ResultSet.WAS_NULL_UNSET;
 
         // discard all previous updates when moving the cursor
@@ -541,15 +547,17 @@
             }
             checkGetterPreconditions(column);
             boolean result = false;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = agent_.crossConverters_.setBooleanFromObject(updatedColumns_[column - 1],
-                        resultSetMetaData_.types_[column - 1]);
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if (isOnInsertRow_ && updatedColumns_[column - 1] == null) {
+                    result = false;
+                } else {
+                    result = agent_.crossConverters_.setBooleanFromObject(
+                            updatedColumns_[column - 1],
+                            resultSetMetaData_.types_[column - 1]);
+                }
             } else {
                 result = isNull(column) ? false : cursor_.getBoolean(column);
             }
-            if (agent_.loggingEnabled()) {
-                agent_.logWriter_.traceExit(this, "getBoolean", result);
-            }
             setWasNull(column);  // Placed close to the return to minimize risk of thread interference
             return result;
         }
@@ -570,9 +578,14 @@
             }
             checkGetterPreconditions(column);
             byte result = 0;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = agent_.crossConverters_.setByteFromObject(updatedColumns_[column - 1],
-                        resultSetMetaData_.types_[column - 1]);
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if ((isOnInsertRow_) && (updatedColumns_[column - 1] == null)) {
+                    result = 0;
+                } else {
+                    result = agent_.crossConverters_.setByteFromObject(
+                            updatedColumns_[column - 1],
+                            resultSetMetaData_.types_[column - 1]);
+                }
             } else {
                 result = isNull(column) ? 0 : cursor_.getByte(column);
             }
@@ -599,9 +612,14 @@
             }
             checkGetterPreconditions(column);
             short result = 0;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = ((Short) agent_.crossConverters_.setObject(java.sql.Types.SMALLINT,
-                        updatedColumns_[column - 1])).shortValue();
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if (isOnInsertRow_ && updatedColumns_[column - 1] == null) {
+                    result = 0;
+                } else {
+                    result = ((Short) agent_.crossConverters_.setObject(
+                            java.sql.Types.SMALLINT,
+                            updatedColumns_[column - 1])).shortValue();
+                }
             } else {
                 result = isNull(column) ? 0 : cursor_.getShort(column);
             }
@@ -628,9 +646,14 @@
             }
             checkGetterPreconditions(column);
             int result = 0;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = ((Integer) agent_.crossConverters_.setObject(java.sql.Types.INTEGER,
-                        updatedColumns_[column - 1])).intValue();
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if (isOnInsertRow_ && updatedColumns_[column - 1] == null) {
+                    result = 0;
+                } else {
+                    result = ((Integer) agent_.crossConverters_.setObject(
+                            java.sql.Types.INTEGER,
+                            updatedColumns_[column - 1])).intValue();
+                }
             } else {
                 result = isNull(column) ? 0 : cursor_.getInt(column);
             }
@@ -657,9 +680,14 @@
             }
             checkGetterPreconditions(column);
             long result = 0;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = ((Long) agent_.crossConverters_.setObject(java.sql.Types.BIGINT,
-                        updatedColumns_[column - 1])).longValue();
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if (isOnInsertRow_ && updatedColumns_[column - 1] == null) {
+                    result = 0;
+                } else {
+                    result = ((Long) agent_.crossConverters_.setObject(
+                            java.sql.Types.BIGINT,
+                            updatedColumns_[column - 1])).longValue();
+                }
             } else {
                 result = isNull(column) ? 0 : cursor_.getLong(column);
             }
@@ -686,9 +714,14 @@
             }
             checkGetterPreconditions(column);
             float result = 0;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = ((Float) agent_.crossConverters_.setObject(java.sql.Types.REAL,
-                        updatedColumns_[column - 1])).floatValue();
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if ((isOnInsertRow_ && updatedColumns_[column - 1] == null)) {
+                    result = 0;
+                } else {
+                    result = ((Float) agent_.crossConverters_.setObject(
+                            java.sql.Types.REAL,
+                            updatedColumns_[column - 1])).floatValue();
+                }
             } else {
                 result = isNull(column) ? 0 : cursor_.getFloat(column);
             }
@@ -715,9 +748,14 @@
             }
             checkGetterPreconditions(column);
             double result = 0;
-            if (wasNonNullSensitiveUpdate(column)) {
-                result = ((Double) agent_.crossConverters_.setObject(java.sql.Types.DOUBLE,
-                        updatedColumns_[column - 1])).doubleValue();
+            if (wasNonNullSensitiveUpdate(column) || isOnInsertRow_) {
+                if (isOnInsertRow_ && updatedColumns_[column - 1] == null) {
+                    result = 0;
+                } else {
+                    result = ((Double) agent_.crossConverters_.setObject(
+                            java.sql.Types.DOUBLE,
+                            updatedColumns_[column - 1])).doubleValue();
+                }
             } else {
                 result = isNull(column) ? 0 : cursor_.getDouble(column);
             }
@@ -1378,7 +1416,7 @@
     }
 
     private void setWasNull(int column) {
-        if (wasNullSensitiveUpdate(column)) {
+        if (wasNullSensitiveUpdate(column) || (isOnInsertRow_ && updatedColumns_[column - 1] == null)) {
             wasNull_ = WAS_NULL;
         } else {
             wasNull_ = (cursor_.isNull_ == null || cursor_.isNull_[column - 1]) ? WAS_NULL : WAS_NOT_NULL;
@@ -2643,14 +2681,8 @@
     public boolean rowInserted() throws SQLException {
         try
         {
-            if (agent_.loggingEnabled()) {
-                agent_.logWriter_.traceEntry(this, "rowInserted");
-            }
-            checkForClosedResultSet();
-            if (true) {
-                throw new SqlException(agent_.logWriter_, "under construction");
-            }
             boolean rowInserted = false;
+            checkForClosedResultSet();
             if (agent_.loggingEnabled()) {
                 agent_.logWriter_.traceExit(this, "rowInserted", rowInserted);
             }
@@ -3297,8 +3329,7 @@
                 if (agent_.loggingEnabled()) {
                     agent_.logWriter_.traceEntry(this, "insertRow");
                 }
-                checkForClosedResultSet();
-                throw new SqlException(agent_.logWriter_, "Driver not capable: insertRow");
+                insertRowX();
             }
         }
         catch ( SqlException se )
@@ -3307,6 +3338,53 @@
         }
     }
 
+    private void insertRowX() throws SqlException {
+        checkForClosedResultSet();
+        if (isOnCurrentRow_ || resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
+            throw new SqlException(agent_.logWriter_, "This method cannot be invoked while the cursor is not on the insert " +
+                    "row or if the concurrency of this ResultSet object is CONCUR_READ_ONLY.");
+       }
+ 
+        // if not on a valid row, then do not accept updateXXX calls
+        if (!isValidCursorPosition_) {
+            throw new SqlException(agent_.logWriter_, "Invalid operation to " +
+                    "insert at current cursor position");
+        }
+
+        // User might not be updating all the updatable columns selected in the
+        // select sql and hence every insertRow on the same ResultSet can be
+        // potentially different than the previous one. Because of that, we
+        // should get a new prepared statement to do inserts every time
+        getPreparedStatementForInsert();
+
+        // build the inputs array for the prepared statement for insert
+        int paramNumber = 0;
+        for (int i = 0; i < updatedColumns_.length; i++) {
+            if (resultSetMetaData_.sqlxUpdatable_[i] == 1) {
+                // Since user may choose not to update all the columns in the
+                // select list, check first if the column has been updated
+                if (columnUpdated_[i] == true) {
+                    paramNumber++;
+
+                    // column is updated either if the updatedColumns_ entry is not null,
+                    // or if the updatedColumns_ entry is null, but columnUpdated is
+                    // set to true, which means columns is updated to a null.
+                    if (updatedColumns_[i] != null ||
+                            (updatedColumns_[i] == null && columnUpdated_[i])) {
+                        preparedStatementForInsert_.setInput(
+                                paramNumber, 
+                                updatedColumns_[i]);
+                    }
+                }
+            }
+        }
+        try {
+            insert();
+        } catch (SqlException e) {
+            throw e;
+        }
+    }
+    
     public void updateRow() throws java.sql.SQLException {
         try
         {
@@ -3550,7 +3628,13 @@
                     agent_.logWriter_.traceEntry(this, "moveToInsertRow");
                 }
                 checkForClosedResultSet();
-                throw new SqlException(agent_.logWriter_, "Driver not capable");
+                checkUpdatableCursor();
+
+                resetUpdatedColumnsForInsert();
+
+                isOnInsertRow_ = true;
+                isOnCurrentRow_ = false;
+                isValidCursorPosition_ = true;
             }
         }
         catch ( SqlException se )
@@ -3567,15 +3651,18 @@
                     agent_.logWriter_.traceEntry(this, "moveToCurrentRow");
                 }
                 checkForClosedResultSet();
-                if (resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
-                    throw new SqlException(agent_.logWriter_, "This method should only be called on ResultSet objects that are " +
-                            "updatable(concurrency type CONCUR_UPDATABLE).");
-                }
+                checkUpdatableCursor();
 
                 if (!isOnInsertRow_) {
                     // no affect
                 } else {
-                    throw new SqlException(agent_.logWriter_, "Driver no capable");
+                    resetUpdatedColumns();
+                    isOnInsertRow_ = false;
+                    isOnCurrentRow_ = true;
+                    if (currentRowInRowset_ > 0) {
+                        updateColumnInfoFromCache();
+                    }
+                    isValidCursorPosition_ = true;
                 }
             }
         }
@@ -3724,6 +3811,35 @@
         agent_.endReadChain();
     }
 
+    protected void insert() throws SqlException {
+        agent_.beginWriteChain(statement_);
+
+        // re-prepare the insert statement if repreparing is needed after a commit.
+        if (!preparedStatementForInsert_.openOnServer_) {
+            preparedStatementForInsert_.materialPreparedStatement_.writePrepare_(
+                    preparedStatementForInsert_.sql_,
+                    preparedStatementForInsert_.section_);
+        }
+
+        try {
+            writeInsertRow(false);
+        } catch (SQLException se ) {
+            throw new SqlException(se);
+        }
+
+        agent_.flow(statement_);
+
+        // read prepare replies if the update statement is re-prepared after a commit.
+        if (!preparedStatementForInsert_.openOnServer_) {
+            preparedStatementForInsert_.materialPreparedStatement_.readPrepare_();
+        }
+
+        readInsertRow();
+
+        agent_.endReadChain();
+     }    
+
+    
     protected void update() throws SqlException {
         agent_.beginWriteChain(statement_);
 
@@ -3915,6 +4031,24 @@
         agent_.endReadChain();
     }
 
+    public void writeInsertRow(boolean chainedWritesFollowingSetLob) throws SQLException {
+        try
+        {
+            preparedStatementForInsert_.materialPreparedStatement_.writeExecute_(
+                    preparedStatementForInsert_.section_,
+                    preparedStatementForInsert_.parameterMetaData_,
+                    preparedStatementForInsert_.parameters_,
+                    (preparedStatementForInsert_.parameterMetaData_ == null ? 0 : 
+                        preparedStatementForInsert_.parameterMetaData_.getColumnCount()),
+                    false, // false means we're not expecting output
+                    chainedWritesFollowingSetLob);  // chaining after the execute        
+        }
+        catch ( SqlException se )
+        {
+            throw se.getSQLException();
+        }
+    }
+    
     public void writeUpdateRow(boolean chainedWritesFollowingSetLob) throws SQLException {
         try
         {
@@ -3956,6 +4090,10 @@
         }
     }
 
+    public void readInsertRow() throws DisconnectException, SqlException {
+        preparedStatementForInsert_.materialPreparedStatement_.readExecute_();
+    }
+
     public void readUpdateRow() throws DisconnectException, SqlException {
         preparedStatementForUpdate_.materialPreparedStatement_.readExecute_();
     }
@@ -4128,7 +4266,51 @@
         updatedColumns_[column - 1] = value;
         columnUpdated_[column - 1] = true;
     }
+    
+    /*
+     * Builds the insert statement that will be used well calling insertRow
+     * 
+     * If no values have been supplied for a column, it will be set 
+     * to the column's default value, if any. 
+     * If no default value had been defined, the default value of a 
+     * nullable column is set to NULL.
+     */
+    private String buildInsertString() throws SqlException {
+        int column;
+        boolean foundOneUpdatedColumnAlready = false;
+        
+        StringBuffer insertSQL = new StringBuffer("INSERT INTO ");
+        StringBuffer valuesSQL = new StringBuffer("VALUES (");
 
+        insertSQL.append(getTableName());
+        insertSQL.append(" (");
+        
+        for (column = 1; column <= resultSetMetaData_.columns_; column++) {
+            if (foundOneUpdatedColumnAlready) {
+                insertSQL.append(",");
+                valuesSQL.append(",");
+            }
+            //using quotes around the column name to preserve case sensitivity
+            try {
+                insertSQL.append("\"" + resultSetMetaData_.getColumnName(column) + "\"");
+            } catch ( SQLException sqle ) {
+                throw new SqlException(sqle);
+            }
+            if (columnUpdated_[column - 1]) { 
+                valuesSQL.append("?");
+            } else {
+                valuesSQL.append("DEFAULT");
+            }
+            foundOneUpdatedColumnAlready = true;
+        }
+        
+        insertSQL.append(") ");
+        valuesSQL.append(") ");
+        insertSQL.append(valuesSQL.toString());
+        
+        return(insertSQL.toString());
+    }
+    
     private String buildUpdateString() throws SqlException {
         int column;
         int numColumns = 0;
@@ -4219,6 +4401,18 @@
         return statement_.section_.getServerCursorName();
     }
 
+    private void getPreparedStatementForInsert() throws SqlException {
+        // each column is associated with a tableName in the extended describe info.
+        String insertString = buildInsertString();
+
+        try {
+            preparedStatementForInsert_ = (PreparedStatement)statement_.connection_.
+                    prepareStatement(insertString);
+        } catch ( SQLException sqle ) {
+            throw new SqlException(sqle);
+        }
+    }
+
     private void getPreparedStatementForUpdate() throws SqlException {
         // each column is associated with a tableName in the extended describe info.
         String updateString = buildUpdateString();
@@ -4241,6 +4435,22 @@
                         statement_.section_.getPositionedUpdateSection()); // update section
     }
 
+    private final void resetUpdatedColumnsForInsert() {
+        // initialize updateColumns with nulls for all columns
+        if (updatedColumns_ == null) {
+            updatedColumns_ = new Object[resultSetMetaData_.columns_];
+        }
+        if (columnUpdated_ != null) {
+            columnUpdated_ = new boolean[resultSetMetaData_.columns_];
+        }
+        for (int i = 0; i < updatedColumns_.length; i++) {
+            updateColumn(i+1, null);
+        }
+        for (int i = 0; i < columnUpdated_.length; i++) {
+            columnUpdated_[i] = false;
+        }
+    }
+
     private final void resetUpdatedColumns() {
         if (updatedColumns_ != null) {
             for (int i = 0; i < updatedColumns_.length; i++) {
@@ -4290,6 +4500,14 @@
         if (column < 1 || column > resultSetMetaData_.columns_) {
             throw new SqlException(agent_.logWriter_, "Invalid argument: parameter index " +
                     column + " is out of range.");
+        }
+    }
+
+    private void checkUpdatableCursor() throws SqlException {
+        if (resultSetConcurrency_ == java.sql.ResultSet.CONCUR_READ_ONLY) {
+            throw new SqlException(agent_.logWriter_, 
+                    "This method should only be called on ResultSet objects " +
+                    "that are updatable(concurrency type CONCUR_UPDATABLE).");
         }
     }
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java?rev=375635&r1=375634&r2=375635&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/impl/jdbc/EmbedResultSet.java Tue Feb  7 08:09:10 2006
@@ -103,6 +103,9 @@
 	private DataValueDescriptor[] rowData;
 	protected boolean wasNull;
 	protected boolean isClosed;
+	private boolean isOnInsertRow;
+	private ExecRow currentRowBeforeInsert;
+	private ExecRow insertRow = null;
 	private Object	currentStream;
 
 	// immutable state
@@ -249,6 +252,12 @@
 		}		
 	}
 
+	private void checkNotOnInsertRow() throws SQLException {
+		if (isOnInsertRow) {
+			throw newSQLException(SQLState.NO_CURRENT_ROW);
+		}
+	}
+
 	// onRow protects us from making requests of
 	// resultSet that would fail with NullPointerExceptions
 	// or milder problems due to not having a row.
@@ -337,6 +346,10 @@
 								// on the underlying connection.  Do this
 								// outside of the connection synchronization.
 
+		if (isOnInsertRow) {
+			moveToCurrentRow();
+		}
+
 
 		synchronized (getConnectionSynchronization()) {
 
@@ -2044,7 +2057,7 @@
 	 * @see EmbedDatabaseMetaData#insertsAreDetected
 	 */
 	public boolean rowInserted() throws SQLException {
-		throw Util.notImplemented();
+		return false;
 	}
 
 	/**
@@ -2087,7 +2100,7 @@
 					getCursorName());
 	}
 
-	//do following few checks before accepting updatable resultset api
+	//do following few checks before accepting updateRow or deleteRow
 	//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
@@ -2095,8 +2108,7 @@
 	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);
+      checkUpdatableCursor(methodName);
 
       //2)Make sure JDBC ResultSet is not closed
       checkIfClosed(methodName);
@@ -2125,7 +2137,33 @@
       return currentRow.getColumn(columnIndex);
 	}
 
-	/**
+    /* do following few checks before accepting insertRow
+     * 1) Make sure this is an updatable ResultSet
+     * 2) Make sure JDBC ResultSet is not closed
+     * 3) Make sure JDBC ResultSet is positioned on insertRow
+     * 4) Make sure underneath language resultset is not closed
+     */
+    protected void checksBeforeInsert() throws SQLException {
+        // 1)Make sure this is an updatable ResultSet
+        // if not updatable resultset, then throw exception
+        checkUpdatableCursor("insertRow");
+
+        // 2)Make sure JDBC ResultSet is not closed
+        checkIfClosed("insertRow");
+
+        // 3)Make sure JDBC ResultSet is positioned on insertRow
+        if (!isOnInsertRow) {
+            throw newSQLException(SQLState.NOT_POSITIONED_ON_INSERT_ROW);
+        }
+
+        // 4)Make sure underneath language resultset is not closed
+        if (theResults.isClosed()) {
+            throw Util.generateCsSQLException(SQLState.LANG_RESULT_SET_NOT_OPEN, "insertRow");
+        }
+    }
+
+    
+    /**
 	 * JDBC 2.0
 	 * 
 	 * Give a nullable column a null value.
@@ -3208,7 +3246,94 @@
 	 *                insert row have not been given a value
 	 */
 	public void insertRow() throws SQLException {
-		throw Util.notImplemented();
+        synchronized (getConnectionSynchronization()) {
+            checksBeforeInsert();
+            setupContextStack();
+            LanguageConnectionContext lcc = null;
+            StatementContext statementContext = null;
+            try {
+                /*
+                 * construct the insert statement
+                 *
+                 * If no values have been supplied for a column, it will be set 
+                 * to the column's default value, if any. 
+                 * If no default value had been defined, the default value of a 
+                 * nullable column is set to NULL.
+                 */
+
+                boolean foundOneColumnAlready = false;
+                StringBuffer insertSQL = new StringBuffer("INSERT INTO ");
+                StringBuffer valuesSQL = new StringBuffer("VALUES (");
+                CursorActivation activation = getEmbedConnection().
+                        getLanguageConnection().lookupCursorActivation(getCursorName());
+
+                ExecCursorTableReference targetTable = 
+                        activation.getPreparedStatement().getTargetTable();
+                // got the underlying (schema.)table name
+                insertSQL.append(getFullBaseTableName(targetTable));
+                ResultDescription rd = theResults.getResultDescription();
+
+                insertSQL.append(" (");
+                // in this for loop we are constructing list of column-names 
+                // and values (?) ,... part of the insert sql
+                for (int i=1; i<=rd.getColumnCount(); i++) { 
+                    if (foundOneColumnAlready) {
+                        insertSQL.append(",");
+                        valuesSQL.append(",");
+                    }
+                    // using quotes around the column name 
+                    // to preserve case sensitivity
+                    insertSQL.append("\"" + 
+                            rd.getColumnDescriptor(i).getName() + "\"");
+                    if (columnGotUpdated[i-1]) { 
+                        valuesSQL.append("?");
+                    } else {
+                        valuesSQL.append("DEFAULT");
+                    }
+                    foundOneColumnAlready = true;
+                }
+                insertSQL.append(") ");
+                valuesSQL.append(") ");
+                insertSQL.append(valuesSQL);
+
+                lcc = getEmbedConnection().getLanguageConnection();
+
+                // Context used for preparing, don't set any timeout (use 0)
+                statementContext = lcc.pushStatementContext(
+                        isAtomic, 
+                        false, 
+                        insertSQL.toString(), 
+                        null, 
+                        false, 
+                        0L);
+                org.apache.derby.iapi.sql.PreparedStatement ps = 
+                        lcc.prepareInternalStatement(insertSQL.toString());
+                Activation act = ps.getActivation(lcc, false);
+
+                // in this for loop we are assigning values for parameters 
+                //in sql constructed earlier VALUES (?, ..)
+                for (int i=1, paramPosition=0; i<=rd.getColumnCount(); i++) { 
+                    // if the column got updated, do following
+                    if (columnGotUpdated[i-1]) {  
+                        act.getParameterValueSet().
+                                getParameterForSet(paramPosition++).
+                                setValue(currentRow.getColumn(i));
+                    }
+                }
+                // Don't see any timeout when inserting rows (use 0)
+                //execute the insert
+                org.apache.derby.iapi.sql.ResultSet rs = 
+                        ps.execute(act, false, true, true, 0L); 
+                rs.close();
+                rs.finish();
+
+                lcc.popStatementContext(statementContext, null);
+            } catch (StandardException t) {
+                throw closeOnTransactionError(t);
+            } finally {
+                restoreContextStack();
+            }
+        }
 	}
 
     /**
@@ -3223,6 +3348,10 @@
     public void updateRow() throws SQLException {
 			synchronized (getConnectionSynchronization()) {
         checksBeforeUpdateOrDelete("updateRow", -1);
+        
+        // Check that the cursor is not positioned on insertRow
+        checkNotOnInsertRow();
+        
         setupContextStack();
         LanguageConnectionContext lcc = null;
         StatementContext statementContext = null;
@@ -3294,6 +3423,9 @@
     public void deleteRow() throws SQLException {
         synchronized (getConnectionSynchronization()) {
             checksBeforeUpdateOrDelete("deleteRow", -1);
+        
+            // Check that the cursor is not positioned on insertRow
+            checkNotOnInsertRow();
 
             setupContextStack();
             //now construct the delete where current of sql
@@ -3375,6 +3507,9 @@
      */
     public void cancelRowUpdates () throws SQLException {
         checksBeforeUpdateOrDelete("cancelRowUpdates", -1);
+        
+        checkNotOnInsertRow();
+        
         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++){
@@ -3406,7 +3541,42 @@
 	 *                not updatable
 	 */
 	public void moveToInsertRow() throws SQLException {
-		throw Util.notImplemented();
+		// if not updatable resultset, then throw exception
+		checkUpdatableCursor("moveToInsertRow");
+
+		checkExecIfClosed("moveToInsertRow");
+
+		synchronized (getConnectionSynchronization()) {
+			try {
+				// initialize state corresponding to insertRow/updateRow impl.
+				for (int i=0; i < columnGotUpdated.length; i++) {
+					columnGotUpdated[i] = false;
+				}
+				currentRowHasBeenUpdated = false;
+
+				// Remember position
+				if (!isOnInsertRow) {
+					currentRowBeforeInsert = currentRow;
+				}
+
+				isOnInsertRow = true;
+
+				// If insertRow has not been allocated yet, get new insertRow
+				if (insertRow == null) {
+					insertRow = stmt.lcc.getExecutionContext().
+						getExecutionFactory().getValueRow(columnGotUpdated.length);
+				}
+				for (int i=1; i <= columnGotUpdated.length; i++) {
+					insertRow.setColumn(i, 
+						resultDescription.getColumnDescriptor(i).getType().getNull());
+				}
+				// Set currentRow to insertRow
+				currentRow = insertRow;
+				rowData = currentRow.getRowArray();
+			} catch (Throwable ex) {
+				handleException(ex);
+			}
+		}
 	}
 
 	/**
@@ -3420,7 +3590,36 @@
 	 *                not updatable
 	 */
 	public void moveToCurrentRow() throws SQLException {
-		throw Util.notImplemented();
+		// if not updatable resultset, then throw exception
+		checkUpdatableCursor("moveToCurrentRow");
+
+		checkExecIfClosed("moveToCurrentRow");
+
+		synchronized (getConnectionSynchronization()) {
+			try {
+
+				if (isOnInsertRow) {
+					// Get position previous to moveToInsertRow
+					currentRow = currentRowBeforeInsert;
+					currentRowBeforeInsert = null;
+
+					// initialize state corresponding to insertRow/updateRow impl.
+					for (int i=0; i < columnGotUpdated.length; i++) {
+						columnGotUpdated[i] = false;
+					}
+					currentRowHasBeenUpdated = false;
+
+					// Get rowData
+					if (currentRow != null) {
+						rowData = currentRow.getRowArray();
+					}
+
+					isOnInsertRow = false;
+				}
+			} catch (Throwable ex) {
+				handleException(ex);
+			}
+		}
 	}
 
     /**
@@ -3770,7 +3969,7 @@
 		if ((appConn == null) || appConn.isClosed())
 			throw Util.noCurrentConnection();
 	}
-
+    
 	/**
 	 * Try to see if we can fish the SQL Statement out of the local statement.
 	 * @return null if we cannot figure out what SQL Statement is currently
@@ -3915,6 +4114,16 @@
 							StandardException
 									.getSeverityFromIdentifier(SQLState.NOT_ON_FORWARD_ONLY_CURSOR));
 	}
+    
+    private void checkUpdatableCursor(String operation) throws SQLException {
+        if (getConcurrency() != JDBC20Translation.CONCUR_UPDATABLE) {
+            throw Util.generateCsSQLException(
+                    SQLState.UPDATABLE_RESULTSET_API_DISALLOWED, 
+                    operation);
+        }
+    }
+
+    
 	private boolean checkRowPosition(int position, String positionText)
 			throws SQLException {
 		// beforeFirst is only allowed on scroll cursors

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties?rev=375635&r1=375634&r2=375635&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_en.properties Tue Feb  7 08:09:10 2006
@@ -1122,6 +1122,7 @@
 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. Cannot issue ''{0}'' on this column.
 XJ085.S=Stream has already been read and end-of-file reached and cannot be re-used.
+XJ086.S=This method cannot be invoked unless the cursor is positioned on the insert row.
 0A000.S=Feature not implemented: {0}.
 
 XJ004.C=Database ''{0}'' not found.
@@ -1279,5 +1280,6 @@
 #
 #
 # ----------------------------------------------------------------------------------------------------------
+
 
 

Modified: db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_pt_BR.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_pt_BR.properties?rev=375635&r1=375634&r2=375635&view=diff
==============================================================================
--- db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_pt_BR.properties (original)
+++ db/derby/code/trunk/java/engine/org/apache/derby/loc/messages_pt_BR.properties Tue Feb  7 08:09:10 2006
@@ -1102,7 +1102,7 @@
 XJ082.U=Valores de BLOB/CLOB n\u00e3o s\u00e3o permitidos como par\u00e2metros ou receptores de m\u00e9todos.
 XJ083.U=''{0}'' n\u00e3o permitido porque o ResultSet n\u00e3o \u00e9 um ResultSet poss\u00edvel de atualizar. 
 XJ084.U=A coluna n\u00e3o corresponde \u00e0 coluna na tabela base. N\u00e3o \u00e9 poss\u00edvel emitir {0} nessa coluna.
-
+XJ086.S=Este m\u00E9todo n\u00E3o pode ser chamado a n\u00E3o ser que o cursor esteja posicionado na linha de inser\u00E7\u00E3o.
 0A000.S=Recurso n\u00e3o implementado: {0}.
 
 XJ004.C=Banco de dados ''{0}'' n\u00e3o localizado.

Modified: db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java?rev=375635&r1=375634&r2=375635&view=diff
==============================================================================
--- db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java (original)
+++ db/derby/code/trunk/java/shared/org/apache/derby/shared/common/reference/SQLState.java Tue Feb  7 08:09:10 2006
@@ -1445,6 +1445,7 @@
     //updatable resultset related
     String UPDATABLE_RESULTSET_API_DISALLOWED = "XJ083.U";
     String COLUMN_NOT_FROM_BASE_TABLE = "XJ084.U";
+    String NOT_POSITIONED_ON_INSERT_ROW = "XJ086.S";
 
     //following are session severity.
     String DATABASE_NOT_FOUND = "XJ004.C";