001: /*
002: *
003: * Derby - Class SURBaseTest
004: *
005: * Licensed to the Apache Software Foundation (ASF) under one or more
006: * contributor license agreements. See the NOTICE file distributed with
007: * this work for additional information regarding copyright ownership.
008: * The ASF licenses this file to You under the Apache License, Version 2.0
009: * (the "License"); you may not use this file except in compliance with
010: * the License. You may obtain a copy of the License at
011: *
012: * http://www.apache.org/licenses/LICENSE-2.0
013: *
014: * Unless required by applicable law or agreed to in writing,
015: * software distributed under the License is distributed on an
016: * "AS IS" BASIS, WITHOUT WARRANTIES OR CONDITIONS OF ANY KIND,
017: * either express or implied. See the License for the specific
018: * language governing permissions and limitations under the License.
019: */
020: package org.apache.derbyTesting.functionTests.tests.jdbcapi;
021:
022: import org.apache.derbyTesting.junit.BaseJDBCTestCase;
023: import org.apache.derbyTesting.junit.JDBC;
024:
025: import junit.framework.*;
026: import java.sql.*;
027:
028: /**
029: * Base class for testing Scrollable Updatable ResultSets.
030: * The setUp() provides a Connection to the database.
031: *
032: * Tests of this class needs to be decorated by a DBSetup
033: * and SURDataModelSetup.
034: *
035: * @author Andreas Korneliussen
036: */
037: abstract public class SURBaseTest extends BaseJDBCTestCase {
038:
039: /** Creates a new instance of SURBaseTest */
040: public SURBaseTest(String name) {
041: super (name);
042: recordCount = SURDataModelSetup.recordCount;
043: }
044:
045: /** Creates a new instance of SURBaseTest*/
046: public SURBaseTest(String name, int records) {
047: super (name);
048: recordCount = records;
049: }
050:
051: /**
052: * Override a connection's default state to ensure it
053: * is always in autocommit false and repeatable
054: * read as a starting point.
055: */
056: protected void initializeConnection(Connection conn)
057: throws SQLException {
058: conn.setAutoCommit(false);
059: conn
060: .setTransactionIsolation(Connection.TRANSACTION_REPEATABLE_READ);
061: }
062:
063: /**
064: * Set up the connection to the database.
065: */
066: public void setUp() throws Exception {
067: println("SetUp");
068: // temp save the connection in this class as con
069: // as well as the default connection in the parent
070: con = getConnection();
071: }
072:
073: /**
074: * Verify the data of a tuple in the ResultSet, based on the data
075: * that were inserted.
076: */
077: protected void verifyTuple(ResultSet rs) throws SQLException {
078: int id = rs.getInt(1);
079: int a = rs.getInt(2);
080: int b = rs.getInt(3);
081: int sum = a + id + 17;
082: println("Reading tuple:(" + id + "," + a + "," + b + ",'"
083: + rs.getString(4) + "')");
084: assertEquals("Expecting b==id+a+17, got: id=" + id + ",a=" + a
085: + ",b=" + b + ",c=" + rs.getString(4), b, sum);
086: }
087:
088: /**
089: * Update the current tuple in the ResultSet using updateXXX() and
090: * updateRow()
091: */
092: protected void updateTuple(ResultSet rs) throws SQLException {
093: assertFalse("Cannot use updateRow() in autocommit mode", rs
094: .getStatement().getConnection().getAutoCommit());
095: int id = rs.getInt(1);
096: int a = rs.getInt(2);
097: int b = rs.getInt(3);
098: int newA = a * 2 + id + 37;
099: int newB = newA + id + 17;
100: println("Updating record (" + id + "," + newA + "," + newB
101: + ")");
102: rs.updateInt(2, newA);
103: rs.updateInt(3, newB);
104: rs.updateRow();
105: }
106:
107: /**
108: * Update the current tuple in the ResultSet using positioned update
109: */
110: protected void updateTuplePositioned(ResultSet rs)
111: throws SQLException {
112: int id = rs.getInt(1);
113: int a = rs.getInt(2);
114: int b = rs.getInt(3);
115: int newA = a * 2 + id + 37;
116: int newB = newA + id + 17;
117: PreparedStatement ps = prepareStatement("update T1 set a=?,b=? where current of "
118: + rs.getCursorName());
119: ps.setInt(1, newA);
120: ps.setInt(2, newB);
121: assertEquals("Expected one tuple to be updated", 1, ps
122: .executeUpdate());
123: }
124:
125: /**
126: * Scroll forward to the end of the ResultSet, and verify tuples while
127: * scrolling.
128: */
129: protected void scrollForward(ResultSet rs) throws SQLException {
130: boolean ignoreCount = rs.getType() == ResultSet.TYPE_FORWARD_ONLY
131: || !rs.isBeforeFirst();
132: int nRecords = 0;
133: while (rs.next()) {
134: nRecords++;
135: verifyTuple(rs);
136: }
137: if (!ignoreCount) {
138: assertEquals("Expected " + recordCount + " records",
139: nRecords, recordCount);
140: }
141: }
142:
143: /**
144: * Scroll backward to the beginning of the ResultSet, and verify tuples
145: * while scrolling.
146: */
147: protected void scrollBackward(ResultSet rs) throws SQLException {
148: boolean ignoreCount = rs.getType() == ResultSet.TYPE_FORWARD_ONLY
149: || !rs.isAfterLast();
150:
151: int nRecords = 0;
152: while (rs.previous()) {
153: nRecords++;
154: verifyTuple(rs);
155: }
156: if (!ignoreCount) {
157: assertEquals("Expected " + recordCount + " records",
158: nRecords, recordCount);
159: }
160: }
161:
162: /**
163: * Scroll forward and update the tuples using updateXXX() and updateRow()
164: */
165: protected void scrollForwardAndUpdate(ResultSet rs)
166: throws SQLException {
167: int nRecords = 0;
168: boolean ignoreCount = rs.getType() == ResultSet.TYPE_FORWARD_ONLY
169: || !rs.isBeforeFirst();
170:
171: while (rs.next()) {
172: nRecords++;
173: verifyTuple(rs);
174: updateTuple(rs);
175: }
176: if (!ignoreCount) {
177: assertEquals("Expected " + recordCount + " records",
178: nRecords, recordCount);
179: }
180: assertNotNull("rs.getCursorName()", rs.getCursorName());
181: }
182:
183: /**
184: * Scroll forward and do positioned updates.
185: */
186: protected void scrollForwardAndUpdatePositioned(ResultSet rs)
187: throws SQLException {
188: int nRecords = 0;
189: boolean ignoreCount = rs.getType() == ResultSet.TYPE_FORWARD_ONLY
190: || !rs.isBeforeFirst();
191: while (rs.next()) {
192: nRecords++;
193: verifyTuple(rs);
194: updateTuplePositioned(rs);
195: }
196: if (!ignoreCount) {
197: assertEquals("Expected " + recordCount + " records",
198: nRecords, recordCount);
199: }
200: assertNotNull("rs.getCursorName()", rs.getCursorName());
201: }
202:
203: /**
204: * Scroll backward and update the records using updateXXX() and updateRow()
205: */
206: protected void scrollBackwardAndUpdate(ResultSet rs)
207: throws SQLException {
208: int nRecords = 0;
209: boolean ignoreCount = rs.getType() == ResultSet.TYPE_FORWARD_ONLY
210: || !rs.isAfterLast();
211: while (rs.previous()) {
212: nRecords++;
213: verifyTuple(rs);
214: updateTuple(rs);
215: }
216: if (!ignoreCount) {
217: assertEquals("Expected " + recordCount + " records",
218: nRecords, recordCount);
219: }
220: assertNotNull("rs.getCursorName()", rs.getCursorName());
221: }
222:
223: /**
224: * Scroll backward and update the records using positioned updates.
225: */
226: protected void scrollBackwardAndUpdatePositioned(ResultSet rs)
227: throws SQLException {
228: int nRecords = 0;
229: boolean ignoreCount = rs.getType() == ResultSet.TYPE_FORWARD_ONLY
230: || !rs.isAfterLast();
231: while (rs.previous()) {
232: nRecords++;
233: verifyTuple(rs);
234: updateTuplePositioned(rs);
235: }
236: if (!ignoreCount) {
237: assertEquals("Expected " + recordCount + " records",
238: nRecords, recordCount);
239: }
240: assertNotNull("rs.getCursorName()", rs.getCursorName());
241: }
242:
243: /**
244: * Assert that update of ResultSet fails with a SQLException
245: * due to read-only ResultSet.
246: */
247: protected void assertFailOnUpdate(ResultSet rs) throws SQLException {
248: boolean failedCorrect = false;
249: try {
250: updateTuple(rs);
251: } catch (SQLException e) {
252: failedCorrect = true;
253: assertEquals("Unexpected SQL state",
254: RESULTSET_NOT_UPDATABLE_SQL_STATE, e.getSQLState());
255:
256: }
257: assertTrue(
258: "Expected cursor to fail on update, since it is read only",
259: failedCorrect);
260: }
261:
262: /**
263: * Assert that a warning was received
264: */
265: protected void assertWarning(SQLWarning warn, String sqlState)
266: throws SQLException {
267: if (warn != null || usingEmbedded()) {
268: assertEquals("Unexpected SQL state", sqlState, warn
269: .getSQLState());
270: } else {
271: println("Expected warning with SQLState = '"
272: + sqlState
273: + "', however warning not propagated to client driver");
274: }
275: }
276:
277: protected Connection con = null; // Connection established in setUp()
278: final int recordCount;
279:
280: /**
281: * Error codes and SQL state
282: */
283: final static String FOR_UPDATE_NOT_PERMITTED_SQL_STATE = "42Y90";
284: final static String CURSOR_NOT_UPDATABLE_SQL_STATE = "42X23";
285: final static String RESULTSET_NOT_UPDATABLE_SQL_STATE = "XJ083";
286: final static String LOCK_TIMEOUT_SQL_STATE = "40XL1";
287: final static String LOCK_TIMEOUT_EXPRESSION_SQL_STATE = "38000";
288: final static String INVALID_CURSOR_STATE_NO_CURRENT_ROW = "24000";
289: final static String CURSOR_OPERATION_CONFLICT = "01001";
290: final static String QUERY_NOT_QUALIFIED_FOR_UPDATABLE_RESULTSET = "01J06";
291: final static String CURSOR_NOT_POSITIONED_ON_INSERT_ROW = "XJ086";
292: }
|