Attached is my attempt to clean up the horrors of the ExecSQL() method in

the JDBC driver.

I've done this by extracting it into a new method object called
QueryExecutor (should go into org/postgresql/core/) and then taking it
apart into different methods in that class.

A short summary:

* Extracted ExecSQL() from Connection into a method object called
  QueryExecutor.

* Moved ReceiveFields() from Connection to QueryExecutor.

* Extracted parts of the original ExecSQL() method body into smaller
  methods on QueryExecutor.

* Bug fix: The instance variable "pid" in Connection was used in two
  places with different meaning. Both were probably in dead code, but it's
  fixed anyway.

Anders Bengtsson
This commit is contained in:
Bruce Momjian 2001-09-06 03:13:34 +00:00
parent d99794e613
commit e30b283f30
3 changed files with 9 additions and 166 deletions

View File

@ -8,10 +8,10 @@ import org.postgresql.Field;
import org.postgresql.fastpath.*;
import org.postgresql.largeobject.*;
import org.postgresql.util.*;
import org.postgresql.core.Encoding;
import org.postgresql.core.*;
/**
* $Id: Connection.java,v 1.26 2001/08/24 16:50:12 momjian Exp $
* $Id: Connection.java,v 1.27 2001/09/06 03:13:34 momjian Exp $
*
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
* JDBC2 versions of the Connection class.
@ -348,166 +348,9 @@ public abstract class Connection
* @return a ResultSet holding the results
* @exception SQLException if a database error occurs
*/
public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQLException
public java.sql.ResultSet ExecSQL(String sql, java.sql.Statement stat) throws SQLException
{
// added Jan 30 2001 to correct maxrows per statement
int maxrows=0;
if(stat!=null)
maxrows=stat.getMaxRows();
// added Oct 7 1998 to give us thread safety.
synchronized(pg_stream) {
// Deallocate all resources in the stream associated
// with a previous request.
// This will let the driver reuse byte arrays that has already
// been allocated instead of allocating new ones in order
// to gain performance improvements.
// PM 17/01/01: Commented out due to race bug. See comments in
// PG_Stream
//pg_stream.deallocate();
Field[] fields = null;
Vector tuples = new Vector();
byte[] buf = null;
int fqp = 0;
boolean hfr = false;
String recv_status = null, msg;
int update_count = 1;
int insert_oid = 0;
SQLException final_error = null;
buf = encoding.encode(sql);
try
{
pg_stream.SendChar('Q');
pg_stream.Send(buf);
pg_stream.SendChar(0);
pg_stream.flush();
} catch (IOException e) {
throw new PSQLException("postgresql.con.ioerror",e);
}
while (!hfr || fqp > 0)
{
Object tup=null; // holds rows as they are recieved
int c = pg_stream.ReceiveChar();
switch (c)
{
case 'A': // Asynchronous Notify
pid = pg_stream.ReceiveInteger(4);
msg = pg_stream.ReceiveString(encoding);
break;
case 'B': // Binary Data Transfer
if (fields == null)
throw new PSQLException("postgresql.con.tuple");
tup = pg_stream.ReceiveTuple(fields.length, true);
// This implements Statement.setMaxRows()
if(maxrows==0 || tuples.size()<maxrows)
tuples.addElement(tup);
break;
case 'C': // Command Status
recv_status = pg_stream.ReceiveString(encoding);
// Now handle the update count correctly.
if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE") || recv_status.startsWith("MOVE")) {
try {
update_count = Integer.parseInt(recv_status.substring(1+recv_status.lastIndexOf(' ')));
} catch(NumberFormatException nfe) {
throw new PSQLException("postgresql.con.fathom",recv_status);
}
if(recv_status.startsWith("INSERT")) {
try {
insert_oid = Integer.parseInt(recv_status.substring(1+recv_status.indexOf(' '),recv_status.lastIndexOf(' ')));
} catch(NumberFormatException nfe) {
throw new PSQLException("postgresql.con.fathom",recv_status);
}
}
}
if (fields != null)
hfr = true;
else
{
try
{
pg_stream.SendChar('Q');
pg_stream.SendChar(' ');
pg_stream.SendChar(0);
pg_stream.flush();
} catch (IOException e) {
throw new PSQLException("postgresql.con.ioerror",e);
}
fqp++;
}
break;
case 'D': // Text Data Transfer
if (fields == null)
throw new PSQLException("postgresql.con.tuple");
tup = pg_stream.ReceiveTuple(fields.length, false);
// This implements Statement.setMaxRows()
if(maxrows==0 || tuples.size()<maxrows)
tuples.addElement(tup);
break;
case 'E': // Error Message
msg = pg_stream.ReceiveString(encoding);
final_error = new SQLException(msg);
hfr = true;
break;
case 'I': // Empty Query
int t = pg_stream.ReceiveChar();
if (t != 0)
throw new PSQLException("postgresql.con.garbled");
if (fqp > 0)
fqp--;
if (fqp == 0)
hfr = true;
break;
case 'N': // Error Notification
addWarning(pg_stream.ReceiveString(encoding));
break;
case 'P': // Portal Name
String pname = pg_stream.ReceiveString(encoding);
break;
case 'T': // MetaData Field Description
if (fields != null)
throw new PSQLException("postgresql.con.multres");
fields = ReceiveFields();
break;
case 'Z': // backend ready for query, ignore for now :-)
break;
default:
throw new PSQLException("postgresql.con.type",new Character((char)c));
}
}
if (final_error != null)
throw final_error;
return getResultSet(this, stat, fields, tuples, recv_status, update_count, insert_oid);
}
}
/**
* Receive the field descriptions from the back end
*
* @return an array of the Field object describing the fields
* @exception SQLException if a database error occurs
*/
private Field[] ReceiveFields() throws SQLException
{
int nf = pg_stream.ReceiveIntegerR(2), i;
Field[] fields = new Field[nf];
for (i = 0 ; i < nf ; ++i)
{
String typname = pg_stream.ReceiveString(encoding);
int typid = pg_stream.ReceiveIntegerR(4);
int typlen = pg_stream.ReceiveIntegerR(2);
int typmod = pg_stream.ReceiveIntegerR(4);
fields[i] = new Field(this, typname, typid, typlen, typmod);
}
return fields;
return new QueryExecutor(sql, stat, pg_stream, this).execute();
}
/**
@ -793,7 +636,7 @@ public abstract class Connection
* This returns a resultset. It must be overridden, so that the correct
* version (from jdbc1 or jdbc2) are returned.
*/
protected abstract java.sql.ResultSet getResultSet(org.postgresql.Connection conn,java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException;
public abstract java.sql.ResultSet getResultSet(org.postgresql.Connection conn,java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException;
/**
* In some cases, it is desirable to immediately release a Connection's

View File

@ -17,7 +17,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/**
* $Id: Connection.java,v 1.8 2001/08/24 16:50:15 momjian Exp $
* $Id: Connection.java,v 1.9 2001/09/06 03:13:34 momjian Exp $
*
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
@ -131,7 +131,7 @@ public class Connection extends org.postgresql.Connection implements java.sql.Co
* This overides the method in org.postgresql.Connection and returns a
* ResultSet.
*/
protected java.sql.ResultSet getResultSet(org.postgresql.Connection conn,java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException
public java.sql.ResultSet getResultSet(org.postgresql.Connection conn,java.sql.Statement stat, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException
{
// in jdbc1 stat is ignored.
return new org.postgresql.jdbc1.ResultSet((org.postgresql.jdbc1.Connection)conn,fields,tuples,status,updateCount,insertOID);

View File

@ -17,7 +17,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/**
* $Id: Connection.java,v 1.10 2001/08/24 16:50:16 momjian Exp $
* $Id: Connection.java,v 1.11 2001/09/06 03:13:34 momjian Exp $
*
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
@ -204,7 +204,7 @@ public class Connection extends org.postgresql.Connection implements java.sql.Co
* This overides the method in org.postgresql.Connection and returns a
* ResultSet.
*/
protected java.sql.ResultSet getResultSet(org.postgresql.Connection conn, java.sql.Statement stat,Field[] fields, Vector tuples, String status, int updateCount, int insertOID) throws SQLException
public java.sql.ResultSet getResultSet(org.postgresql.Connection conn, java.sql.Statement stat,Field[] fields, Vector tuples, String status, int updateCount, int insertOID) throws SQLException
{
// In 7.1 we now test concurrency to see which class to return. If we are not working with a
// Statement then default to a normal ResultSet object.