// jTDS JDBC Driver for Microsoft SQL Server and Sybase // Copyright (C) 2004 The jTDS Project // // This library is free software; you can redistribute it and/or // modify it under the terms of the GNU Lesser General Public // License as published by the Free Software Foundation; either // version 2.1 of the License, or (at your option) any later version. // // This library is distributed in the hope that it will be useful, // but WITHOUT ANY WARRANTY; without even the implied warranty of // MERCHANTABILITY or FITNESS FOR A PARTICULAR PURPOSE. See the GNU // Lesser General Public License for more details. // // You should have received a copy of the GNU Lesser General Public // License along with this library; if not, write to the Free Software // Foundation, Inc., 59 Temple Place, Suite 330, Boston, MA 02111-1307 USA // package net.sourceforge.jtds.jdbc; import java.sql.Connection; import java.sql.ResultSet; import java.sql.SQLException; import java.sql.Statement; /** * Test case to illustrate use of Cached cursor result set. * * @version 1.0 * @author Mike Hutchinson */ public class ClientSideCursorTest extends DatabaseTestCase { public ClientSideCursorTest(String name) { super(name); } /** * General test of scrollable cursor functionality. * <p/> * When running on SQL Server this test will exercise MSCursorResultSet. * When running on Sybase this test will exercise CachedResultSet. */ public void testCachedCursor() throws Exception { try { dropTable("jTDS_CachedCursorTest"); Statement stmt = con.createStatement(); stmt.execute("CREATE TABLE jTDS_CachedCursorTest " + "(key1 int NOT NULL, key2 char(4) NOT NULL," + "data varchar(255))\r\n" + "ALTER TABLE jTDS_CachedCursorTest " + "ADD CONSTRAINT PK_jTDS_CachedCursorTest PRIMARY KEY CLUSTERED" + "( key1, key2)"); for (int i = 1; i <= 16; i++) { assertEquals(1, stmt.executeUpdate("INSERT INTO jTDS_CachedCursorTest VALUES(" + i + ", 'XXXX','LINE " + i + "')")); } stmt.close(); stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs = stmt.executeQuery("SELECT * FROM jTDS_CachedCursorTest ORDER BY key1"); assertNotNull(rs); assertEquals(null, stmt.getWarnings()); assertTrue(rs.isBeforeFirst()); assertTrue(rs.first()); assertEquals(1, rs.getInt(1)); assertTrue(rs.isFirst()); assertTrue(rs.last()); assertEquals(16, rs.getInt(1)); assertTrue(rs.isLast()); assertFalse(rs.next()); assertTrue(rs.isAfterLast()); rs.beforeFirst(); assertTrue(rs.next()); assertEquals(1, rs.getInt(1)); rs.afterLast(); assertTrue(rs.previous()); assertEquals(16, rs.getInt(1)); assertTrue(rs.absolute(8)); assertEquals(8, rs.getInt(1)); assertTrue(rs.relative(-1)); assertEquals(7, rs.getInt(1)); rs.updateString(3, "New line 7"); rs.updateRow(); // assertTrue(rs.rowUpdated()); // MS API cursors appear not to support this rs.moveToInsertRow(); rs.updateInt(1, 17); rs.updateString(2, "XXXX"); rs.updateString(3, "LINE 17"); rs.insertRow(); rs.moveToCurrentRow(); rs.last(); // assertTrue(rs.rowInserted()); // MS API cursors appear not to support this Statement stmt2 = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_READ_ONLY); ResultSet rs2 = stmt2.executeQuery("SELECT * FROM jTDS_CachedCursorTest ORDER BY key1"); rs.updateString(3, "NEW LINE 17"); rs.updateRow(); assertTrue(rs2.last()); assertEquals(17, rs2.getInt(1)); assertEquals("NEW LINE 17", rs2.getString(3)); rs.deleteRow(); rs2.refreshRow(); assertTrue(rs2.rowDeleted()); rs2.close(); stmt2.close(); rs.close(); stmt.close(); } finally { dropTable("jTDS_CachedCursorTest"); } } /** * Test support for JDBC 1 style positioned updates with named cursors. * <p/> * When running on SQL Server this test will exercise MSCursorResultSet. * When running on Sybase this test will exercise CachedResultSet. */ public void testPositionedUpdate() throws Exception { assertTrue(con.getMetaData().supportsPositionedDelete()); assertTrue(con.getMetaData().supportsPositionedUpdate()); Statement stmt = con.createStatement(); stmt.execute("CREATE TABLE #TESTPOS (id INT primary key, data VARCHAR(255))"); for (int i = 1; i < 5; i++) { stmt.execute("INSERT INTO #TESTPOS VALUES(" + i + ", 'This is line " + i + "')"); } stmt.setCursorName("curname"); ResultSet rs = stmt.executeQuery("SELECT * FROM #TESTPOS FOR UPDATE"); Statement stmt2 = con.createStatement(); while (rs.next()) { if (rs.getInt(1) == 1) { stmt2.execute("UPDATE #TESTPOS SET data = 'Updated' WHERE CURRENT OF curname"); } else if (rs.getInt(1) == 3) { stmt2.execute("DELETE FROM #TESTPOS WHERE CURRENT OF curname"); } } rs.close(); stmt.setFetchSize(100); rs = stmt.executeQuery("SELECT * FROM #TESTPOS"); while (rs.next()) { int id = rs.getInt(1); assertTrue(id != 3); // Should have been deleted if (id == 1) { assertEquals("Updated", rs.getString(2)); } } stmt2.close(); stmt.close(); } /** * Test optimistic updates throw exception if row is changed on disk. * <p/> * When running on SQL Server this test will exercise MSCursorResultSet. * When running on Sybase this test will exercise CachedResultSet. */ public void testOptimisticUpdates() throws Exception { Connection con2 = getConnection(); try { dropTable("jTDS_CachedCursorTest"); Statement stmt = con.createStatement(ResultSet.TYPE_SCROLL_SENSITIVE, ResultSet.CONCUR_UPDATABLE); ResultSet rs; stmt.execute("CREATE TABLE jTDS_CachedCursorTest (id int primary key, data varchar(255))"); for (int i = 0; i < 4; i++) { stmt.executeUpdate("INSERT INTO jTDS_CachedCursorTest VALUES("+i+", 'Table A line "+i+"')"); } // Open cursor rs = stmt.executeQuery("SELECT id, data FROM jTDS_CachedCursorTest"); Statement stmt2 = con2.createStatement(); while (rs.next()) { if (rs.getInt(1) == 1) { assertEquals(1, stmt2.executeUpdate("UPDATE jTDS_CachedCursorTest SET data = 'NEW VALUE' WHERE id = 1")); rs.updateString(2, "TEST UPDATE"); try { rs.updateRow(); assertNotNull(rs.getWarnings()); assertEquals("Expected optimistic update exception", "24000", rs.getWarnings().getSQLState()); } catch (SQLException e) { // Expected exception as row has been modified on disk assertEquals("24000", e.getSQLState()); } } } rs.close(); stmt.close(); } finally { if (con2 != null) { con2.close(); } dropTable("jTDS_CachedCursorTest"); } } /** * Test updateable result set where table is not keyed. * Uses a server side cursor and positioned updates on Sybase. */ public void testUpdateNoKeys() throws Exception { Statement stmt = con.createStatement(ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE); stmt.execute("CREATE TABLE ##TESTNOKEY (id int, data varchar(255))"); for (int i = 0; i < 4; i++) { stmt.executeUpdate("INSERT INTO ##TESTNOKEY VALUES("+i+", 'Test line "+i+"')"); } ResultSet rs = stmt.executeQuery("SELECT * FROM ##TESTNOKEY"); assertTrue(rs.next()); assertTrue(rs.next()); rs.updateString(2, "UPDATED"); rs.updateRow(); rs.close(); rs = stmt.executeQuery("SELECT * FROM ##TESTNOKEY"); while (rs.next()) { if (rs.getInt(1) == 1) { assertEquals("UPDATED", rs.getString(2)); } } stmt.close(); } public static void main(String[] args) { junit.textui.TestRunner.run(ClientSideCursorTest.class); } }