blob: 3d57560ca52a7a3312bd2cb2cd8c7966ddff58f2 [file] [log] [blame]
/*
*
* Derby - Class UpdatableResultSetTest
*
* Licensed to the Apache Software Foundation (ASF) under one or more
* contributor license agreements. See the NOTICE file distributed with
* this work for additional information regarding copyright ownership.
* The ASF licenses this file to You 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.io.InputStream;
import java.sql.Blob;
import java.sql.Clob;
import java.sql.Connection;
import java.sql.PreparedStatement;
import java.sql.ResultSet;
import java.sql.SQLException;
import java.sql.Statement;
import java.sql.Timestamp;
import java.util.Date;
import junit.framework.Test;
import org.apache.derbyTesting.junit.BaseJDBCTestCase;
import org.apache.derbyTesting.junit.TestConfiguration;
/**
* Tests updatable result sets.
*
* DERBY-1767 - Test that the deleteRow, insertRow and updateRow methods
* with column/table/schema/cursor names containing quotes.
*
*/
public class UpdatableResultSetTest extends BaseJDBCTestCase {
private static final byte[] BYTES1 = {
0x65, 0x66, 0x67, 0x68, 0x69,
0x69, 0x68, 0x67, 0x66, 0x65
};
private static final byte[] BYTES2 = {
0x69, 0x68, 0x67, 0x66, 0x65,
0x65, 0x66, 0x67, 0x68, 0x69
};
/**
* Key used to identify inserted rows.
* Use method <code>requestKey</code> to obtain it.
**/
private static int insertKey = 0;
private int key = -1;
/** Creates a new instance of UpdatableResultSetTest */
public UpdatableResultSetTest(String name) {
super(name);
}
/**
* Create require objects and data. No tearDown
* is needed because these are created in non-auto-commit
* mode and no commit is ever issued. Thus on the super's
* tearDown the rollback will revert everything.
*/
protected void setUp() throws SQLException {
Connection conn = getConnection();
conn.setAutoCommit(false);
Statement stmt = conn.createStatement();
stmt.execute("create table UpdateTestTableResultSet (" +
"sno int not null unique," +
"dBlob BLOB," +
"dClob CLOB," +
"dLongVarchar LONG VARCHAR," +
"dLongBit LONG VARCHAR FOR BIT DATA)");
// Quoted table
stmt.executeUpdate("create table \"my \"\"quoted\"\" table\" (x int)");
stmt.executeUpdate("insert into \"my \"\"quoted\"\" table\" (x) " +
"values (1), (2), (3)");
// Quoted columns
stmt.executeUpdate("create table \"my quoted columns\" " +
"(\"my \"\"quoted\"\" column\" int)");
stmt.executeUpdate("insert into \"my quoted columns\" " +
"values (1), (2), (3) ");
// Quoted schema
stmt.executeUpdate("create table \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\" (x int)");
stmt.executeUpdate("insert into \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\" values (1), (2), (3) ");
// No quotes, use with quoted cursor
stmt.executeUpdate("create table \"my table\" (x int)");
stmt.executeUpdate("insert into \"my table\" values (1), (2), (3) ");
stmt.close();
}
/** Create a test suite with all tests in this class. */
public static Test suite() {
return TestConfiguration.defaultSuite(UpdatableResultSetTest.class);
}
/**
* Tests insertRow with table name containing quotes
*/
public void testInsertRowOnQuotedTable() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" table\"");
rs.next();
rs.moveToInsertRow();
rs.updateInt(1, 4);
rs.insertRow();
rs.moveToCurrentRow();
rs.close();
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" table\" " +
"order by x");
for (int i=1; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests updateRow with table name containing quotes
*/
public void testUpdateRowOnQuotedTable() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" table\"");
rs.next();
rs.updateInt(1, 4);
rs.updateRow();
rs.close();
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" table\" " +
"order by x");
for (int i=2; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests deleteRow with table name containing quotes
*/
public void testDeleteRowOnQuotedTable() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" table\"");
rs.next();
rs.deleteRow();
rs.close();
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" table\" " +
"order by x");
for (int i=2; i<=3; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests insertRow with column name containing quotes
*/
public void testInsertRowOnQuotedColumn() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my quoted columns\"");
rs.next();
rs.moveToInsertRow();
rs.updateInt(1, 4);
rs.insertRow();
rs.moveToCurrentRow();
rs.close();
rs = stmt.executeQuery("select * from \"my quoted columns\" " +
"order by \"my \"\"quoted\"\" column\"");
for (int i=1; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests updateRow with column name containing quotes
*/
public void testUpdateRowOnQuotedColumn() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my quoted columns\"");
rs.next();
rs.updateInt(1, 4);
rs.updateRow();
rs.close();
rs = stmt.executeQuery("select * from \"my quoted columns\" " +
"order by \"my \"\"quoted\"\" column\"");
for (int i=2; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests deleteRow with column name containing quotes
*/
public void testDeleteRowOnQuotedColumn() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my quoted columns\"");
rs.next();
rs.deleteRow();
rs.close();
rs = stmt.executeQuery("select * from \"my quoted columns\" " +
"order by \"my \"\"quoted\"\" column\"");
for (int i=2; i<=3; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests insertRow with schema name containing quotes
*/
public void testInsertRowOnQuotedSchema() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\"");
rs.next();
rs.moveToInsertRow();
rs.updateInt(1, 4);
rs.insertRow();
rs.moveToCurrentRow();
rs.close();
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\" order by x");
for (int i=1; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests updateRow with schema name containing quotes
*/
public void testUpdateRowOnQuotedSchema() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\"");
rs.next();
rs.updateInt(1, 4);
rs.updateRow();
rs.close();
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\" order by x");
for (int i=2; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests deleteRow with schema name containing quotes
*/
public void testDeleteRowOnQuotedSchema() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\"");
rs.next();
rs.deleteRow();
rs.close();
rs = stmt.executeQuery("select * from \"my \"\"quoted\"\" schema\"." +
"\"my quoted schema\" order by x");
for (int i=2; i<=3; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests insertRow with cursor name containing quotes
*/
public void testInsertRowOnQuotedCursor() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
stmt.setCursorName("my \"\"\"\"quoted\"\"\"\" cursor\"\"");
rs = stmt.executeQuery("select * from \"my table\"");
rs.next();
rs.moveToInsertRow();
rs.updateInt(1, 4);
rs.insertRow();
rs.moveToCurrentRow();
rs.close();
rs = stmt.executeQuery("select * from \"my table\" order by x");
for (int i=1; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests updateRow with cursor name containing quotes
*/
public void testUpdateRowOnQuotedCursor() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
stmt.setCursorName("\"\"my quoted cursor");
rs = stmt.executeQuery("select * from \"my table\"");
rs.next();
rs.updateInt(1, 4);
rs.updateRow();
rs.close();
rs = stmt.executeQuery("select * from \"my table\" order by x");
for (int i=2; i<=4; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* Tests deleteRow with cursor name containing quotes
*/
public void testDeleteRowOnQuotedCursor() throws SQLException {
ResultSet rs = null;
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
stmt.setCursorName("\"\"my quoted cursor\"\"");
rs = stmt.executeQuery("select * from \"my table\"");
rs.next();
rs.deleteRow();
rs.close();
rs = stmt.executeQuery("select * from \"my table\" order by x");
for (int i=2; i<=3; i++) {
assertTrue("there is a row", rs.next());
assertEquals("row contains correct value", i, rs.getInt(1));
}
rs.close();
stmt.close();
}
/**
* This methods tests the ResultSet interface method
* updateBlob
*
* @throws Exception
*/
public void testUpdateBlob()
throws Exception {
//Byte array in which the returned bytes from
//the Database after the update are stored. This
//array is then checked to determine if it
//has the same elements of the Byte array used for
//the update operation
byte[] bytes_ret = new byte[10];
//1 Input Stream for insertion
InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
//2 Input Stream for insertion
InputStream is2 = new java.io.ByteArrayInputStream(BYTES2);
//Prepared Statement used to insert the data
PreparedStatement ps_sb = prep("dBlob");
//first insert
ps_sb.setInt(1, key);
ps_sb.setBinaryStream(2,is1,BYTES1.length);
ps_sb.executeUpdate();
//second insert
int key2 = requestKey();
ps_sb.setInt(1, key2);
ps_sb.setBinaryStream(2,is2,BYTES2.length);
ps_sb.executeUpdate();
ps_sb.close();
//Update operation
//use a different ResultSet variable so that the
//other tests can go on unimpacted
//we do not have set methods on Clob and Blob implemented
//So query the first Clob from the database
//update the second result set with this
//Clob value
ResultSet rs1 = fetch("dBlob", key);
rs1.next();
Blob blob = rs1.getBlob(1);
rs1.close();
rs1 = fetchUpd("dBlob", key2);
rs1.next();
rs1.updateBlob(1,blob);
rs1.updateRow();
rs1.close();
//Query to see whether the data that has been updated
//using the updateBlob method is the same
//data that we expected
rs1 = fetch("dBlob", key2);
rs1.next();
assertEquals(blob, rs1.getBlob(1));
rs1.close();
}
/**
* This methods tests the ResultSet interface method
* updateBlob
*
* @throws Exception
*/
public void testUpdateBlobStringParameterName()
throws Exception {
//Byte array in which the returned bytes from
//the Database after the update are stored. This
//array is then checked to determine if it
//has the same elements of the Byte array used for
//the update operation
byte[] bytes_ret = new byte[10];
//1 Input Stream for insertion
InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
//2 Input Stream for insertion
InputStream is2 = new java.io.ByteArrayInputStream(BYTES2);
//Prepared Statement used to insert the data
PreparedStatement ps_sb = prep("dBlob");
//first insert
ps_sb.setInt(1, key);
ps_sb.setBinaryStream(2,is1,BYTES1.length);
ps_sb.executeUpdate();
//second insert
int key2 = requestKey();
ps_sb.setInt(1, key2);
ps_sb.setBinaryStream(2,is2,BYTES2.length);
ps_sb.executeUpdate();
ps_sb.close();
//Update operation
//use a different ResultSet variable so that the
//other tests can go on unimpacted
//we do not have set methods on Clob and Blob implemented
//So query the first Clob from the database
//update the second result set with this
//Clob value
ResultSet rs1 = fetch("dBlob", key);
rs1.next();
Blob blob = rs1.getBlob(1);
rs1.close();
rs1 = fetchUpd("dBlob", key2);
rs1.next();
rs1.updateBlob("dBlob",blob);
rs1.updateRow();
rs1.close();
//Query to see whether the data that has been updated
//using the updateBlob method is the same
//data that we expected
rs1 = fetch("dBlob", key2);
rs1.next();
assertEquals(blob, rs1.getBlob(1));
rs1.close();
}
/**
* This methods tests the ResultSet interface method
* updateClob
*
* @throws Exception
*/
public void testUpdateClob()
throws Exception {
//Byte array in which the returned bytes from
//the Database after the update are stored. This
//array is then checked to determine if it
//has the same elements of the Byte array used for
//the update operation
byte[] bytes_ret = new byte[10];
//1 Input Stream for insertion
InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
//2 Input Stream for insertion
InputStream is2 = new java.io.ByteArrayInputStream(BYTES2);
//Prepared Statement used to insert the data
PreparedStatement ps_sb = prep("dClob");
//first insert
ps_sb.setInt(1,key);
ps_sb.setAsciiStream(2,is1,BYTES1.length);
ps_sb.executeUpdate();
//second insert
int key2 = requestKey();
ps_sb.setInt(1,key2);
ps_sb.setAsciiStream(2,is2,BYTES2.length);
ps_sb.executeUpdate();
ps_sb.close();
//Update operation
//use a different ResultSet variable so that the
//other tests can go on unimpacted
//we do not have set methods on Clob and Blob implemented
//So query the first Clob from the database
//update the second result set with this
//Clob value
ResultSet rs1 = fetchUpd("dClob", key);
rs1.next();
Clob clob = rs1.getClob(1);
rs1.close();
rs1 = fetchUpd("dClob", key2);
rs1.next();
rs1.updateClob(1,clob);
rs1.updateRow();
rs1.close();
//Query to see whether the data that has been updated
//using the updateClob method is the same
//data that we expected
rs1 = fetch("dClob", key2);
rs1.next();
assertEquals(clob, rs1.getClob(1));
rs1.close();
}
/**
* This methods tests the ResultSet interface method
* updateClob
*
* @throws Exception
*/
public void testUpdateClobStringParameterName()
throws Exception {
//Byte array in which the returned bytes from
//the Database after the update are stored. This
//array is then checked to determine if it
//has the same elements of the Byte array used for
//the update operation
byte[] bytes_ret = new byte[10];
//1 Input Stream for insertion
InputStream is1 = new java.io.ByteArrayInputStream(BYTES1);
//2 Input Stream for insertion
InputStream is2 = new java.io.ByteArrayInputStream(BYTES2);
//Prepared Statement used to insert the data
PreparedStatement ps_sb = prep("dClob");
//first insert
ps_sb.setInt(1, key);
ps_sb.setAsciiStream(2,is1,BYTES1.length);
ps_sb.executeUpdate();
//second insert
int key2 = requestKey();
ps_sb.setInt(1, key2);
ps_sb.setAsciiStream(2,is2,BYTES2.length);
ps_sb.executeUpdate();
ps_sb.close();
//Update operation
//use a different ResultSet variable so that the
//other tests can go on unimpacted
//we do not have set methods on Clob and Blob implemented
//So query the first Clob from the database
//update the second result set with this
//Clob value
ResultSet rs1 = fetch("dClob", key);
rs1.next();
Clob clob = rs1.getClob(1);
rs1.close();
rs1 = fetchUpd("dClob", key2);
rs1.next();
rs1.updateClob("dClob",clob);
rs1.updateRow();
rs1.close();
//Query to see whether the data that has been updated
//using the updateClob method is the same
//data that we expected
rs1 = fetch("dClob", key2);
rs1.next();
assertEquals(clob, rs1.getClob(1));
rs1.close();
}
/**
* Get a key that is used to identify an inserted row.
* Introduced to avoid having to delete table contents after each test,
* and because the order of the tests is not guaranteed.
*
* @return an integer in range [1, Integer.MAX_VALUE -1]
*/
private static final int requestKey() {
return ++insertKey;
}
/**
* Prepare commonly used statement to insert a row.
*
* @param colName name of the column to insert into
* @throws SQLException
*/
private PreparedStatement prep(String colName)
throws SQLException {
return prepareStatement("insert into UpdateTestTableResultSet " +
"(sno, " + colName + ") values (?,?)");
}
/**
* Fetch the specified row for update.
*
* @param colName name of the column to fetch
* @param key identifier for row to fetch
* @return a <code>ResultSet</code> with zero or one row, depending on
* the key used
* @throws SQLException
*/
private ResultSet fetchUpd(String colName, int key)
throws SQLException {
Statement stmt = createStatement(ResultSet.TYPE_FORWARD_ONLY,
ResultSet.CONCUR_UPDATABLE);
return stmt.executeQuery("select " + colName +
" from UpdateTestTableResultSet where sno = " + key +
" for update");
}
/**
* Fetch the specified row.
*
* @param colName name of the column to fetch
* @param key identifier for row to fetch
* @return a <code>ResultSet</code> with zero or one row, depending on
* the key used
* @throws SQLException
*/
private ResultSet fetch(String colName, int key)
throws SQLException {
Statement stmt = createStatement();
return stmt.executeQuery("select " + colName +
" from UpdateTestTableResultSet where sno = " + key);
}
public void testDerby6981()
throws SQLException
{
Statement stmt = createStatement();
stmt.executeUpdate("CREATE TABLE TEST1 " +
"(ID int PRIMARY KEY NOT NULL,LASTUPDATE timestamp)");
PreparedStatement ps = prepareStatement(
"SELECT id, LASTUPDATE FROM test1 WHERE id = ? " +
"FOR UPDATE OF id, LASTUPDATE ",
ResultSet.TYPE_FORWARD_ONLY, ResultSet.CONCUR_UPDATABLE);
long newDate = new Date().getTime();
for (int i = 0; i < 3; i++)
{
ps.setInt(1, 3);
ResultSet rs = ps.executeQuery();
if (!rs.next())
{
rs.moveToInsertRow();
rs.updateInt(1, 3);
rs.updateTimestamp(2, new Timestamp(newDate));
rs.insertRow();
}
else
{
rs.updateInt(1, 3);
rs.updateTimestamp(2, new Timestamp(newDate));
rs.updateRow();
}
rs.close();
}
stmt.close();
ps.close();
}
}