// 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);
}
}