refcursor handling patch

From: Nic Ferrier <nferrier(at)tapsellferrier(dot)co(dot)uk>
To: pgsql-patches(at)postgresql(dot)org, pgsql-jdbc(at)postgresql(dot)org
Subject: refcursor handling patch
Date: 2003-04-14 22:51:06
Message-ID: 87smsku205.fsf@pooh-sticks-bridge.tapsellferrier.co.uk
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: pgsql-jdbc pgsql-patches

The inlined patch allows current CVS to deal with ref cursor return
types.

Barry Lind and I have talked about this implementation before, I
submit it now as similar as it could be to our previous
discussions. However, I think that a couple of things might have
changed that might mean we change the implementation of this:

- the introduction of 'base' classes for implementation might make
PGRefCursorResultSet obsolete. However, since it still does
something that the user might want site of I think it's in a
valuable place.

- the statement class heirarchys should descend from their nearest
relative, not from the Abstract... version? if not we end up having
to put nearlly the same code (to create ref cursor result sets) in
each one.

I'd very much appreciate testing of this, I only have a java1.2
environment for postgresql at the moment. Whilst it works for me
there we need to know it's okay on java1.1 and java1.4.

Nic Ferrier

the patch follows>>>>

Index: org/postgresql/PGRefCursorResultSet.java
===================================================================
RCS file: PGRefCursorResultSet.java
diff -N PGRefCursorResultSet.java
--- /dev/null Mon Apr 14 18:19:00 2003
+++ PGRefCursorResultSet.java Mon Apr 14 18:44:12 2003
@@ -0,0 +1,25 @@
+/*-------------------------------------------------------------------------
+ *
+ * PGRefCursorResultSet.java
+ * Describes a PLPGSQL refcursor type.
+ *
+ * Copyright (c) 2003, PostgreSQL Global Development Group
+ *
+ * IDENTIFICATION
+ * $Header$
+ *
+ *-------------------------------------------------------------------------
+ */
+package org.postgresql;
+
+
+/** A ref cursor based result set.
+ */
+public interface PGRefCursorResultSet
+{
+
+ /** return the name of the cursor.
+ */
+ public String getRefCursor ();
+
+}
Index: org/postgresql/core/BaseStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/core/BaseStatement.java,v
retrieving revision 1.1
diff -p -u -r1.1 BaseStatement.java
--- org/postgresql/core/BaseStatement.java 2003/03/07 18:39:41 1.1
+++ org/postgresql/core/BaseStatement.java 2003/04/14 22:44:12
@@ -12,13 +12,14 @@
*/
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();

Index: org/postgresql/jdbc1/AbstractJdbc1ResultSet.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java,v
retrieving revision 1.11
diff -p -u -r1.11 AbstractJdbc1ResultSet.java
--- org/postgresql/jdbc1/AbstractJdbc1ResultSet.java 2003/03/08 06:06:55 1.11
+++ org/postgresql/jdbc1/AbstractJdbc1ResultSet.java 2003/04/14 22:44:13
@@ -575,11 +575,20 @@ public abstract class AbstractJdbc1Resul
return getBytes(columnIndex);
default:
String type = field.getPGType();
+
+ System.err.println("type is: " + type);
+
// 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));
Index: org/postgresql/jdbc1/Jdbc1CallableStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1CallableStatement.java,v
retrieving revision 1.3
diff -p -u -r1.3 Jdbc1CallableStatement.java
--- org/postgresql/jdbc1/Jdbc1CallableStatement.java 2003/03/07 18:39:44 1.3
+++ org/postgresql/jdbc1/Jdbc1CallableStatement.java 2003/04/14 22:44:13
@@ -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;

@@ -17,6 +18,11 @@ public class Jdbc1CallableStatement exte
public BaseResultSet createResultSet (Field[] fields, java.util.Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
+
+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc1RefCursorResultSet(this, cursorName);
}
}

Index: org/postgresql/jdbc1/Jdbc1PreparedStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1PreparedStatement.java,v
retrieving revision 1.3
diff -p -u -r1.3 Jdbc1PreparedStatement.java
--- org/postgresql/jdbc1/Jdbc1PreparedStatement.java 2003/03/07 18:39:44 1.3
+++ org/postgresql/jdbc1/Jdbc1PreparedStatement.java 2003/04/14 22:44:13
@@ -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;

@@ -16,5 +17,10 @@ public class Jdbc1PreparedStatement exte
public BaseResultSet createResultSet (Field[] fields, java.util.Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
+
+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc1RefCursorResultSet(this, cursorName);
}
}
Index: org/postgresql/jdbc1/Jdbc1RefCursorResultSet.java
===================================================================
RCS file: Jdbc1RefCursorResultSet.java
diff -N Jdbc1RefCursorResultSet.java
--- /dev/null Mon Apr 14 18:19:00 2003
+++ Jdbc1RefCursorResultSet.java Mon Apr 14 18:44:13 2003
@@ -0,0 +1,44 @@
+package org.postgresql.jdbc1;
+
+
+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 <nferrier(at)tapsellferrier(dot)co(dot)uk>
+ */
+public class Jdbc1RefCursorResultSet extends AbstractJdbc1ResultSet
+ 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();
+ }
+}
Index: org/postgresql/jdbc1/Jdbc1Statement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc1/Jdbc1Statement.java,v
retrieving revision 1.5
diff -p -u -r1.5 Jdbc1Statement.java
--- org/postgresql/jdbc1/Jdbc1Statement.java 2003/03/07 18:39:44 1.5
+++ org/postgresql/jdbc1/Jdbc1Statement.java 2003/04/14 22:44:13
@@ -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;

@@ -22,5 +23,10 @@ public class Jdbc1Statement extends org.
public BaseResultSet createResultSet (Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc1ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
+
+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc1RefCursorResultSet(this, cursorName);
}
}
Index: org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java,v
retrieving revision 1.18
diff -p -u -r1.18 AbstractJdbc2ResultSet.java
--- org/postgresql/jdbc2/AbstractJdbc2ResultSet.java 2003/03/25 02:24:07 1.18
+++ org/postgresql/jdbc2/AbstractJdbc2ResultSet.java 2003/04/14 22:44:14
@@ -148,11 +148,18 @@ public abstract class AbstractJdbc2Resul

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));
Index: org/postgresql/jdbc2/Jdbc2CallableStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2CallableStatement.java,v
retrieving revision 1.4
diff -p -u -r1.4 Jdbc2CallableStatement.java
--- org/postgresql/jdbc2/Jdbc2CallableStatement.java 2003/03/07 18:39:45 1.4
+++ org/postgresql/jdbc2/Jdbc2CallableStatement.java 2003/04/14 22:44:14
@@ -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;

@@ -17,6 +18,11 @@ public class Jdbc2CallableStatement exte
public BaseResultSet createResultSet (Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
+
+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc2RefCursorResultSet(this, cursorName);
}
}

Index: org/postgresql/jdbc2/Jdbc2PreparedStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2PreparedStatement.java,v
retrieving revision 1.4
diff -p -u -r1.4 Jdbc2PreparedStatement.java
--- org/postgresql/jdbc2/Jdbc2PreparedStatement.java 2003/03/07 18:39:45 1.4
+++ org/postgresql/jdbc2/Jdbc2PreparedStatement.java 2003/04/14 22:44:15
@@ -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;

@@ -17,6 +18,12 @@ public class Jdbc2PreparedStatement exte
public BaseResultSet createResultSet (Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
+
+
+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc2RefCursorResultSet(this, cursorName);
}
}

Index: org/postgresql/jdbc2/Jdbc2RefCursorResultSet.java
===================================================================
RCS file: Jdbc2RefCursorResultSet.java
diff -N Jdbc2RefCursorResultSet.java
--- /dev/null Mon Apr 14 18:19:00 2003
+++ Jdbc2RefCursorResultSet.java Mon Apr 14 18:44:15 2003
@@ -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 <nferrier(at)tapsellferrier(dot)co(dot)uk>
+ */
+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();
+ }
+}
Index: org/postgresql/jdbc2/Jdbc2Statement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc2/Jdbc2Statement.java,v
retrieving revision 1.5
diff -p -u -r1.5 Jdbc2Statement.java
--- org/postgresql/jdbc2/Jdbc2Statement.java 2003/03/07 18:39:45 1.5
+++ org/postgresql/jdbc2/Jdbc2Statement.java 2003/04/14 22:44:15
@@ -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;

@@ -22,5 +23,10 @@ public class Jdbc2Statement extends org.
public BaseResultSet createResultSet (Field[] fields, Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
{
return new Jdbc2ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
+
+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc2RefCursorResultSet(this, cursorName);
}
}
Index: org/postgresql/jdbc3/Jdbc3CallableStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3CallableStatement.java,v
retrieving revision 1.4
diff -p -u -r1.4 Jdbc3CallableStatement.java
--- org/postgresql/jdbc3/Jdbc3CallableStatement.java 2003/03/07 18:39:45 1.4
+++ org/postgresql/jdbc3/Jdbc3CallableStatement.java 2003/04/14 22:44:15
@@ -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 exte
return new Jdbc3ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
}

+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc3RefCursorResultSet(this, cursorName);
+ }
}

Index: org/postgresql/jdbc3/Jdbc3PreparedStatement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3PreparedStatement.java,v
retrieving revision 1.4
diff -p -u -r1.4 Jdbc3PreparedStatement.java
--- org/postgresql/jdbc3/Jdbc3PreparedStatement.java 2003/03/07 18:39:45 1.4
+++ org/postgresql/jdbc3/Jdbc3PreparedStatement.java 2003/04/14 22:44:15
@@ -2,6 +2,7 @@ package org.postgresql.jdbc3;


import java.sql.*;
+import org.postgresql.PGRefCursorResultSet;
import org.postgresql.core.BaseResultSet;
import org.postgresql.core.Field;

@@ -18,5 +19,9 @@ public class Jdbc3PreparedStatement exte
return new Jdbc3ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
}

+ public PGRefCursorResultSet createRefCursorResultSet (Field[] fields, java.util.Vector tuples, String status, int updateCount, long insertOID, boolean binaryCursor) throws SQLException
+ {
+ return new Jdbc3RefCursorResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
+ }
}

Index: org/postgresql/jdbc3/Jdbc3RefCursorResultSet.java
===================================================================
RCS file: Jdbc3RefCursorResultSet.java
diff -N Jdbc3RefCursorResultSet.java
--- /dev/null Mon Apr 14 18:19:00 2003
+++ Jdbc3RefCursorResultSet.java Mon Apr 14 18:44:15 2003
@@ -0,0 +1,41 @@
+package org.postgresql.jdbc3;
+
+
+import org.postgresql.PGConnection;
+import org.postgresql.PGRefCursorResultSet;
+
+/** A real result set based on a ref cursor.
+ *
+ * @author Nic Ferrier <nferrier(at)tapsellferrier(dot)co(dot)uk>
+ */
+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
+ {
+ 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 + "\";" };
+ Jdbc3Connection execr = (Jdbc3Connection) statement.getConnection();
+ execr.execSQL(toExec, new String[0], statement, this);
+ isInitialized = true;
+ return super.next();
+ }
+}
Index: org/postgresql/jdbc3/Jdbc3Statement.java
===================================================================
RCS file: /projects/cvsroot/pgsql-server/src/interfaces/jdbc/org/postgresql/jdbc3/Jdbc3Statement.java,v
retrieving revision 1.4
diff -p -u -r1.4 Jdbc3Statement.java
--- org/postgresql/jdbc3/Jdbc3Statement.java 2003/03/07 18:39:45 1.4
+++ org/postgresql/jdbc3/Jdbc3Statement.java 2003/04/14 22:44:15
@@ -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;

@@ -24,4 +25,8 @@ public class Jdbc3Statement extends org.
return new Jdbc3ResultSet(this, fields, tuples, status, updateCount, insertOID, binaryCursor);
}

+ public PGRefCursorResultSet createRefCursorResultSet (String cursorName) throws SQLException
+ {
+ return new Jdbc3RefCursorResultSet(this, cursorName);
+ }
}

Browse pgsql-jdbc by date

  From Date Subject
Next Message Kevin Brown 2003-04-15 00:35:18 Re: [GENERAL] Problem about pgsql's column alias
Previous Message snpe 2003-04-14 22:38:00 JDBC driver without URL

Browse pgsql-patches by date

  From Date Subject
Next Message Dennis Gearon 2003-04-14 23:41:28 Re: Are we losing momentum?
Previous Message Bruce Momjian 2003-04-14 22:37:57 Are we losing momentum?