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 da...@apache.org on 2006/02/15 19:18:51 UTC

svn commit: r378045 [2/2] - in /db/derby/code/trunk/java: engine/org/apache/derby/impl/sql/execute/ testing/org/apache/derbyTesting/functionTests/harness/ testing/org/apache/derbyTesting/functionTests/master/ testing/org/apache/derbyTesting/functionTes...

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURBaseTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURBaseTest.java?rev=378045&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURBaseTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURBaseTest.java Wed Feb 15 10:18:47 2006
@@ -0,0 +1,305 @@
+/*
+ *
+ * Derby - Class SURBaseTest
+ *
+ * Copyright 2006 The Apache Software Foundation or its 
+ * licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, 
+ * software distributed under the License is distributed on an 
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
+ * either express or implied. See the License for the specific 
+ * language governing permissions and limitations under the License.
+ */
+package org.apache.derbyTesting.functionTests.tests.jdbcapi;
+import org.apache.derbyTesting.functionTests.util.DerbyJUnitTest;
+import org.apache.derbyTesting.functionTests.util.TestUtil;
+import org.apache.derby.tools.ij;
+import junit.framework.*;
+import java.sql.*;
+import java.util.Properties;
+
+/**
+ * Base class for testing Scrollable Updatable ResultSets. 
+ * The setUp() provides a Connection to the database.
+ * 
+ * Tests of this class needs to be decorated by a DBSetup
+ * and SURDataModelSetup.
+ * 
+ * @author Andreas Korneliussen 
+ */
+abstract public class SURBaseTest extends TestCase {
+    
+    /** Creates a new instance of SURBaseTest */
+    public SURBaseTest(String name) {
+        super(name);
+    }
+    
+    /**
+     * Get a JDBC Connection to the Derby database.
+     * The autocommit flag is set to false, and the isolation level
+     * for the transactions is set to repeatable read.
+     */
+    protected Connection getNewConnection() 
+        throws SQLException
+    {
+        final Connection rcon = getConnection();
+        rcon.setAutoCommit(false);
+        rcon.setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
+        return rcon;
+    }
+
+    static Connection getConnection() 
+        throws SQLException
+    {
+        String url = TestUtil.getJdbcUrlPrefix() + "wombat;create=true";
+        return DriverManager.getConnection(url);        
+    }
+    
+    /**
+     * Set up the connection to the database.
+     */
+    public void setUp() throws  Exception {       
+        println("SetUp");
+        TestUtil.loadDriver();
+        con = getNewConnection();
+    }
+    
+    /**
+     * Rollback the transaction
+     */
+    public void tearDown() throws Exception {
+        println("TearDown");
+        try { 
+            con.rollback();
+            con.close();
+        } catch (SQLException e) {
+            printStackTrace(e);
+        }      
+    }
+    
+    /**
+     * Verify the data of a tuple in the ResultSet, based on the data 
+     * that were inserted.
+     */
+    protected void verifyTuple(ResultSet rs) throws SQLException {
+        int id = rs.getInt(1);
+        int a = rs.getInt(2);
+        int b = rs.getInt(3);
+        int sum = a + id + 17;
+        println("Reading tuple:(" + id + "," + a  + "," + b + ",'" + 
+                rs.getString(4) + "')");
+        assertEquals("Expecting b==id+a+17, got: id=" + id + 
+                     ",a=" + a + ",b=" + b + ",c=" +rs.getString(4), b, sum);
+    }
+    
+    /**
+     * Update the current tuple in the ResultSet using updateXXX() and 
+     * updateRow()
+     */
+    protected void updateTuple(ResultSet rs) throws SQLException {
+        assertTrue("Cannot use updateRow() in autocommit mode", 
+                   !con.getAutoCommit());
+        int id = rs.getInt(1);
+        int a = rs.getInt(2);
+        int b = rs.getInt(3);        
+        int newA = a*2 +id + 37;
+        int newB = newA + id + 17;
+        println("Updating record (" + id + "," + newA + "," + newB + ")");
+        rs.updateInt(2, newA);
+        rs.updateInt(3, newB); 
+        rs.updateRow();
+    }
+    
+    /**
+     * Update the current tuple in the ResultSet using positioned update
+     */
+    protected void updateTuplePositioned(ResultSet rs) throws SQLException {
+        int id = rs.getInt(1);
+        int a = rs.getInt(2);
+        int b = rs.getInt(3);        
+        int newA = a*2 +id + 37;
+        int newB = newA + id + 17;
+        PreparedStatement ps = con.
+            prepareStatement("update T1 set a=?,b=? where current of " +
+                             rs.getCursorName());
+        ps.setInt(1, newA);
+        ps.setInt(2, newB);
+        assertEquals("Expected one tuple to be updated", 1, ps.executeUpdate());
+    }
+    
+    /**
+     * Scroll forward to the end of the ResultSet, and verify tuples while 
+     * scrolling. 
+     */
+    protected void scrollForward(ResultSet rs) throws SQLException
+    {        
+        boolean ignoreCount = rs.getType()==ResultSet.TYPE_FORWARD_ONLY 
+            || !rs.isBeforeFirst();
+        int nRecords = 0; 
+        while (rs.next()) {
+            nRecords++;
+            verifyTuple(rs);
+        }
+        if (!ignoreCount) {
+            assertEquals("Expected  " + recordCount + " records", nRecords, 
+                         recordCount);
+        }
+    }
+    
+    /**
+     * Scroll backward to the beginning of the ResultSet, and verify tuples 
+     * while scrolling.
+     */
+    protected void scrollBackward(ResultSet rs) throws SQLException
+    {
+        boolean ignoreCount = rs.getType()==ResultSet.TYPE_FORWARD_ONLY 
+            || !rs.isAfterLast();
+        
+        int nRecords = 0; 
+        while (rs.previous()) {
+            nRecords++;
+            verifyTuple(rs);
+        }
+        if (!ignoreCount) {
+            assertEquals("Expected  " + recordCount + " records", nRecords, 
+                         recordCount);
+        }
+    }
+    
+    /**
+     * Scroll forward and update the tuples using updateXXX() and updateRow()
+     */
+    protected void scrollForwardAndUpdate(ResultSet rs) throws SQLException
+    {
+        int nRecords = 0; 
+        boolean ignoreCount = rs.getType()==ResultSet.TYPE_FORWARD_ONLY 
+            || !rs.isBeforeFirst();
+        
+        while (rs.next()) {
+            nRecords++;
+            verifyTuple(rs);
+            updateTuple(rs);
+        }
+        if (!ignoreCount) {
+            assertEquals("Expected  " + recordCount + " records", nRecords, 
+                         recordCount);
+        }
+        assertNotNull("rs.getCursorName()", rs.getCursorName());
+    }
+    
+    /**
+     * Scroll forward and do positioned updates.
+     */
+    protected void scrollForwardAndUpdatePositioned(ResultSet rs) 
+        throws SQLException
+    {
+        int nRecords = 0; 
+        boolean ignoreCount = rs.getType()==ResultSet.TYPE_FORWARD_ONLY 
+            || !rs.isBeforeFirst();
+        while (rs.next()) {
+            nRecords++;
+            verifyTuple(rs);
+            updateTuplePositioned(rs);
+        }
+        if (!ignoreCount) {
+            assertEquals("Expected  " + recordCount + " records", nRecords, 
+                         recordCount);
+        }
+        assertNotNull("rs.getCursorName()", rs.getCursorName());
+    }
+    
+    /**
+     * Scroll backward and update the records using updateXXX() and updateRow()
+     */
+    protected void scrollBackwardAndUpdate(ResultSet rs) throws SQLException
+    {
+        int nRecords = 0; 
+        boolean ignoreCount = rs.getType()==ResultSet.TYPE_FORWARD_ONLY 
+            || !rs.isAfterLast();
+        while (rs.previous()) {
+            nRecords++;
+            verifyTuple(rs);
+            updateTuple(rs);
+        }
+        if (!ignoreCount) {
+            assertEquals("Expected  " + recordCount + " records", nRecords, 
+                         recordCount);
+        }
+        assertNotNull("rs.getCursorName()", rs.getCursorName());
+    }
+    
+    /**
+     * Scroll backward and update the records using positioned updates.
+     */
+    protected void scrollBackwardAndUpdatePositioned(ResultSet rs) 
+        throws SQLException
+    {
+        int nRecords = 0; 
+        boolean ignoreCount = rs.getType()==ResultSet.TYPE_FORWARD_ONLY 
+            || !rs.isAfterLast();
+        while (rs.previous()) {
+            nRecords++;
+            verifyTuple(rs);
+            updateTuplePositioned(rs);
+        }
+        if (!ignoreCount) {
+            assertEquals("Expected  " + recordCount + " records", nRecords, 
+                         recordCount);
+        }
+        assertNotNull("rs.getCursorName()", rs.getCursorName());
+    }
+    
+    /**
+     * Assert that update of ResultSet fails with a SQLException
+     * due to read-only ResultSet.
+     */
+    protected void assertFailOnUpdate(ResultSet rs) 
+        throws SQLException
+    {
+        boolean failedCorrect = false;
+        try {
+            updateTuple(rs);
+        } catch (SQLException e) {
+            failedCorrect = true;
+            assertEquals("Unexpected SQL state", 
+                         RESULTSET_NOT_UPDATABLE_SQL_STATE, 
+                         e.getSQLState());
+            
+        }
+        assertTrue("Expected cursor to fail on update, since it is read only", 
+                   failedCorrect);
+    }
+    
+    protected Connection con = null; // Connection established in setUp()
+    final static int recordCount = SURDataModelSetup.recordCount;  
+    
+       
+    /**
+     * Error codes and SQL state
+     */
+    final static String FOR_UPDATE_NOT_PERMITTED_SQL_STATE = "42Y90";
+    final static String CURSOR_NOT_UPDATABLE_SQL_STATE = "42X23";
+    final static String RESULTSET_NOT_UPDATABLE_SQL_STATE = "XJ083";
+    final static String LOCK_TIMEOUT_SQL_STATE = "40XL1";
+    final static String LOCK_TIMEOUT_EXPRESSION_SQL_STATE = "38000";
+    
+    static void println(String text) {
+        DerbyJUnitTest.println(text);
+    }
+    
+    /**
+     * Prints the stack trace. If run in the harness, the
+     * harness will mark the test as failed if this method
+     * has been called.
+     */
+    static void printStackTrace(Throwable t) {
+        DerbyJUnitTest.printStackTrace(t);
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURBaseTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURDataModelSetup.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURDataModelSetup.java?rev=378045&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURDataModelSetup.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURDataModelSetup.java Wed Feb 15 10:18:47 2006
@@ -0,0 +1,263 @@
+/*
+ *
+ * Derby - Class SURDataModelSetup
+ *
+ * Copyright 2006 The Apache Software Foundation or its 
+ * licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License");
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing, 
+ * software distributed under the License is distributed on an 
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND, 
+ * either express or implied. See the License for the specific 
+ * language governing permissions and limitations under the License.
+ */
+package org.apache.derbyTesting.functionTests.tests.jdbcapi;
+import org.apache.derbyTesting.functionTests.util.DerbyJUnitTest;
+import org.apache.derbyTesting.functionTests.util.TestUtil;
+import java.sql.Connection;
+import java.sql.DriverManager;
+import java.sql.PreparedStatement;
+import java.sql.SQLException;
+import java.sql.Statement;
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import java.util.Set;
+import java.util.Iterator;
+import java.util.HashSet;
+import java.util.Arrays;
+import java.util.Collections;
+
+/**
+ * This class is a decorator for the Scrollable Updatable Resultset
+ * tests.  It sets up a datamodel and populates it with data.
+ * @author Andreas Korneliussen
+ */
+public class SURDataModelSetup extends TestSetup
+{
+    /**
+     * Constructor.
+     * @param test test to decorate with this setup
+     * @param model enumerator for which model to use.
+     * (Alternatively we could use a subclass for each model)
+     */
+    public SURDataModelSetup(Test test, SURDataModel model) {
+        super(test);
+        this.model = model;       
+    }
+    
+    /**
+     * Creates a datamodel for testing Scrollable Updatable ResultSets
+     * and populates the database model with data.
+     * @param model enumerator for which model to use
+     * @param con connection to database
+     */
+    public static void createDataModel(SURDataModel model, Connection con) 
+        throws SQLException
+    {
+        try { 
+            con.createStatement().execute("drop table t1"); 
+        } catch (SQLException e) {
+            assertEquals("'drop table t1' failed with unexpected SQL State",
+                         TABLE_EXISTS_SQL_STATE, e.getSQLState());
+            
+            // The net framework does not give any valuable error code
+            if (TestUtil.isNetFramework()) {
+                
+                assertEquals("'drop table t1' failed with unexpected error code",
+                             NET_ERROR, e.getErrorCode());
+            } else {
+                assertEquals("'drop table t1' failed with unexpected error code",
+                             TABLE_EXISTS_ERRORCODE, e.getErrorCode());
+            }
+            
+        };
+        
+        Statement statement = con.createStatement();
+        
+        /** Create the table */
+        statement.execute(model.getCreateTableStatement());
+        println(model.getCreateTableStatement());
+        
+        /** Create secondary index */
+        if (model.hasSecondaryKey()) {
+            statement.execute("create index a_on_t on t1(a)");
+            println("create index a_on_t on t1(a)");
+        }
+        
+        /** Populate with data */
+        PreparedStatement ps = con.
+            prepareStatement("insert into t1 values (?,?,?,?)");
+        
+        for (int i=0; i<recordCount; i++) {
+            ps.setInt(1, i);
+            ps.setInt(2, i);
+            ps.setInt(3, i*2 + 17);
+            ps.setString(4, "Tuple " +i);
+            ps.addBatch();
+        }
+        ps.executeBatch();
+        con.commit();
+    }
+    
+    /**
+     * Creates a datamodel for testing Scrollable Updatable ResultSets
+     * and populates the database model with data.
+     */
+    public void setUp() throws  Exception {       
+        TestUtil.loadDriver();
+        println("Setting up datamodel: " + model);
+        try {
+            con = getNewConnection();
+            createDataModel(model, con);
+        } catch (SQLException e) {
+            printStackTrace(e); // Print the entire stack
+            throw e;
+        }
+    }
+    
+    /**
+     * Delete the datamodel
+     */
+    public void tearDown() 
+        throws Exception
+    {
+        try {
+            con.rollback();
+            con.createStatement().execute("drop table t1");
+            con.commit();
+            con.close();
+        } catch (SQLException e) {
+            printStackTrace(e);
+        }
+    }
+    
+    public String toString() {
+        return "SURDataModel tests with model: " + model;
+    }
+
+    /**
+     * Get a JDBC Connection to the Derby database
+     */
+    private Connection getNewConnection() 
+        throws SQLException
+    {
+        final Connection rcon = SURBaseTest.getConnection();
+        rcon.setAutoCommit(false);
+        return rcon;
+    }
+
+    private Connection con = null;
+    private final SURDataModel model;
+    final static int recordCount = 10;  // Number of records in data model.  
+        
+    /**
+     * Enum for the layout of the data model
+     */
+    public final static class SURDataModel {
+
+        /** Model with no keys */
+        public final static SURDataModel MODEL_WITH_NO_KEYS = 
+            new SURDataModel("NO_KEYS");
+        
+        /** Model with primary key */
+        public final static SURDataModel MODEL_WITH_PK = 
+            new SURDataModel("PK");
+        
+        /** Model with secondary index */
+        public final static SURDataModel MODEL_WITH_SECONDARY_KEY = 
+            new SURDataModel("SECONDARY_KEY");
+        
+        /** Model with primary key and secondary index */
+        public final static SURDataModel MODEL_WITH_PK_AND_SECONDARY_KEY = 
+            new SURDataModel("PK_AND_SECONDARY_KEY");
+
+        /** Array with all values */
+        private final static Set values = Collections.unmodifiableSet
+            (new HashSet((Arrays.asList(new SURDataModel[] {
+                MODEL_WITH_NO_KEYS, 
+                MODEL_WITH_PK, 
+                MODEL_WITH_SECONDARY_KEY,
+                MODEL_WITH_PK_AND_SECONDARY_KEY
+            }))));
+        
+        /**
+         * Returns an unmodifyable set of all valid data models
+         */ 
+        public final static Set values() {
+            return values;
+        }
+       
+
+        /** Returns true if this model has primary key */
+        public boolean hasPrimaryKey() {
+            return (this==MODEL_WITH_PK || 
+                    this==MODEL_WITH_PK_AND_SECONDARY_KEY);
+        }
+        
+        /** Returns true if this model has a secondary key */
+        public boolean hasSecondaryKey() {
+            return (this==MODEL_WITH_SECONDARY_KEY || 
+                    this==MODEL_WITH_PK_AND_SECONDARY_KEY);
+        }
+
+        /**
+         * Returns the string for creating the table
+         */
+        public String getCreateTableStatement() {
+            return hasPrimaryKey() 
+                ? "create table t1 (id int primary key, a int, b int, c varchar(5000))"
+                : "create table t1 (id int, a int, b int, c varchar(5000))";
+        }
+
+        /**
+         * Returns a string representation of the model 
+         * @return string representation of this object
+         */
+        public String toString() {
+            return name;
+        }
+        
+        /**
+         * Constructor
+         */
+        private SURDataModel(String name) {
+            this.name = name;
+        }
+        
+        
+        
+        private final String name;
+    }
+
+    /**
+     * <p>
+     * Debug code to print chatty informational messages.
+     * </p>
+     */
+    public static void println(String text)
+    {
+        DerbyJUnitTest.println(text);
+    }
+    
+    /**
+     * Prints the stack trace. If run in the harness, the
+     * harness will mark the test as failed if this method
+     * has been called.
+     */
+    static void printStackTrace(Throwable t) {
+        DerbyJUnitTest.printStackTrace(t);
+    }
+    
+    /**
+     * Error codes and SQL state
+     */
+    private final static String TABLE_EXISTS_SQL_STATE = "42Y55";
+    private final static int TABLE_EXISTS_ERRORCODE = 20000;
+    private final static int NET_ERROR = -1; 
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURDataModelSetup.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest.java?rev=378045&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest.java Wed Feb 15 10:18:47 2006
@@ -0,0 +1,554 @@
+/*
+ *
+ * Derby - Class SURQueryMixTest
+ *
+ * Copyright 2006 The Apache Software Foundation or its
+ * licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ */
+package org.apache.derbyTesting.functionTests.tests.jdbcapi;
+import java.sql.DatabaseMetaData;
+import java.sql.ResultSet;
+import java.sql.ResultSetMetaData;
+import java.sql.SQLException;
+import java.sql.PreparedStatement;
+import java.sql.Statement;
+import java.sql.Types;
+import java.util.ArrayList;
+import java.util.HashMap;
+import java.util.HashSet;
+import java.util.Iterator;
+import java.util.List;
+import java.util.Map;
+import java.util.Random;
+import java.util.Set;
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+
+/**
+ * Tests for Scrollable Updatable ResultSet (SUR). This TestCase tests
+ * scrolling (navigation), updates (using updateXXX() and updateRow() or
+ * positioned updates), deletion of records (using deleteRow() or positioned 
+ * deletes) of ResultSets.
+ * @author Andreas Korneliussen
+ */
+public class SURQueryMixTest extends SURBaseTest
+{
+    /**
+     * Constructor
+     * @param name model name of data model for this TestCase
+     * @param query to use for producing the resultset
+     * @param cursorName name of cursor
+     * @param positioned flag to determine if the Test should use positioned
+     *        updates/deletes instead of updateRow() and deleteRow()
+     */
+    public SURQueryMixTest(final String model, final String query, 
+                           final String cursorName, final boolean positioned) 
+    {
+        super("SURQueryMixTest{Model=" + model + ",Query=" +query + ",Cursor=" 
+                + cursorName + ",Positioned=" + positioned + "}");
+        this.query = query;
+        this.cursorName = cursorName;
+        this.positioned = positioned;
+        this.checkRowUpdated = false;
+        this.checkRowDeleted = false;
+    }
+
+    /**
+     * Test SUR properties of the query
+     */
+    public void runTest() 
+        throws SQLException
+    {
+        println(query);
+        DatabaseMetaData dbMeta = con.getMetaData();
+                
+        if (dbMeta.ownDeletesAreVisible(ResultSet.TYPE_SCROLL_INSENSITIVE)) {
+            checkRowDeleted = true;
+        }
+        
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE,
+                                          ResultSet.CONCUR_UPDATABLE);
+        
+        s.setCursorName(cursorName);
+        ResultSet rs = s.executeQuery(query);
+
+        checkRowUpdated = dbMeta.ownUpdatesAreVisible(rs.getType());        
+        checkRowDeleted = dbMeta.ownDeletesAreVisible(rs.getType());
+        
+        // Create map with rows
+        Map rows = createRowMap(rs);
+        
+        // Set of rows which are updated (contains Integer with position in RS)
+        final Set updatedRows = new HashSet();
+        
+        // Set of rows which are deleted (contains Integer with position in RS)
+        final Set deletedRows = new HashSet();
+                
+        // Test navigation
+        testNavigation(rs, rows, updatedRows, deletedRows);
+        
+        // Only test updatability if the ResultSet is updatable:
+        // (Note: this enables the test do run successfully even if
+        // scrollable updatable resultsets are not implemented. 
+        // If SUR is not implemented, a well behaved JDBC driver will 
+        // downgrade the concurrency mode to READ_ONLY).
+        // SUR may be implemented incrementally, i.e first in embedded mode
+        // then in the network driver.)
+        if (rs.getConcurrency()==ResultSet.CONCUR_UPDATABLE) {
+        
+            // update a random sample of 2 records
+            updateRandomSampleOfNRecords(rs, rows, updatedRows, 2); 
+            testNavigation(rs, rows, updatedRows, deletedRows); 
+            
+            // update a random sample of 5 records
+            updateRandomSampleOfNRecords(rs, rows, updatedRows, 5); 
+            testNavigation(rs, rows, updatedRows, deletedRows); 
+            
+            // update a random sample of 10 records
+            updateRandomSampleOfNRecords(rs, rows, updatedRows, 10); 
+            testNavigation(rs, rows, updatedRows, deletedRows); 
+            
+            // delete a random sample of 2 records
+            deleteRandomSampleOfNRecords(rs, rows, deletedRows, 2);
+            testNavigation(rs, rows, updatedRows, deletedRows); 
+            
+            // delete a random sample of 5 records
+            deleteRandomSampleOfNRecords(rs, rows, deletedRows, 5);
+            testNavigation(rs, rows, updatedRows, deletedRows); 
+            
+            // delete a random sample of 10 records
+            deleteRandomSampleOfNRecords(rs, rows, deletedRows, 10);
+            testNavigation(rs, rows, updatedRows, deletedRows); 
+        } else {
+            println("Skipped testing updatability");
+        }
+        
+        rs.close();
+    }
+    
+    /**
+     * Creates a Map of the values in the ResultSet. 
+     * The key object in the map, is the postion in the 
+     * ResultSet (Integer 1..n), while the value is a
+     * concatenation of the strings for all columns in the row.
+     */
+    private Map createRowMap(final ResultSet rs) 
+        throws SQLException
+    {
+        final Map rows = new HashMap();        
+        rs.beforeFirst();
+        assertTrue("Unexpected return from isBeforeFirst()",
+                   rs.isBeforeFirst());
+        
+        int i = 0;
+        int sum = 0;
+        int expectedSum = 0;
+        boolean checkSum = true;
+        while (rs.next()) {
+            expectedSum += i;
+            i++;
+            String row = getRowString(rs);
+            println(row);
+            rows.put(new Integer(i), row);
+            sum += rs.getInt(1);
+            if (rs.getInt(1) < 0) {
+                checkSum = false;
+            }
+        }
+        if (i<SURDataModelSetup.recordCount) {
+            checkSum = false;
+        }
+        
+        assertTrue("Unexpected return from isAfterLast()", rs.isAfterLast());
+        
+        if (checkSum) {
+            assertEquals("Sum for column 1 is not correct", expectedSum, sum);
+        }
+        
+        return rows;
+    }
+
+    /**
+     * Create a random sample of rows
+     * @param rows Map to create sample from
+     * @param k number of rows in the sample
+     * @return a list containing k elements of rows
+     **/
+    private List createRandomSample(final Map rows, int k) {
+        Random r = new Random();
+        ArrayList sampledKeys = new ArrayList();
+        int n = 0;        
+        for (Iterator i = rows.keySet().iterator(); i.hasNext();) {
+            Object key = i.next();
+            n++;            
+            if (n<=k) {
+                sampledKeys.add(key);
+            } else {
+                // sampledKeys now has a size of k
+                double d = r.nextDouble();
+                // p = probability of going into the sample
+                double p = (double) k / (double) n; 
+                if (d<p) {
+                    // Replace a random value from the sample with the new value
+                    int keyToReplace = Math.abs(r.nextInt())%k;                    
+                    sampledKeys.set(keyToReplace, key);
+                }
+            }
+        }
+        return sampledKeys;
+    }
+    
+    /**
+     * Delete a random sample of n records in the resultset
+     * @param rs result set to be updated
+     * @param rows map of rows, will also be updated
+     * @param deletedRows set of rows being deleted (position in RS)
+     * @param k number of records to be deleted
+     */
+    private void deleteRandomSampleOfNRecords(final ResultSet rs, 
+                                              final Map rows,
+                                              final Set deletedRows,
+                                              final int k) 
+        throws SQLException
+    {
+        List sampledKeys = createRandomSample(rows, k);
+        println("Sampled keys:" + sampledKeys);
+        ResultSetMetaData meta = rs.getMetaData();
+        for (Iterator i = sampledKeys.iterator(); i.hasNext();) {
+            Integer key = (Integer) i.next();
+            rs.absolute(key.intValue());            
+            if (rs.rowDeleted()) continue; // skip deleting row if already deleted
+            if (positioned) {
+                con.createStatement().executeUpdate
+                        ("DELETE FROM T1 WHERE CURRENT OF \"" + cursorName + 
+                         "\"");
+                
+                rs.relative(0); // If this call is not here, the old values are
+                                // returned in rs.getXXX calls
+            } else {
+                rs.deleteRow();
+            }
+            println("Deleted row " + key);
+            // Update the rows table
+            rows.put(key, getRowString(rs));
+            
+            // Update the updatedRows set
+            deletedRows.add(key);
+        }
+    }
+    
+    /**
+     * Update a random sample of n records in the resultset
+     * @param rs result set to be updated
+     * @param rows map of rows, will also be updated
+     * @param updatedRows set of being updated (position in RS)
+     * @param k number of records to be updated
+     */
+    private void updateRandomSampleOfNRecords(final ResultSet rs, 
+                                              final Map rows,
+                                              final Set updatedRows,
+                                              final int k) 
+        throws SQLException
+    {
+        List sampledKeys = createRandomSample(rows, k);
+        println("Sampled keys:" + sampledKeys);
+        ResultSetMetaData meta = rs.getMetaData();
+        for (Iterator i = sampledKeys.iterator(); i.hasNext();) {
+            Integer key = (Integer) i.next();
+            rs.absolute(key.intValue());            
+            
+            if (positioned) {
+                updatePositioned(rs, meta);
+                rs.relative(0); // If this call is not here, the old values are
+                                // returned in rs.getXXX calls
+            } else {
+                updateRow(rs, meta);
+            }
+            // Update the rows table
+            rows.put(key, getRowString(rs));
+            
+            // Update the updatedRows set
+            updatedRows.add(key);
+        }
+    }
+
+    /**
+     * Updates the current row in the ResultSet using updateRow()
+     * @param rs ResultSet to be updated
+     * @param meta meta for the ResultSet
+     **/
+    private void updateRow(final ResultSet rs, final ResultSetMetaData meta) 
+        throws SQLException
+    {
+        for (int column = 1; column<=meta.getColumnCount(); column++) {
+            if (meta.getColumnType(column)==Types.INTEGER) {
+                // Set to negative value
+                rs.updateInt(column, -rs.getInt(column));
+            } else {
+                rs.updateString(column, "UPDATED_" + rs.getString(column));
+            }
+        }
+        rs.updateRow();
+    }
+    
+    /**
+     * Updates the current row in the ResultSet using updateRow()
+     * @param rs ResultSet to be updated
+     * @param meta meta for the ResultSet
+     **/
+    private void updatePositioned(final ResultSet rs, 
+                                  final ResultSetMetaData meta) 
+        throws SQLException                          
+    {
+        StringBuffer sb = new StringBuffer();
+        sb.append("UPDATE T1 SET ");
+        for (int column = 1; column<=meta.getColumnCount(); column++) {
+            sb.append(meta.getColumnName(column));
+            sb.append("=?");
+            if (column<meta.getColumnCount()) {
+                sb.append(",");
+            }
+        }
+        sb.append(" WHERE CURRENT OF \"");
+        sb.append(cursorName);
+        sb.append("\"");
+        println(sb.toString());
+        PreparedStatement ps = con.prepareStatement(sb.toString());
+        
+        for (int column = 1; column<=meta.getColumnCount(); column++) {
+           if (meta.getColumnType(column)==Types.INTEGER) {
+                // Set to negative value
+                ps.setInt(column, -rs.getInt(column));
+            } else {
+                ps.setString(column, "UPDATED_" + rs.getString(column));
+            }
+        }
+        assertEquals("Expected one row to be updated", 1, ps.executeUpdate());        
+    }
+    
+    
+    /**
+     * Tests navigation in ResultSet. This test requires that the ResultSet
+     * is not empty, and positioned before the first row. Also the 
+     * ResultSet needs to contain column a or column id as the first column from
+     * the SURDataModel (for checksum test)
+     * @return a Map with all rows in the resultset (concatnated as a string)
+     */
+    private void testNavigation(final ResultSet rs, final Map rows, 
+                                final Set updatedRows, final Set deletedRows) 
+        throws SQLException
+    {        
+        rs.afterLast();
+        {
+            int i = rows.size();
+            while (rs.previous()) {
+                String rowString = getRowString(rs);
+                assertEquals("Navigating with rs.previous(). The row is " +
+                             "different compared to the value when navigating " +
+                             "forward.", rows.get(new Integer(i)), rowString);
+                
+                
+                if (checkRowUpdated && updatedRows.contains(new Integer(i))) {
+                    assertTrue("Expected rs.rowUpdated() to return true on " + 
+                               "updated row " + rowString, rs.rowUpdated());
+                } 
+                if (checkRowDeleted && deletedRows.contains(new Integer(i))) {
+                    assertTrue("Expected rs.rowDeleted() to return true on " + 
+                               "deleted row " + rowString, rs.rowDeleted());
+                } 
+                i--;
+            }
+        }
+        // Test absolute
+        for (int i = 1; i <= rows.size(); i++) {
+            assertTrue("Unexpected return from absolute()", rs.absolute(i));
+            String rowString = getRowString(rs);
+            assertEquals("Navigating with rs.absolute(). The row is " +
+                         "different compared to the value" +
+                         " when navigating forward.", 
+                         rows.get(new Integer(i)),
+                         rowString);
+            if (checkRowUpdated && updatedRows.contains(new Integer(i))) {
+                assertTrue("Expected rs.rowUpdated() to return true on " +
+                           "updated row " + rowString, rs.rowUpdated());
+            }
+            if (checkRowDeleted && deletedRows.contains(new Integer(i))) {
+                assertTrue("Expected rs.rowDeleted() to return true on " +
+                           "deleted row " + rowString, rs.rowDeleted());
+            }
+        }
+        assertFalse("Unexpected return from absolute()", rs.absolute(0));
+        assertTrue("Unexpected return from isBeforeFirst()", 
+                   rs.isBeforeFirst());
+        assertFalse("Unexpected return from absolute()", 
+                    rs.absolute(rows.size() + 1));
+        assertTrue("Unexpected return from isAfterLast()", rs.isAfterLast());
+        assertTrue("Unexpected return from absolute()", rs.absolute(-1));
+        assertTrue("Unexpected return from isLast()", rs.isLast());
+        assertTrue("Unexpected return from absolute()", rs.absolute(1));
+        assertTrue("Unexpected return from isFirst()", rs.isFirst());
+        
+        // Test relative
+        {
+            rs.beforeFirst();
+            assertTrue("Unexptected return from isBeforeFirst()", 
+                       rs.isBeforeFirst());
+            
+            int relativePos = rows.size();
+            assertTrue("Unexpected return from relative()", 
+                       rs.relative(relativePos)); 
+            
+            // Should now be on the last row
+            assertTrue("Unexptected return from isLast()", rs.isLast());
+            assertEquals("Navigating with rs.relative(+). " +
+                         "A tuple was different compared to the value" +
+                         " when navigating forward.", 
+                         rows.get(new Integer(relativePos)),
+                         getRowString(rs));
+            
+            assertTrue("Unexpected return from relative()", 
+                       rs.relative((-relativePos + 1))); 
+            
+            // Should now be on the first row
+            assertTrue("Unexptected return from isFirst()", rs.isFirst());
+            
+            assertEquals("Navigating with rs.relative(-). " + 
+                         "A tuple was different compared to the value" +
+                         " when navigating forward.", 
+                         rows.get(new Integer(1)),
+                         getRowString(rs));
+            
+        }
+        // Test navigation in the end of the ResultSet
+        rs.afterLast();
+        assertTrue("Unexpected return from isAfterLast()", rs.isAfterLast());
+        assertTrue("Unexpected return from previous()", rs.previous());
+        assertTrue("Unexpected return from isLast()", rs.isLast());
+        assertFalse("Unexpected return from next()", rs.next());
+        assertTrue("Unexpected return from isAfterLast()", rs.isAfterLast());
+        rs.last();
+        assertTrue("Unexpected return from isLast()", rs.isLast());
+        assertFalse("Unexpected return from next()", rs.next());
+        assertTrue("Unexpected return from isAfterLast()", rs.isAfterLast());
+
+
+        // Test navigation in the beginning of the ResultSet
+        rs.beforeFirst();
+        assertTrue("Unexpected return from isBeforeFirst()", 
+                   rs.isBeforeFirst());
+        assertTrue("Unexpected return from next()", rs.next());
+        assertTrue("Unexpected return from isFirst", rs.isFirst());
+        assertFalse("Unexpected return from previous()", rs.previous());
+        assertTrue("Unexpected return from isBeforeFirst()", 
+                   rs.isBeforeFirst());
+        
+        rs.first();
+        assertTrue("Unexpected return from isFirst", rs.isFirst());
+        assertFalse("Unexpected return from previous()", rs.previous());
+        assertTrue("Unexpected return from isBeforeFirst()", 
+                   rs.isBeforeFirst());
+    }
+
+    /**
+     * Get a concatenation of the values of the 
+     * current Row in the ResultSet
+     */
+    private String getRowString(final ResultSet rs) 
+        throws SQLException
+    {
+        int numberOfColumns = rs.getMetaData().getColumnCount();
+        StringBuffer sb = new StringBuffer();
+        if (rs.rowDeleted()) return "";
+        for (int i = 1; i <= numberOfColumns; i++) {
+            sb.append(rs.getString(i));
+            if (i < numberOfColumns) { 
+                sb.append(','); 
+            }
+        }
+        return sb.toString();
+    }
+    
+    private final String query;
+    private final String cursorName;
+    private final boolean positioned;
+    private boolean checkRowUpdated;
+    private boolean checkRowDeleted;
+    
+    private final static String[] selectConditions = new String[] {
+        "WHERE c like 'T%'",
+        " ",        
+        "WHERE b > 5",
+        "WHERE id >= a",
+        "WHERE id > 1 and id < 900",
+        "WHERE id = 1",
+        "WHERE id in (1,3,4,600,900,955,966,977,978)",
+        "WHERE a in (1,3,4,600,9200,955,966,977,978)",
+        "WHERE a>2 and a<9000"
+    };
+    
+    private final static String[] projectConditions = new String[] {
+        "id,c,a,b",
+        "id,c",
+        "a,b",
+        "*",
+        "id,a,b,c",        
+        "id,a",           
+        "a,b,c",        
+        "a,c"
+    };
+    
+    private static TestSuite createTestCases(final String modelName) {
+        TestSuite suite = new TestSuite();
+        for (int doPos = 0; doPos<2; doPos++) {
+            boolean positioned = doPos>0; // true if to use positioned updates
+
+            for (int i = 0; i < selectConditions.length; i++) {
+                for (int j = 0; j < projectConditions.length; j++) {
+                    final String cursorName = "cursor_" + i + "_" + j;
+                    
+                    final String stmtString = "SELECT " + projectConditions[j] +
+                            " FROM T1 " + selectConditions[i];
+                    suite.addTest(new SURQueryMixTest(modelName, stmtString, cursorName, 
+                                              positioned));
+                }
+            }
+        }
+        return suite;
+    }
+    
+    /**
+     * The suite contains all testcases in this class running on different data models
+     */
+    public static Test suite() 
+    {   
+        TestSuite mainSuite = new TestSuite();
+        
+        // Iterate over all data models and decorate the tests:
+        for (Iterator i = SURDataModelSetup.SURDataModel.values().iterator();
+             i.hasNext();) {
+            
+            SURDataModelSetup.SURDataModel model =
+                (SURDataModelSetup.SURDataModel) i.next();
+            
+            TestSuite suite = createTestCases(model.toString());
+            TestSetup decorator = new SURDataModelSetup(suite, model);
+            mainSuite.addTest(decorator);
+        }
+        return mainSuite;
+    }
+    
+  
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest_app.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest_app.properties?rev=378045&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest_app.properties (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest_app.properties Wed Feb 15 10:18:47 2006
@@ -0,0 +1,3 @@
+runwithibm13=false
+runwithjdk13=false
+runwithjdk12=false

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURQueryMixTest_app.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest.java?rev=378045&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest.java (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest.java Wed Feb 15 10:18:47 2006
@@ -0,0 +1,887 @@
+/*
+ *
+ * Derby - Class SURTest
+ *
+ * Copyright 2006 The Apache Software Foundation or its
+ * licensors, as applicable.
+ *
+ * Licensed under the Apache License, Version 2.0 (the "License")
+ * you may not use this file except in compliance with the License.
+ * You may obtain a copy of the License at
+ *
+ *    http://www.apache.org/licenses/LICENSE-2.0
+ *
+ * Unless required by applicable law or agreed to in writing,
+ * software distributed under the License is distributed on an
+ * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
+ * either express or implied. See the License for the specific
+ * language governing permissions and limitations under the License.
+ */
+package org.apache.derbyTesting.functionTests.tests.jdbcapi;
+import java.sql.PreparedStatement;
+import java.sql.ResultSet;
+import java.sql.SQLException;
+import java.sql.SQLWarning;
+import java.sql.Statement;
+import junit.extensions.TestSetup;
+import junit.framework.Test;
+import junit.framework.TestSuite;
+import java.util.Iterator;
+/**
+ * Tests for variants of scrollable updatable resultsets.
+ *
+ * @author Andreas Korneliussen
+ */
+public class SURTest extends SURBaseTest {
+    
+    /** Creates a new instance of SURTest */
+    public SURTest(String name) {
+        super(name);
+    }
+    
+    /**
+     * Test that you get a warning when specifying a query which is not
+     * updatable and concurrency mode CONCUR_UPDATABLE.
+     * In this case, the query contains an "order by"
+     */
+    public void testConcurrencyModeWarning1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 order by a");
+        
+        SQLWarning warn = rs.getWarnings();
+        assertEquals("Expected resultset to be read only",
+                     ResultSet.CONCUR_READ_ONLY,
+                     rs.getConcurrency());
+        assertNotNull("Expected to get a warning", warn);
+        scrollForward(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test that you get a warning when specifying a query which is not
+     * updatable and concurrency mode CONCUR_UPDATABLE.
+     * In this case, the query contains a join.
+     */
+    public void testConcurrencyModeWarning2()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery
+            ("select * from t1 as table1,t1 as table2 where " +
+             "table1.a=table2.a");
+        
+        SQLWarning warn = rs.getWarnings();
+        assertEquals("Expected resultset to be read only",
+                     ResultSet.CONCUR_READ_ONLY,
+                     rs.getConcurrency());
+        assertNotNull("Expected to get a warning", warn);
+        scrollForward(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test that you get an exception when specifying update clause
+     * "FOR UPDATE"
+     * along with a query which is not updatable.
+     * In this case, the query contains and order by.
+     */
+    public void testForUpdateException1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        try {
+            String queryString =
+                "select * from t1 order by a for update";
+            s.setCursorName(getNextCursorName());
+            ResultSet rs = s.executeQuery(queryString);
+            
+            assertTrue("Expected query '" + queryString +
+                       "' to fail", false);
+        } catch (SQLException e) {
+            assertEquals("Unexpected SQLState", 
+                         FOR_UPDATE_NOT_PERMITTED_SQL_STATE,
+                         e.getSQLState());
+        }
+        con.rollback();
+    }
+    
+    /**
+     * Test that you get an exception when specifying update clause
+     * "FOR UPDATE" along with a query which is not updatable.
+     * In this case, the query contains a join
+     */
+    public void testForUpdateException2()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        try {
+            String queryString =
+                "select * from t1 as table1,t1 as table2" +
+                " where table1.a=table2.a for update";
+            s.setCursorName(getNextCursorName());
+            ResultSet rs = s.executeQuery(queryString);
+            
+            assertTrue("Expected query '" + queryString + "' to fail",
+                       false);
+        } catch (SQLException e) {
+            assertEquals("Unexpected SQLState", 
+                         FOR_UPDATE_NOT_PERMITTED_SQL_STATE,
+                         e.getSQLState());
+        }
+        con.rollback();
+    }
+    
+    /**
+     * Test that you can scroll forward and read all records in the
+     * ResultSet
+     */
+    public void testForwardOnlyReadOnly1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_READ_ONLY);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        scrollForward(rs);
+        rs.close();
+    }
+    
+    
+    /**
+     * Test that you get an exception if you try to update a ResultSet
+     * with concurrency mode CONCUR_READ_ONLY.
+     */
+    public void testFailOnUpdateOfReadOnlyResultSet1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_READ_ONLY);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.next();
+        assertFailOnUpdate(rs);
+    }
+    
+    /**
+     * Test that you get an exception when attempting to update a
+     * ResultSet which has been downgraded to a read only ResultSet.
+     */
+    public void testFailOnUpdateOfReadOnlyResultSet2()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 order by id");
+        
+        rs.next();
+        assertFailOnUpdate(rs);
+    }
+    
+    /**
+     * Test that you get an exception when attempting to update a
+     * ResultSet which has been downgraded to a read only ResultSet.
+     */
+    public void testFailOnUpdateOfReadOnlyResultSet3()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs =
+            s.executeQuery("select * from t1 for read only");
+        
+        rs.next();
+        assertFailOnUpdate(rs);
+    }
+    
+    /**
+     * Test that you get an exception when attempting to update a
+     * ResultSet which has been downgraded to a read only ResultSet.
+     */
+    public void testFailOnUpdateOfReadOnlyResultSet4()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery
+            ("select * from t1 where a=1 for read only");
+        
+        rs.next();
+        verifyTuple(rs);
+        assertFailOnUpdate(rs);
+    }
+    
+    
+    /**
+     * Test that you get an exception if you try to update a ResultSet
+     * with concurrency mode CONCUR_READ_ONLY.
+     */
+    public void testFailOnUpdateOfReadOnlyResultSet5()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.
+                                          TYPE_SCROLL_INSENSITIVE,
+                                          ResultSet.CONCUR_READ_ONLY);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery
+            ("select * from t1 where a=1 for read only");
+        
+        rs.next();
+        verifyTuple(rs);
+        assertFailOnUpdate(rs);
+    }
+    
+    /**
+     * Test that you can scroll forward and update indexed records in
+     * the ResultSet (not using FOR UPDATE)
+     */
+    public void testIndexedUpdateCursor1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 where a=1");
+        
+        assertTrue("Expected to get a tuple on rs.next()", rs.next());
+        verifyTuple(rs);
+        updateTuple(rs);
+        
+    }
+    
+    /**
+     *  Test that you can scroll forward and update indexed records
+     *  in the ResultSet (using FOR UPDATE).
+     */
+    public void testIndexedUpdateCursor2()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY,
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs =
+            s.executeQuery("select * from t1 where a=1 for update");
+        
+        assertTrue("Expected to get a tuple on rs.next()", rs.next());
+        verifyTuple(rs);
+        updateTuple(rs);
+    }
+    
+    /**
+     *  Test that you can scroll forward and update indexed records
+     *  in the scrollable ResultSet (not using FOR UPDATE).
+     */
+    public void
+        testIndexedScrollInsensitiveUpdateCursorWithoutForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs =
+            s.executeQuery("select * from t1 where a=1 or a=2");
+        
+        rs.next();
+        rs.next();
+        rs.previous();
+        verifyTuple(rs);
+        updateTuple(rs);
+    }
+    
+    /**
+     *  Test that you can scroll forward and update indexed records
+     *  in the scrollable ResultSet (using FOR UPDATE).
+     */
+    public void
+        testIndexedScrollInsensitiveUpdateCursorWithForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery
+            ("select * from t1 where a=1 or a=2 for update");
+        
+        rs.next();
+        rs.next();
+        rs.previous();
+        verifyTuple(rs);
+        updateTuple(rs);
+        rs.close();
+        s.close();
+    }
+   
+    /**
+     * Test update of a keyed record using scrollable updatable
+     * resultset.
+     */
+    public void testPrimaryKeyUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.last();
+        rs.next();
+        while(rs.previous()) {
+            // Update the key of every second row.
+            int key = rs.getInt(1);
+            if (key%2==0) {
+                int newKey = -key;
+                rs.updateInt(1, newKey);
+                rs.updateRow();
+            }
+        }
+        PreparedStatement ps = con.prepareStatement
+            ("select * from t1 where id=?");
+        for (int i=0; i<recordCount; i++) {
+            int key = (i%2==0) ? -i : i;
+            ps.setInt(1, key);
+            ResultSet rs2 = ps.executeQuery();
+            assertTrue("Expected query to have 1 row", rs2.next());
+            println("T1: Read Tuple:(" + rs2.getInt(1) + "," +
+                    rs2.getInt(2) + "," +
+                    rs2.getInt(3) + ")");
+            assertEquals("Unexpected value of id", key, rs2.getInt(1));
+            assertTrue("Did not expect more than 1 row, " +
+                       "however rs2.next returned another row",
+                       !rs2.next());
+        }
+    }
+        
+    /**
+     * Test update of a keyed record using other statement
+     * object.
+     */
+    public void testOtherPrimaryKeyUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.last();
+        int primaryKey = rs.getInt(1);
+        PreparedStatement ps = con.prepareStatement
+            ("update t1 set id = ? where id= ?");
+        ps.setInt(1, -primaryKey);
+        ps.setInt(2, primaryKey);
+        assertEquals("Expected one row to be updated", 1,
+                     ps.executeUpdate());
+        
+        rs.updateInt(2, -555);
+        rs.updateInt(3, -777);
+        rs.updateRow();
+        
+        PreparedStatement ps2 = con.prepareStatement
+            ("select * from t1 where id=?");
+        ps2.setInt(1, -primaryKey);
+        ResultSet rs2 = ps2.executeQuery();
+        assertTrue("Expected query to have 1 row", rs2.next());
+        println("T1: Read Tuple:(" + rs2.getInt(1) + "," +
+                rs2.getInt(2) + "," +
+                rs2.getInt(3) + ")");
+        assertEquals("Expected a=-555", -555, rs2.getInt(2));
+        assertEquals("Expected b=-777", -777, rs2.getInt(3));
+        assertTrue("Did not expect more than 1 row, however " +
+                   "rs2.next() returned another row", !rs2.next());
+    }
+    
+    /**
+     * Test update of a keyed record using other both the
+     * scrollable updatable resultset and using another statement
+     * object.
+     */
+    public void testOtherAndOwnPrimaryKeyUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.last();
+        int primaryKey = rs.getInt(1);
+        PreparedStatement ps = con.prepareStatement
+            ("update t1 set id = ? where id= ?");
+        ps.setInt(1, -primaryKey);
+        ps.setInt(2, primaryKey);
+        assertEquals("Expected one row to be updated", 1,
+                     ps.executeUpdate());
+        rs.updateInt(1, primaryKey*10);
+        rs.updateInt(2, -555);
+        rs.updateInt(3, -777);
+        rs.updateRow();
+        
+        PreparedStatement ps2 =
+            con.prepareStatement("select * from t1 where id=?");
+        ps2.setInt(1, primaryKey*10);
+        ResultSet rs2 = ps2.executeQuery();
+        assertTrue("Expected query to have 1 row", rs2.next());
+        println("T1: Read Tuple:(" + rs2.getInt(1) + "," +
+                rs2.getInt(2) + "," +
+                rs2.getInt(3) + ")");
+        assertEquals("Expected a=-555", -555, rs2.getInt(2));
+        assertEquals("Expected b=-777", -777, rs2.getInt(3));
+        assertTrue("Did not expect more than 1 row, however " +
+                   "rs2.next() returned another row", !rs2.next());
+    }
+    
+    /**
+     * Update multiple keyed records using scrollable updatable resultset
+     */
+    public void testMultipleKeyUpdates()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.last();
+        int primaryKey = rs.getInt(1);
+        PreparedStatement ps = con.prepareStatement
+            ("update t1 set id = ? where id= ?");
+        ps.setInt(1, -primaryKey);
+        ps.setInt(2, primaryKey);
+        assertEquals("Expected one row to be updated", 1,
+                     ps.executeUpdate());
+        rs.updateInt(1, primaryKey*10);
+        rs.updateInt(2, -555);
+        rs.updateInt(3, -777);
+        rs.updateRow();
+        rs.first();
+        rs.last();
+        for (int i=0; i<10; i++) {
+            rs.first();
+            rs.last();
+            rs.next();
+            rs.previous();
+            rs.updateInt(1, primaryKey*10 +i);
+            rs.updateInt(2, (-555 -i));
+            rs.updateInt(3, (-777 -i));
+            rs.updateRow();
+        }
+    }
+    
+    /**
+     * Test update indexed records using scrollable updatable resultset 
+     */
+    public void testSecondaryIndexKeyUpdate1()
+        throws SQLException 
+    {
+        
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.last();
+        rs.next();
+        int newKey = 0;
+        while(rs.previous()) {
+            // Update the secondary key of all rows
+            rs.updateInt(2, newKey--);
+            rs.updateRow();
+        }
+        PreparedStatement ps = con.prepareStatement
+            ("select * from t1 where a=?");
+        for (int i=0; i<recordCount; i++) {
+            int key = -i;
+            ps.setInt(1, key);
+            ResultSet rs2 = ps.executeQuery();
+            assertTrue("Expected query to have 1 row", rs2.next());
+            println("T1: Read Tuple:(" + rs2.getInt(1) + "," +
+                    rs2.getInt(2) + "," +
+                    rs2.getInt(3) + ")");
+            assertEquals("Unexpected value of id", key, rs2.getInt(2));
+            assertTrue("Did not expect more than 1 row, " +
+                       "however rs2.next returned another row",
+                       !rs2.next());
+        }
+    }
+    
+    /**
+     * Test update indexed records using other statement object
+     * and using resultset.
+     */
+    public void testOtherSecondaryKeyUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        rs.last();
+        int indexedKey = rs.getInt(2);
+        PreparedStatement ps =
+            con.prepareStatement("update t1 set a = ? where a= ?");
+        ps.setInt(1, -indexedKey);
+        ps.setInt(2, indexedKey);
+        assertEquals("Expected one row to be updated", 1,
+                     ps.executeUpdate());
+        
+        rs.updateInt(1, -555);
+        rs.updateInt(3, -777);
+        rs.updateRow();
+        
+        PreparedStatement ps2 =
+            con.prepareStatement("select * from t1 where a=?");
+        ps2.setInt(1, -indexedKey);
+        ResultSet rs2 = ps2.executeQuery();
+        assertTrue("Expected query to have 1 row", rs2.next());
+        println("T1: Read Tuple:(" + rs2.getInt(1) + "," +
+                rs2.getInt(2) + "," +
+                rs2.getInt(3) + ")");
+        assertEquals("Expected id=-555", -555, rs2.getInt(1));
+        assertEquals("Expected b=-777", -777, rs2.getInt(3));
+        assertTrue("Did not expect more than 1 row, however " +
+                   "rs2.next() returned another row", !rs2.next());
+    }
+    
+    /**
+     * Test scrolling in a read only resultset
+     */
+    public void testScrollInsensitiveReadOnly1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_READ_ONLY);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        scrollForward(rs);
+        scrollBackward(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test updating a forward only resultset (with FOR UPDATE)
+     */
+    public void testForwardOnlyConcurUpdatableWithForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 for update");
+        
+        scrollForwardAndUpdate(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test updating a forward only resultset (without FOR UPDATE)
+     */
+    public void testForwardOnlyConcurUpdatableWithoutForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        scrollForwardAndUpdate(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test updating a forward only resultset (without FOR UPDATE)
+     * and using positioned update
+     */
+    public void testPositionedUpdateWithoutForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName("MYCURSOR");
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        scrollForwardAndUpdatePositioned(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test updating a forward only resultset (with FOR UPDATE)
+     * and using positioned update
+     */
+    public void testPositionedUpdateWithForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement();
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 for update");
+        
+        scrollForwardAndUpdatePositioned(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test positioned update of a scrollable resultset (with FOR UPDATE) 
+     */
+    public void testScrollablePositionedUpdateWithForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement
+            (ResultSet.TYPE_SCROLL_INSENSITIVE,
+             ResultSet.CONCUR_READ_ONLY);
+        s.setCursorName("MYCURSOR");
+        ResultSet rs = s.executeQuery("select * from t1 for update");
+        
+        rs.next();
+        int pKey = rs.getInt(1);
+        rs.previous();
+        rs.next();
+        assertEquals("Expecting to be on the same row after previous() " + 
+                     "+ next() ", pKey, rs.getInt(1));
+        rs.next();
+        rs.previous();
+        assertEquals("Expecting to be on the same row after next() + " + 
+                     "previous()", pKey, rs.getInt(1));
+        final int previousA = rs.getInt(2);
+        final int previousB = rs.getInt(3);
+        println(rs.getCursorName());
+        PreparedStatement ps = con.prepareStatement
+            ("update T1 set a=?,b=? where current of " + rs.getCursorName());
+        ps.setInt(1, 666);
+        ps.setInt(2, 777);
+        ps.executeUpdate();
+        rs.next();
+        rs.previous();
+        assertEquals("Expected to be on the same row after next() + previous()",
+                     pKey, rs.getInt(1));
+        assertEquals("Expected row to be updated by own change, " + 
+                     " however did not get updated value for column a", 
+                     666, rs.getInt(2));
+        assertEquals("Expected row to be updated by own change, however did " +
+                     "not get updated value for column b", 777, rs.getInt(3));
+        rs.close();
+        s.setCursorName(getNextCursorName());
+        rs = s.executeQuery("select * from t1 order by b");
+        
+        while (rs.next()) {
+            if (rs.getInt(1)==pKey) {
+                assertEquals("Expected row with primary key = " + pKey + 
+                             " to be updated", 666, rs.getInt(2));
+                assertEquals("Expected row with primary key = " + pKey + 
+                             " to be updated", 777, rs.getInt(3));
+            } else {
+                println("Got tuple (" + rs.getInt(1) + "," + rs.getInt(2) + 
+                        "," + rs.getInt(3) + "," + rs.getString(4)+ ")");
+            }
+        }
+        
+    }
+    
+    /**
+     * Test update of a scrollable resultset (with FOR UPDATE)
+     * Only scrolling forward
+     */
+    public void testScrollInsensitiveConcurUpdatableWithForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 for update");
+        scrollForwardAndUpdate(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test update of a scrollable resultset (with FOR UPDATE) 
+     * Scrolling forward and backward.
+     */
+    public void testScrollInsensitiveConcurUpdatableWithForUpdate2()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
+                                          ResultSet.CONCUR_UPDATABLE);
+        assertEquals("Invalid resultset concurrency on statement", 
+                     ResultSet.CONCUR_UPDATABLE, s.getResultSetConcurrency());
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1 for update");
+        
+        assertEquals("Invalid resultset concurrency on resultset", 
+                     ResultSet.CONCUR_UPDATABLE, rs.getConcurrency());
+        scrollForward(rs);
+        scrollBackwardAndUpdate(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test update of a scrollable resultset
+     * Scrolling forward and backward. Then open another
+     * resultset and verify the data.
+     */
+    private void testScrollInsensistiveConurUpdatable3(ResultSet rs) 
+        throws SQLException 
+    {
+        while (rs.next()) {
+        }
+        while (rs.previous()) {
+            int a = rs.getInt(1);
+            int b = rs.getInt(2);
+            int id = b - 17 - a;
+            int newA = 1000;
+            int newB = id + newA + 17;
+            rs.updateInt(1, newA); // Set a to 1000
+            rs.updateInt(2, newB); // Set b to checksum value
+            rs.updateRow();
+            
+            assertEquals("Expected a to be 1000", 1000, rs.getInt(1));
+        }
+        int count = 0;
+        while (rs.next()) {
+            int a = rs.getInt(1);
+            count++;
+            assertEquals("Incorrect row updated for row " + count, 1000, a);
+        }
+        assertEquals("Expected count to be the same as number of records", 
+                     recordCount, count);
+        while (rs.previous()) {
+            int a = rs.getInt(1);
+            count--;
+            assertEquals("Incorrect row updated for row " + count, 1000, a);
+        }
+        rs.close();
+        Statement s = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, 
+                                          ResultSet.CONCUR_READ_ONLY);
+        s.setCursorName(getNextCursorName());
+        rs = s.executeQuery("select * from t1");
+        
+        while (rs.next()) {
+            int id = rs.getInt(1);
+            int a = rs.getInt(2);
+            int b = rs.getInt(3);
+            println("Updated tuple:" + id + "," + a + "," + b);
+        }
+    }
+    
+    /**
+     * Test update of a scrollable resultset (with FOR UPDATE)
+     * Scrolling forward and backward. Then open another
+     * resultset and verify the data.
+     */
+    public void testScrollInsensitiveConcurUpdatableWithForUpdate3()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select a,b from t1 for update");
+        
+        testScrollInsensistiveConurUpdatable3(rs);
+    }
+    
+    /**
+     * Test update of a scrollable resultset (without FOR UPDATE) 
+     * Scrolling forward only
+     */
+    public void testScrollInsensitiveConcurUpdatableWithoutForUpdate1()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        scrollForwardAndUpdate(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test update of a scrollable resultset (without FOR UPDATE) 
+     * Scrolling forward and backward.
+     */
+    public void testScrollInsensitiveConcurUpdatableWithoutForUpdate2()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select * from t1");
+        
+        scrollForward(rs);
+        scrollBackwardAndUpdate(rs);
+        rs.close();
+    }
+    
+    /**
+     * Test update of a scrollable resultset (without FOR UPDATE)
+     * Scrolling forward and backward. Then open another
+     * resultset and verify the data.
+     */
+    public void testScrollInsensitiveConcurUpdatableWithoutForUpdate3()
+        throws SQLException 
+    {
+        Statement s = con.createStatement(ResultSet.TYPE_SCROLL_INSENSITIVE, 
+                                          ResultSet.CONCUR_UPDATABLE);
+        s.setCursorName(getNextCursorName());
+        ResultSet rs = s.executeQuery("select a,b from t1");
+        
+        testScrollInsensistiveConurUpdatable3(rs);
+    }
+    
+    /**
+     * Get a new cursor name. WORKAROUND FOR DERBY-787, since
+     * the cursors have side-effects..!
+     * To reproduce DERBY-787, just return the same cursor name.
+     */
+    private final String getNextCursorName() {
+        return "MYCURSOR" + cursorIndex++;
+    }
+    
+    private static int cursorIndex = 0;
+
+    
+    /**
+     * The suite contains all testcases in this class running on different 
+     * data models
+     */
+    public static Test suite() {
+        
+        TestSuite mainSuite = new TestSuite();
+        
+        // Iterate over all data models and decorate the tests:
+        for (Iterator i = SURDataModelSetup.SURDataModel.values().iterator();
+             i.hasNext();) {
+            
+            SURDataModelSetup.SURDataModel model = 
+                (SURDataModelSetup.SURDataModel) i.next();
+            
+            TestSuite suite = new TestSuite(SURTest.class);
+            TestSetup decorator = new SURDataModelSetup
+                (suite, model);
+            
+            mainSuite.addTest(decorator);    
+        }
+        
+        return mainSuite;
+    }
+}

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest.java
------------------------------------------------------------------------------
    svn:eol-style = native

Added: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest_app.properties
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest_app.properties?rev=378045&view=auto
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest_app.properties (added)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest_app.properties Wed Feb 15 10:18:47 2006
@@ -0,0 +1,3 @@
+runwithibm13=false
+runwithjdk13=false
+runwithjdk12=false

Propchange: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/tests/jdbcapi/SURTest_app.properties
------------------------------------------------------------------------------
    svn:eol-style = native

Modified: db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/TestUtil.java
URL: http://svn.apache.org/viewcvs/db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/TestUtil.java?rev=378045&r1=378044&r2=378045&view=diff
==============================================================================
--- db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/TestUtil.java (original)
+++ db/derby/code/trunk/java/testing/org/apache/derbyTesting/functionTests/util/TestUtil.java Wed Feb 15 10:18:47 2006
@@ -30,7 +30,10 @@
 import java.util.Properties;
 import java.util.StringTokenizer;
 import java.util.NoSuchElementException;
-
+import java.security.AccessController;
+import java.security.PrivilegedAction;
+import java.security.PrivilegedExceptionAction;
+import java.security.PrivilegedActionException;
 import javax.sql.DataSource;
 
 import org.apache.derby.iapi.reference.JDBC30Translation;
@@ -165,7 +168,13 @@
 	{
 		if (framework != UNKNOWN_FRAMEWORK)
 			return framework;
-		String frameworkString = System.getProperty("framework");
+              String frameworkString = (String) AccessController.doPrivileged
+                  (new PrivilegedAction() {
+                          public Object run() {
+                              return System.getProperty("framework");
+                          }
+                      }
+                   );              
 		if (frameworkString == null || 
 		   frameworkString.toUpperCase(Locale.ENGLISH).equals("EMBEDDED"))
 			framework = EMBEDDED_FRAMEWORK;
@@ -199,7 +208,13 @@
     */
     public static String getHostName()
     {
-        String hostName = (System.getProperty("hostName"));
+        String hostName = (String) AccessController.doPrivileged
+            (new PrivilegedAction() {
+                    public Object run() {
+                        return System.getProperty("hostName");
+                    }
+                }
+             );    
         if (hostName == null)
             hostName="localhost";
         return hostName;
@@ -243,7 +258,7 @@
 	*/
 	public static void loadDriver() throws Exception
 	{
-		String driverName = null;
+              final String driverName;
 		framework = getFramework();
 		switch (framework)
 		{
@@ -258,9 +273,23 @@
 			case DERBY_NET_CLIENT_FRAMEWORK:
 				driverName = "org.apache.derby.jdbc.ClientDriver";
 				break;
+                      default: 
+                            driverName=  "org.apache.derby.jdbc.EmbeddedDriver";
+                            break;
 		}
-		Class.forName(driverName).newInstance();
-	}
+                                
+              try {
+                  AccessController.doPrivileged
+                      (new PrivilegedExceptionAction() {
+                              public Object run() throws Exception {
+                                  return Class.forName(driverName).newInstance();
+                              }
+                          }
+                       );
+              } catch (PrivilegedActionException e) {
+                  throw e.getException();
+              }
+        }
 
 
 	/**