diff --git a/src/interfaces/jdbc/org/postgresql/PGRefCursorResultSet.java b/src/interfaces/jdbc/org/postgresql/PGRefCursorResultSet.java new file mode 100644 index 0000000000..2594c7e1d0 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/PGRefCursorResultSet.java @@ -0,0 +1,25 @@ +/*------------------------------------------------------------------------- + * + * PGRefCursorResultSet.java + * Describes a PLPGSQL refcursor type. + * + * Copyright (c) 2003, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/Attic/PGRefCursorResultSet.java,v 1.1 2003/05/03 20:40:45 barry Exp $ + * + *------------------------------------------------------------------------- + */ +package org.postgresql; + + +/** A ref cursor based result set. + */ +public interface PGRefCursorResultSet +{ + + /** return the name of the cursor. + */ + public String getRefCursor (); + +} diff --git a/src/interfaces/jdbc/org/postgresql/core/BaseStatement.java b/src/interfaces/jdbc/org/postgresql/core/BaseStatement.java index c7432d2016..dc5ffbdf78 100644 --- a/src/interfaces/jdbc/org/postgresql/core/BaseStatement.java +++ b/src/interfaces/jdbc/org/postgresql/core/BaseStatement.java @@ -6,19 +6,20 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseStatement.java,v 1.1 2003/03/07 18:39:41 barry Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseStatement.java,v 1.2 2003/05/03 20:40:45 barry Exp $ * *------------------------------------------------------------------------- */ package org.postgresql.core; - +import org.postgresql.PGRefCursorResultSet; import java.sql.*; import java.util.Vector; public interface BaseStatement extends org.postgresql.PGStatement { - public BaseResultSet createResultSet(Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException; + public BaseResultSet createResultSet(Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException; + public PGRefCursorResultSet createRefCursorResultSet(String cursorName) throws SQLException; public BaseConnection getPGConnection(); diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java index 99e42b5c92..ee1db017cf 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java @@ -9,7 +9,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.11 2003/03/08 06:06:55 barry Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.12 2003/05/03 20:40:45 barry Exp $ * *------------------------------------------------------------------------- */ @@ -575,11 +575,18 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet return getBytes(columnIndex); default: String type = field.getPGType(); + // if the backend doesn't know the type then coerce to String if (type.equals("unknown")) { return getString(columnIndex); } + // Specialized support for ref cursors is neater. + else if (type.equals("refcursor")) + { + String cursorName = getString(columnIndex); + return statement.createRefCursorResultSet(cursorName); + } else { return connection.getObject(field.getPGType(), getString(columnIndex)); diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java index 8f39d2bb24..c473dd240b 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java @@ -13,7 +13,7 @@ import org.postgresql.core.QueryExecutor; import org.postgresql.largeobject.*; import org.postgresql.util.*; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.20 2003/04/17 04:37:07 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.21 2003/05/03 20:40:45 barry Exp $ * This class defines methods of the jdbc1 specification. This class is * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement @@ -871,6 +871,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement break; case Types.BINARY: case Types.VARBINARY: + case Types.LONGVARBINARY: l_pgType = PG_BYTEA; break; case Types.OTHER: @@ -1490,6 +1491,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement break; case Types.BINARY: case Types.VARBINARY: + case Types.LONGVARBINARY: setObject(parameterIndex, x); break; case Types.OTHER: diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java index bb30580c3c..697a1869ab 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java @@ -3,6 +3,7 @@ package org.postgresql.jdbc1; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; @@ -18,5 +19,10 @@ public class Jdbc1CallableStatement extends AbstractJdbc1Statement implements ja { return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc1RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java index 87e64d6906..a80928ebdd 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java @@ -2,6 +2,7 @@ package org.postgresql.jdbc1; import java.sql.*; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; @@ -17,4 +18,9 @@ public class Jdbc1PreparedStatement extends AbstractJdbc1Statement implements Pr { return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc1RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1RefCursorResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1RefCursorResultSet.java new file mode 100644 index 0000000000..7b83bf6742 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1RefCursorResultSet.java @@ -0,0 +1,44 @@ +package org.postgresql.jdbc1; + +import java.sql.SQLException; +import org.postgresql.core.QueryExecutor; +import org.postgresql.core.BaseStatement; +import org.postgresql.PGRefCursorResultSet; + +/** A real result set based on a ref cursor. + * + * @author Nic Ferrier + */ +public class Jdbc1RefCursorResultSet extends Jdbc1ResultSet + implements PGRefCursorResultSet +{ + + // The name of the cursor being used. + String refCursorHandle; + + // Indicates when the result set has activaly bound to the cursor. + boolean isInitialized = false; + + + Jdbc1RefCursorResultSet(BaseStatement statement, String refCursorName) + { + super(statement, null, null, null, -1, 0L, false); + this.refCursorHandle = refCursorName; + } + + public String getRefCursor () + { + return refCursorHandle; + } + + public boolean next () throws SQLException + { + if (isInitialized) + return super.next(); + // Initialize this res set with the rows from the cursor. + String[] toExec = { "FETCH ALL IN \"" + refCursorHandle + "\";" }; + QueryExecutor.execute(toExec, new String[0], this); + isInitialized = true; + return super.next(); + } +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java index 67cb91b32e..38edfd87e0 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java @@ -3,10 +3,11 @@ package org.postgresql.jdbc1; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.5 2003/03/07 18:39:44 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/Jdbc1Statement.java,v 1.6 2003/05/03 20:40:45 barry Exp $ * This class implements the java.sql.Statement interface for JDBC1. * However most of the implementation is really done in * org.postgresql.jdbc1.AbstractJdbc1Statement @@ -23,4 +24,9 @@ public class Jdbc1Statement extends org.postgresql.jdbc1.AbstractJdbc1Statement { return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc1RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java index 46ebdb47ce..2151423502 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java @@ -9,7 +9,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.18 2003/03/25 02:24:07 davec Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.19 2003/05/03 20:40:45 barry Exp $ * *------------------------------------------------------------------------- */ @@ -148,11 +148,18 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra default: String type = field.getPGType(); + // if the backend doesn't know the type then coerce to String if (type.equals("unknown")) { return getString(columnIndex); } + // Specialized support for ref cursors is neater. + else if (type.equals("refcursor")) + { + String cursorName = getString(columnIndex); + return statement.createRefCursorResultSet(cursorName); + } else { return connection.getObject(field.getPGType(), getString(columnIndex)); diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java index 5b8e76e122..e10223e975 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java @@ -3,6 +3,7 @@ package org.postgresql.jdbc2; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; @@ -18,5 +19,10 @@ public class Jdbc2CallableStatement extends org.postgresql.jdbc2.AbstractJdbc2St { return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc2RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java index 4eeded05fd..83023f05f4 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java @@ -3,6 +3,7 @@ package org.postgresql.jdbc2; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; @@ -18,5 +19,11 @@ public class Jdbc2PreparedStatement extends org.postgresql.jdbc2.AbstractJdbc2St { return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc2RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2RefCursorResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2RefCursorResultSet.java new file mode 100644 index 0000000000..08ec33d752 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2RefCursorResultSet.java @@ -0,0 +1,43 @@ +package org.postgresql.jdbc2; + + +import org.postgresql.core.QueryExecutor; +import org.postgresql.core.BaseStatement; +import org.postgresql.PGRefCursorResultSet; + + +/** A real result set based on a ref cursor. + * + * @author Nic Ferrier + */ +public class Jdbc2RefCursorResultSet extends Jdbc2ResultSet + implements PGRefCursorResultSet +{ + + String refCursorHandle; + + // Indicates when the result set has activaly bound to the cursor. + boolean isInitialized = false; + + Jdbc2RefCursorResultSet(BaseStatement statement, String refCursorName) throws java.sql.SQLException + { + super(statement, null, null, null, -1, 0L, false); + this.refCursorHandle = refCursorName; + } + + public String getRefCursor () + { + return refCursorHandle; + } + + public boolean next () throws java.sql.SQLException + { + if (isInitialized) + return super.next(); + // Initialize this res set with the rows from the cursor. + String[] toExec = { "FETCH ALL IN \"" + refCursorHandle + "\";" }; + QueryExecutor.execute(toExec, new String[0], this); + isInitialized = true; + return super.next(); + } +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java index a1328dd3fb..eb78a889b3 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java @@ -3,10 +3,11 @@ package org.postgresql.jdbc2; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.5 2003/03/07 18:39:45 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/Jdbc2Statement.java,v 1.6 2003/05/03 20:40:45 barry Exp $ * This class implements the java.sql.Statement interface for JDBC2. * However most of the implementation is really done in * org.postgresql.jdbc2.AbstractJdbc2Statement or one of it's parents @@ -23,4 +24,9 @@ public class Jdbc2Statement extends org.postgresql.jdbc2.AbstractJdbc2Statement { return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc2RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3CallableStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3CallableStatement.java index 2b71e192cf..0008f0e98c 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3CallableStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3CallableStatement.java @@ -3,6 +3,7 @@ package org.postgresql.jdbc3; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; @@ -19,5 +20,9 @@ public class Jdbc3CallableStatement extends org.postgresql.jdbc3.AbstractJdbc3St return new Jdbc3ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc3RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3PreparedStatement.java index 229a4353cd..e9e25f76b0 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3PreparedStatement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3PreparedStatement.java @@ -2,7 +2,9 @@ package org.postgresql.jdbc3; import java.sql.*; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; +import org.postgresql.core.BaseStatement; import org.postgresql.core.Field; public class Jdbc3PreparedStatement extends org.postgresql.jdbc3.AbstractJdbc3Statement implements java.sql.PreparedStatement @@ -15,8 +17,12 @@ public class Jdbc3PreparedStatement extends org.postgresql.jdbc3.AbstractJdbc3St public BaseResultSet createResultSet (Field[] fields, java.util.Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException { - return new Jdbc3ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); + return new Jdbc3ResultSet((BaseStatement)this, fields, tuples, status, updateCount, insertOID, binaryCursor); + } + + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc3RefCursorResultSet(this, cursorName); } - } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3RefCursorResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3RefCursorResultSet.java new file mode 100644 index 0000000000..fe18672a7b --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3RefCursorResultSet.java @@ -0,0 +1,47 @@ +package org.postgresql.jdbc3; + +import org.postgresql.core.QueryExecutor; +import org.postgresql.core.Field; +import org.postgresql.core.BaseStatement; +import java.util.Vector; +import org.postgresql.PGConnection; +import org.postgresql.PGRefCursorResultSet; + +/** A real result set based on a ref cursor. + * + * @author Nic Ferrier + */ +public class Jdbc3RefCursorResultSet extends Jdbc3ResultSet implements PGRefCursorResultSet +{ + + String refCursorHandle; + + // Indicates when the result set has activaly bound to the cursor. + boolean isInitialized = false; + + Jdbc3RefCursorResultSet(java.sql.Statement statement, String refCursorName) throws java.sql.SQLException + { + // This casting is a GCJ requirement. + super((BaseStatement)statement, + (Field[])null, + (Vector)null, + (String)null, -1, 0L, false); + this.refCursorHandle = refCursorName; + } + + public String getRefCursor () + { + return refCursorHandle; + } + + public boolean next () throws java.sql.SQLException + { + if (isInitialized) + return super.next(); + // Initialize this res set with the rows from the cursor. + String[] toExec = { "FETCH ALL IN \"" + refCursorHandle + "\";" }; + QueryExecutor.execute(toExec, new String[0], this); + isInitialized = true; + return super.next(); + } +} diff --git a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3Statement.java index aa8cf00ca6..eedea2f5f0 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3Statement.java @@ -3,10 +3,11 @@ package org.postgresql.jdbc3; import java.sql.*; import java.util.Vector; +import org.postgresql.PGRefCursorResultSet; import org.postgresql.core.BaseResultSet; import org.postgresql.core.Field; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3Statement.java,v 1.4 2003/03/07 18:39:45 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc3/Attic/Jdbc3Statement.java,v 1.5 2003/05/03 20:40:45 barry Exp $ * This class implements the java.sql.Statement interface for JDBC3. * However most of the implementation is really done in * org.postgresql.jdbc3.AbstractJdbc3Statement or one of it's parents @@ -24,4 +25,8 @@ public class Jdbc3Statement extends org.postgresql.jdbc3.AbstractJdbc3Statement return new Jdbc3ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor); } + public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException + { + return new Jdbc3RefCursorResultSet(this, cursorName); + } } diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/RefCursorTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/RefCursorTest.java new file mode 100644 index 0000000000..a3ce71cb15 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/RefCursorTest.java @@ -0,0 +1,100 @@ +package org.postgresql.test.jdbc2; + +import org.postgresql.test.TestUtil; +import junit.framework.TestCase; +import java.io.*; +import java.sql.*; + +/* + * RefCursor ResultSet tests. + * This test case is basically the same as the ResultSet test case. + * + * @author Nic Ferrier + */ +public class RefCursorTest extends TestCase +{ + private Connection con; + + public RefCursorTest(String name) + { + super(name); + } + + protected void setUp() throws Exception + { + // this is the same as the ResultSet setup. + con = TestUtil.openDB(); + Statement stmt = con.createStatement(); + + TestUtil.createTable(con, "testrs", "id integer"); + + stmt.executeUpdate("INSERT INTO testrs VALUES (1)"); + stmt.executeUpdate("INSERT INTO testrs VALUES (2)"); + stmt.executeUpdate("INSERT INTO testrs VALUES (3)"); + stmt.executeUpdate("INSERT INTO testrs VALUES (4)"); + stmt.executeUpdate("INSERT INTO testrs VALUES (6)"); + stmt.executeUpdate("INSERT INTO testrs VALUES (9)"); + + + // Create the functions. + stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getRefcursor () RETURNS refcursor AS '" + + "declare v_resset; begin open v_resset for select id from testrs order by id; " + + "return v_resset; end;' LANGUAGE 'plpgsql';"); + stmt.execute ("CREATE OR REPLACE FUNCTION testspg__getEmptyRefcursor () RETURNS refcursor AS '" + + "declare v_resset; begin open v_resset for select id from testrs where id < 1 order by id; " + + "return v_resset; end;' LANGUAGE 'plpgsql';"); + stmt.close(); + } + + protected void tearDown() throws Exception + { + Statement stmt = con.createStatement (); + stmt.execute ("drop FUNCTION testspg__getRefcursor ();"); + stmt.execute ("drop FUNCTION testspg__getEmptyRefcursor ();"); + TestUtil.dropTable(con, "testrs"); + TestUtil.closeDB(con); + } + + public void testResult() throws Exception + { + CallableStatement call = con.prepareCall("{ ? = call testspg__getRefcursor () }"); + call.registerOutParameter(1, Types.OTHER); + call.execute(); + ResultSet rs = (ResultSet) call.getObject(1); + + assertTrue(rs.next()); + assertTrue(rs.getInt(1) == 1); + + assertTrue(rs.next()); + assertTrue(rs.getInt(1) == 2); + + assertTrue(rs.next()); + assertTrue(rs.getInt(1) == 3); + + assertTrue(rs.next()); + assertTrue(rs.getInt(1) == 4); + + assertTrue(rs.next()); + assertTrue(rs.getInt(1) == 6); + + assertTrue(rs.next()); + assertTrue(rs.getInt(1) == 9); + + assertTrue(!rs.next()); + + call.close(); + } + + + public void testEmptyResult() throws Exception + { + CallableStatement call = con.prepareCall("{ ? = call testspg__getRefcursor () }"); + call.registerOutParameter(1, Types.OTHER); + call.execute(); + + ResultSet rs = (ResultSet) call.getObject(1); + assertTrue(!rs.next()); + + call.close(); + } +}