--- /dev/null
+\r
+package org.postgresql.core;\r
+\r
+import java.util.Vector;\r
+import java.io.IOException;\r
+import java.sql.*;\r
+import org.postgresql.*;\r
+import org.postgresql.util.PSQLException;\r
+\r
+/*\r
+ * Executes a query on the backend.\r
+ *\r
+ * <p>The lifetime of a QueryExecutor object is from sending the query\r
+ * until the response has been received from the backend.\r
+ *\r
+ * $Id: QueryExecutor2.java,v 1.1 2002/03/21 03:20:29 davec Exp $\r
+ */\r
+\r
+public class QueryExecutor2\r
+{\r
+\r
+ private final String sql;\r
+ private final java.sql.Statement statement;\r
+ private final PG_Stream pg_stream;\r
+ private final org.postgresql.Connection connection;\r
+\r
+ public QueryExecutor2(String sql,\r
+ java.sql.Statement statement,\r
+ PG_Stream pg_stream,\r
+ org.postgresql.Connection connection)\r
+ throws SQLException\r
+ {\r
+ this.sql = sql;\r
+ this.statement = statement;\r
+ this.pg_stream = pg_stream;\r
+ this.connection = connection;\r
+\r
+ if (statement != null)\r
+ maxRows = statement.getMaxRows();\r
+ else\r
+ maxRows = 0;\r
+ }\r
+\r
+ private Field[] fields = null;\r
+ private Vector tuples = new Vector();\r
+ private boolean binaryCursor = false;\r
+ private String status = null;\r
+ private int update_count = 1;\r
+ private long insert_oid = 0;\r
+ private int maxRows;\r
+\r
+ /*\r
+ * Execute a query on the backend.\r
+ */\r
+ public java.sql.ResultSet execute() throws SQLException\r
+ {\r
+\r
+ StringBuffer errorMessage = null;\r
+\r
+ synchronized (pg_stream)\r
+ {\r
+\r
+ sendQuery(sql);\r
+ connection.asyncStatus = org.postgresql.Connection.PGASYNC_BUSY;\r
+\r
+ while ( connection.asyncStatus != org.postgresql.Connection.PGASYNC_IDLE )\r
+ {\r
+ int c = pg_stream.ReceiveChar();\r
+\r
+ if ( c == 'A' )\r
+ {\r
+\r
+ int pid = pg_stream.ReceiveIntegerR(4);\r
+ String msg = pg_stream.ReceiveString(connection.getEncoding());\r
+\r
+ org.postgresql.Driver.debug(msg);\r
+ continue;\r
+ }\r
+ else if ( c == 'N' )\r
+ {\r
+ String notification = pg_stream.ReceiveString(connection.getEncoding());\r
+ org.postgresql.Driver.debug(notification);\r
+ connection.addWarning(notification);\r
+ continue;\r
+ }\r
+ else if ( connection.asyncStatus != org.postgresql.Connection.PGASYNC_BUSY )\r
+ {\r
+ if ( connection.asyncStatus != org.postgresql.Connection.PGASYNC_IDLE )\r
+ {\r
+ // only one possibility left which is PGASYNC_READY, so let's get out\r
+ break;\r
+ }\r
+ if ( c == 'E' ) {\r
+ String error = pg_stream.ReceiveString(connection.getEncoding());\r
+ org.postgresql.Driver.debug(error);\r
+\r
+ // no sense in creating this object until we really need it\r
+ if ( errorMessage == null ) {\r
+ errorMessage = new StringBuffer();\r
+ }\r
+\r
+ errorMessage.append(error);\r
+ break;\r
+ }\r
+ }else{\r
+\r
+ switch (c)\r
+ {\r
+ case 'C': // Command Status\r
+ receiveCommandStatus();\r
+ break;\r
+\r
+ case 'E': // Error Message\r
+\r
+ // it's possible to get multiple error messages from one query\r
+ // see libpq, there are some comments about a connection being closed\r
+ // by the backend after real error occurs, so append error messages here\r
+ // so append them and just remember that an error occured\r
+ // throw the exception at the end of processing\r
+\r
+ String error = pg_stream.ReceiveString(connection.getEncoding());\r
+ org.postgresql.Driver.debug(error);\r
+\r
+ // no sense in creating this object until we really need it\r
+ if ( errorMessage == null ) {\r
+ errorMessage = new StringBuffer();\r
+ }\r
+\r
+ errorMessage.append(error);\r
+ connection.asyncStatus = org.postgresql.Connection.PGASYNC_READY;\r
+ break;\r
+\r
+ case 'Z': // backend ready for query, ignore for now :-)\r
+ connection.asyncStatus = org.postgresql.Connection.PGASYNC_IDLE;\r
+ break;\r
+\r
+ case 'I': // Empty Query\r
+ int t = pg_stream.ReceiveChar();\r
+ if (t != 0)\r
+ throw new PSQLException("postgresql.con.garbled");\r
+\r
+ connection.asyncStatus = org.postgresql.Connection.PGASYNC_READY;\r
+ break;\r
+\r
+ case 'P': // Portal Name\r
+ String pname = pg_stream.ReceiveString(connection.getEncoding());\r
+ org.postgresql.Driver.debug(pname);\r
+ break;\r
+\r
+ case 'T': // MetaData Field Description\r
+ receiveFields();\r
+ break;\r
+\r
+ case 'B': // Binary Data Transfer\r
+ receiveTuple(true);\r
+ break;\r
+\r
+ case 'D': // Text Data Transfer\r
+ receiveTuple(false);\r
+ break;\r
+\r
+ default:\r
+ throw new PSQLException("postgresql.con.type",\r
+ new Character((char) c));\r
+ }\r
+ }\r
+ }\r
+ // did we get an error message?\r
+\r
+ if ( errorMessage != null ) {\r
+ // yes, throw an exception\r
+ throw new SQLException(errorMessage.toString());\r
+ }\r
+ return connection.getResultSet(connection, statement, fields, tuples, status, update_count, insert_oid, binaryCursor);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Send a query to the backend.\r
+ */\r
+ private void sendQuery(String query) throws SQLException\r
+ {\r
+ try\r
+ {\r
+ pg_stream.SendChar('Q');\r
+ pg_stream.Send(connection.getEncoding().encode(query));\r
+ pg_stream.SendChar(0);\r
+ pg_stream.flush();\r
+\r
+ }\r
+ catch (IOException e)\r
+ {\r
+ throw new PSQLException("postgresql.con.ioerror", e);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Receive a tuple from the backend.\r
+ *\r
+ * @param isBinary set if the tuple should be treated as binary data\r
+ */\r
+ private void receiveTuple(boolean isBinary) throws SQLException\r
+ {\r
+ if (fields == null)\r
+ throw new PSQLException("postgresql.con.tuple");\r
+ Object tuple = pg_stream.ReceiveTuple(fields.length, isBinary);\r
+ if (isBinary)\r
+ binaryCursor = true;\r
+ if (maxRows == 0 || tuples.size() < maxRows)\r
+ tuples.addElement(tuple);\r
+ }\r
+\r
+ /*\r
+ * Receive command status from the backend.\r
+ */\r
+ private void receiveCommandStatus() throws SQLException\r
+ {\r
+ status = pg_stream.ReceiveString(connection.getEncoding());\r
+\r
+ try\r
+ {\r
+ // Now handle the update count correctly.\r
+ if (status.startsWith("INSERT") || status.startsWith("UPDATE") || status.startsWith("DELETE") || status.startsWith("MOVE"))\r
+ {\r
+ update_count = Integer.parseInt(status.substring(1 + status.lastIndexOf(' ')));\r
+ }\r
+ if (status.startsWith("INSERT"))\r
+ {\r
+ insert_oid = Long.parseLong(status.substring(1 + status.indexOf(' '),\r
+ status.lastIndexOf(' ')));\r
+ }\r
+ }\r
+ catch (NumberFormatException nfe)\r
+ {\r
+ throw new PSQLException("postgresql.con.fathom", status);\r
+ }\r
+ }\r
+\r
+ /*\r
+ * Receive the field descriptions from the back end.\r
+ */\r
+ private void receiveFields() throws SQLException\r
+ {\r
+ if (fields != null)\r
+ throw new PSQLException("postgresql.con.multres");\r
+\r
+ int size = pg_stream.ReceiveIntegerR(2);\r
+ fields = new Field[size];\r
+\r
+ for (int i = 0; i < fields.length; i++)\r
+ {\r
+ String typeName = pg_stream.ReceiveString(connection.getEncoding());\r
+ int typeOid = pg_stream.ReceiveIntegerR(4);\r
+ int typeLength = pg_stream.ReceiveIntegerR(2);\r
+ int typeModifier = pg_stream.ReceiveIntegerR(4);\r
+ fields[i] = new Field(connection, typeName, typeOid, typeLength, typeModifier);\r
+ }\r
+ }\r
+}\r