Connection.java
上传用户:psq1974
上传日期:2007-01-06
资源大小:1195k
文件大小:33k
源码类别:

mpeg/mp3

开发平台:

C/C++

  1. package postgresql;
  2. import java.io.*;
  3. import java.lang.*;
  4. import java.lang.reflect.*;
  5. import java.net.*;
  6. import java.util.*;
  7. import java.sql.*;
  8. import postgresql.fastpath.*;
  9. import postgresql.largeobject.*;
  10. import postgresql.util.*;
  11. /**
  12.  * A Connection represents a session with a specific database.  Within the
  13.  * context of a Connection, SQL statements are executed and results are
  14.  * returned.
  15.  *
  16.  * <P>A Connection's database is able to provide information describing
  17.  * its tables, its supported SQL grammar, its stored procedures, the
  18.  * capabilities of this connection, etc.  This information is obtained
  19.  * with the getMetaData method.
  20.  *
  21.  * <p><B>Note:</B> By default, the Connection automatically commits changes
  22.  * after executing each statement.  If auto-commit has been disabled, an
  23.  * explicit commit must be done or database changes will not be saved.
  24.  *
  25.  * @see java.sql.Connection
  26.  */
  27. public class Connection implements java.sql.Connection 
  28. {
  29.   // This is the network stream associated with this connection
  30.   protected PG_Stream pg_stream;
  31.   
  32.   // This is set by postgresql.Statement.setMaxRows()
  33.   protected int maxrows = 0; // maximum no. of rows; 0 = unlimited
  34.   
  35.   // This is a cache of the DatabaseMetaData instance for this connection
  36.   protected DatabaseMetaData metadata;
  37.   
  38.   private String PG_HOST;
  39.   private int PG_PORT;
  40.   private String PG_USER;
  41.   private String PG_PASSWORD;
  42.   private String PG_DATABASE;
  43.   private boolean PG_STATUS;
  44.   
  45.   public boolean CONNECTION_OK = true;
  46.   public boolean CONNECTION_BAD = false;
  47.   
  48.   private boolean autoCommit = true;
  49.   private boolean readOnly = false;
  50.   
  51.   protected Driver this_driver;
  52.   private String this_url;
  53.   private String cursor = null; // The positioned update cursor name
  54.   
  55.   // These are new for v6.3, they determine the current protocol versions
  56.   // supported by this version of the driver. They are defined in
  57.   // src/include/libpq/pqcomm.h
  58.   protected static final int PG_PROTOCOL_LATEST_MAJOR = 1;
  59.   protected static final int PG_PROTOCOL_LATEST_MINOR = 0;
  60.   private static final int SM_DATABASE = 64;
  61.   private static final int SM_USER = 32;
  62.   private static final int SM_OPTIONS = 64;
  63.   private static final int SM_UNUSED = 64;
  64.   private static final int SM_TTY = 64;
  65.   
  66.   private static final int AUTH_REQ_OK       = 0;
  67.   private static final int AUTH_REQ_KRB4     = 1;
  68.   private static final int AUTH_REQ_KRB5     = 2;
  69.   private static final int AUTH_REQ_PASSWORD = 3;
  70.   private static final int AUTH_REQ_CRYPT    = 4;
  71.   
  72.   // New for 6.3, salt value for crypt authorisation
  73.   private String salt;
  74.   
  75.   // This is used by Field to cache oid -> names.
  76.   // It's here, because it's shared across this connection only.
  77.   // Hence it cannot be static within the Field class, because it would then
  78.   // be across all connections, which could be to different backends.
  79.   protected Hashtable fieldCache = new Hashtable();
  80.   
  81.   /**
  82.    * This is the current date style of the backend
  83.    */
  84.   protected int currentDateStyle;
  85.   
  86.   /**
  87.    * This defines the formats for dates, according to the various date styles.
  88.    *
  89.    * <p>There are two strings for each entry. The first is the string to search
  90.    * for in the datestyle message, and the second the format to use.
  91.    *
  92.    * <p>To add a new date style, work out the format. Then with psql running
  93.    * in the date style you wish to add, type: show datestyle;
  94.    *
  95.    * <p>eg:
  96.    * <br><pre>
  97.    * => show datestyle;
  98.    * NOTICE:  Datestyle is SQL with European conventions
  99.    *                       ^^^^^^^^^^^^^^^^^
  100.    * </pre>The marked part of the string is the first string below. The second
  101.    * is your format. If a style (like ISO) ignores the US/European variants,
  102.    * then you can ignore the "with" part of the string.
  103.    */
  104.   protected static final String dateStyles[] = {
  105.     "Postgres with European", "dd-MM-yyyy",
  106.     "Postgres with US", "MM-dd-yyyy",
  107.     "ISO", "yyyy-MM-dd",
  108.     "SQL with European", "dd/MM/yyyy",
  109.     "SQL with US", "MM/dd/yyyy",
  110.     "German", "dd.MM.yyyy"
  111.   };
  112.   
  113.   // Now handle notices as warnings, so things like "show" now work
  114.   protected SQLWarning firstWarning = null;
  115.   
  116.   /**
  117.    * Connect to a PostgreSQL database back end.
  118.    *
  119.    * <p><b>Important Notice</b>
  120.    *
  121.    * <br>Although this will connect to the database, user code should open
  122.    * the connection via the DriverManager.getConnection() methods only.
  123.    *
  124.    * <br>This should only be called from the postgresql.Driver class.
  125.    *
  126.    * @param host the hostname of the database back end
  127.    * @param port the port number of the postmaster process
  128.    * @param info a Properties[] thing of the user and password
  129.    * @param database the database to connect to
  130.    * @param u the URL of the connection
  131.    * @param d the Driver instantation of the connection
  132.    * @return a valid connection profile
  133.    * @exception SQLException if a database access error occurs
  134.    */
  135.   public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
  136.   {
  137.     // Throw an exception if the user or password properties are missing
  138.     // This occasionally occurs when the client uses the properties version
  139.     // of getConnection(), and is a common question on the email lists
  140.     if(info.getProperty("user")==null)
  141.       throw new SQLException("The user property is missing. It is mandatory.");
  142.     if(info.getProperty("password")==null)
  143.       throw new SQLException("The password property is missing. It is mandatory.");
  144.     
  145.     this_driver = d;
  146.     this_url = new String(url);
  147.     PG_DATABASE = new String(database);
  148.     PG_PASSWORD = new String(info.getProperty("password"));
  149.     PG_USER = new String(info.getProperty("user"));
  150.     PG_PORT = port;
  151.     PG_HOST = new String(host);
  152.     PG_STATUS = CONNECTION_BAD;
  153.     
  154.     // Now make the initial connection
  155.     try
  156.       {
  157. pg_stream = new PG_Stream(host, port);
  158.       } catch (ConnectException cex) {
  159. // Added by Peter Mount <peter@retep.org.uk>
  160. // ConnectException is thrown when the connection cannot be made.
  161. // we trap this an return a more meaningful message for the end user
  162. throw new SQLException ("Connection refused. Check that the hostname and port is correct, and that the postmaster is running with the -i flag, which enables TCP/IP networking.");
  163.       } catch (IOException e) {
  164. throw new SQLException ("Connection failed: " + e.toString());
  165.       }
  166.       
  167.       // Now we need to construct and send a startup packet
  168.       try
  169. {
  170.   // Ver 6.3 code
  171.   pg_stream.SendInteger(4+4+SM_DATABASE+SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY,4);
  172.   pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2);
  173.   pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2);
  174.   pg_stream.Send(database.getBytes(),SM_DATABASE);
  175.   
  176.   // This last send includes the unused fields
  177.   pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY);
  178.   
  179.   // now flush the startup packets to the backend
  180.   pg_stream.flush();
  181.   
  182.   // Now get the response from the backend, either an error message
  183.   // or an authentication request
  184.   int areq = -1; // must have a value here
  185.   do {
  186.     int beresp = pg_stream.ReceiveChar();
  187.     switch(beresp)
  188.       {
  189.       case 'E':
  190. // An error occured, so pass the error message to the
  191. // user.
  192. //
  193. // The most common one to be thrown here is:
  194. // "User authentication failed"
  195. //
  196. throw new SQLException(pg_stream.ReceiveString(4096));
  197.       case 'R':
  198. // Get the type of request
  199. areq = pg_stream.ReceiveIntegerR(4);
  200. // Get the password salt if there is one
  201. if(areq == AUTH_REQ_CRYPT) {
  202.   byte[] rst = new byte[2];
  203.   rst[0] = (byte)pg_stream.ReceiveChar();
  204.   rst[1] = (byte)pg_stream.ReceiveChar();
  205.   salt = new String(rst,0,2);
  206.   DriverManager.println("Salt="+salt);
  207. }
  208. // now send the auth packet
  209. switch(areq)
  210.   {
  211.   case AUTH_REQ_OK:
  212.     break;
  213.     
  214.   case AUTH_REQ_KRB4:
  215.     DriverManager.println("postgresql: KRB4");
  216.     throw new SQLException("Kerberos 4 not supported");
  217.     
  218.   case AUTH_REQ_KRB5:
  219.     DriverManager.println("postgresql: KRB5");
  220.     throw new SQLException("Kerberos 5 not supported");
  221.     
  222.   case AUTH_REQ_PASSWORD:
  223.     DriverManager.println("postgresql: PASSWORD");
  224.     pg_stream.SendInteger(5+PG_PASSWORD.length(),4);
  225.     pg_stream.Send(PG_PASSWORD.getBytes());
  226.     pg_stream.SendInteger(0,1);
  227.     pg_stream.flush();
  228.     break;
  229.     
  230.   case AUTH_REQ_CRYPT:
  231.     DriverManager.println("postgresql: CRYPT");
  232.     String crypted = UnixCrypt.crypt(salt,PG_PASSWORD);
  233.     pg_stream.SendInteger(5+crypted.length(),4);
  234.     pg_stream.Send(crypted.getBytes());
  235.     pg_stream.SendInteger(0,1);
  236.     pg_stream.flush();
  237.     break;
  238.     
  239.   default:
  240.     throw new SQLException("Authentication type "+areq+" not supported. Check that you have configured the pg_hba.conf file to include the client's IP address or Subnet, and is using a supported authentication scheme.");
  241.   }
  242. break;
  243.       default:
  244. throw new SQLException("error getting authentication request");
  245.       }
  246.     } while(areq != AUTH_REQ_OK);
  247.   
  248. } catch (IOException e) {
  249.   throw new SQLException("Connection failed: " + e.toString());
  250. }
  251. // Find out the date style by issuing the SQL: show datestyle
  252. // This actually issues a warning, and our own warning handling
  253. // code handles this itself.
  254. //
  255. // Also, this query replaced the NULL query issued to test the
  256. // connection.
  257. //
  258. clearWarnings();
  259. ExecSQL("show datestyle");
  260. // Initialise object handling
  261. initObjectTypes();
  262. // Mark the connection as ok, and cleanup
  263. clearWarnings();
  264. PG_STATUS = CONNECTION_OK;
  265.   }
  266.   
  267.   /**
  268.    * SQL statements without parameters are normally executed using
  269.    * Statement objects.  If the same SQL statement is executed many
  270.    * times, it is more efficient to use a PreparedStatement
  271.    *
  272.    * @return a new Statement object
  273.    * @exception SQLException passed through from the constructor
  274.    */
  275.   public java.sql.Statement createStatement() throws SQLException
  276.   {
  277.     return new Statement(this);
  278.   }
  279.   
  280.   /**
  281.    * A SQL statement with or without IN parameters can be pre-compiled
  282.    * and stored in a PreparedStatement object.  This object can then
  283.    * be used to efficiently execute this statement multiple times.
  284.    *
  285.    * <B>Note:</B> This method is optimized for handling parametric
  286.    * SQL statements that benefit from precompilation if the drivers
  287.    * supports precompilation.  PostgreSQL does not support precompilation.
  288.    * In this case, the statement is not sent to the database until the
  289.    * PreparedStatement is executed.  This has no direct effect on users;
  290.    * however it does affect which method throws certain SQLExceptions
  291.    *
  292.    * @param sql a SQL statement that may contain one or more '?' IN
  293.    * parameter placeholders
  294.    * @return a new PreparedStatement object containing the pre-compiled
  295.    * statement.
  296.    * @exception SQLException if a database access error occurs.
  297.    */
  298.   public java.sql.PreparedStatement prepareStatement(String sql) throws SQLException
  299.   {
  300.     return new PreparedStatement(this, sql);
  301.   }
  302.   
  303.   /**
  304.    * A SQL stored procedure call statement is handled by creating a
  305.    * CallableStatement for it.  The CallableStatement provides methods
  306.    * for setting up its IN and OUT parameters and methods for executing
  307.    * it.
  308.    *
  309.    * <B>Note:</B> This method is optimised for handling stored procedure
  310.    * call statements.  Some drivers may send the call statement to the
  311.    * database when the prepareCall is done; others may wait until the
  312.    * CallableStatement is executed.  This has no direct effect on users;
  313.    * however, it does affect which method throws certain SQLExceptions
  314.    *
  315.    * @param sql a SQL statement that may contain one or more '?' parameter
  316.    * placeholders.  Typically this statement is a JDBC function call
  317.    * escape string.
  318.    * @return a new CallableStatement object containing the pre-compiled
  319.    * SQL statement
  320.    * @exception SQLException if a database access error occurs
  321.    */
  322.   public java.sql.CallableStatement prepareCall(String sql) throws SQLException
  323.   {
  324.     throw new SQLException("Callable Statements are not supported at this time");
  325.     // return new CallableStatement(this, sql);
  326.   }
  327.   
  328.   /**
  329.    * A driver may convert the JDBC sql grammar into its system's
  330.    * native SQL grammar prior to sending it; nativeSQL returns the
  331.    * native form of the statement that the driver would have sent.
  332.    *
  333.    * @param sql a SQL statement that may contain one or more '?'
  334.    * parameter placeholders
  335.    * @return the native form of this statement
  336.    * @exception SQLException if a database access error occurs
  337.    */
  338.   public String nativeSQL(String sql) throws SQLException
  339.   {
  340.     return sql;
  341.   }
  342.   
  343.   /**
  344.    * If a connection is in auto-commit mode, than all its SQL
  345.    * statements will be executed and committed as individual
  346.    * transactions.  Otherwise, its SQL statements are grouped
  347.    * into transactions that are terminated by either commit()
  348.    * or rollback().  By default, new connections are in auto-
  349.    * commit mode.  The commit occurs when the statement completes
  350.    * or the next execute occurs, whichever comes first.  In the
  351.    * case of statements returning a ResultSet, the statement
  352.    * completes when the last row of the ResultSet has been retrieved
  353.    * or the ResultSet has been closed.  In advanced cases, a single
  354.    * statement may return multiple results as well as output parameter
  355.    * values.  Here the commit occurs when all results and output param
  356.    * values have been retrieved.
  357.    *
  358.    * @param autoCommit - true enables auto-commit; false disables it
  359.    * @exception SQLException if a database access error occurs
  360.    */
  361.   public void setAutoCommit(boolean autoCommit) throws SQLException
  362.   {
  363.     if (this.autoCommit == autoCommit)
  364.       return;
  365.     if (autoCommit)
  366.       ExecSQL("end");
  367.     else
  368.       ExecSQL("begin");
  369.     this.autoCommit = autoCommit;
  370.   }
  371.   
  372.   /**
  373.    * gets the current auto-commit state
  374.    * 
  375.    * @return Current state of the auto-commit mode
  376.    * @exception SQLException (why?)
  377.    * @see setAutoCommit
  378.    */
  379.   public boolean getAutoCommit() throws SQLException
  380.   {
  381.     return this.autoCommit;
  382.   }
  383.   
  384.   /**
  385.    * The method commit() makes all changes made since the previous
  386.    * commit/rollback permanent and releases any database locks currently
  387.    * held by the Connection.  This method should only be used when
  388.    * auto-commit has been disabled.  (If autoCommit == true, then we
  389.    * just return anyhow)
  390.    *
  391.    * @exception SQLException if a database access error occurs
  392.    * @see setAutoCommit
  393.    */
  394.   public void commit() throws SQLException
  395.   {
  396.     if (autoCommit)
  397.       return;
  398.     ExecSQL("commit");
  399.     autoCommit = true;
  400.     ExecSQL("begin");
  401.     autoCommit = false;
  402.   }
  403.   
  404.   /**
  405.    * The method rollback() drops all changes made since the previous
  406.    * commit/rollback and releases any database locks currently held by
  407.    * the Connection. 
  408.    *
  409.    * @exception SQLException if a database access error occurs
  410.    * @see commit
  411.    */
  412.   public void rollback() throws SQLException
  413.   {
  414.     if (autoCommit)
  415.       return;
  416.     ExecSQL("rollback");
  417.     autoCommit = true;
  418.     ExecSQL("begin");
  419.     autoCommit = false;
  420.   }
  421.   
  422.   /**
  423.    * In some cases, it is desirable to immediately release a Connection's
  424.    * database and JDBC resources instead of waiting for them to be
  425.    * automatically released (cant think why off the top of my head)
  426.    *
  427.    * <B>Note:</B> A Connection is automatically closed when it is
  428.    * garbage collected.  Certain fatal errors also result in a closed
  429.    * connection.
  430.    *
  431.    * @exception SQLException if a database access error occurs
  432.    */
  433.   public void close() throws SQLException
  434.   {
  435.     if (pg_stream != null)
  436.       {
  437. try
  438.   {
  439.     pg_stream.close();
  440.   } catch (IOException e) {}
  441.   pg_stream = null;
  442.       }
  443.   }
  444.   
  445.   /**
  446.    * Tests to see if a Connection is closed
  447.    *
  448.    * @return the status of the connection
  449.    * @exception SQLException (why?)
  450.    */
  451.   public boolean isClosed() throws SQLException
  452.   {
  453.     return (pg_stream == null);
  454.   }
  455.   
  456.   /**
  457.    * A connection's database is able to provide information describing
  458.    * its tables, its supported SQL grammar, its stored procedures, the
  459.    * capabilities of this connection, etc.  This information is made
  460.    * available through a DatabaseMetaData object.
  461.    *
  462.    * @return a DatabaseMetaData object for this connection
  463.    * @exception SQLException if a database access error occurs
  464.    */
  465.   public java.sql.DatabaseMetaData getMetaData() throws SQLException
  466.   {
  467.     if(metadata==null)
  468.       metadata = new DatabaseMetaData(this);
  469.     return metadata;
  470.   }
  471.   
  472.   /**
  473.    * You can put a connection in read-only mode as a hunt to enable
  474.    * database optimizations
  475.    *
  476.    * <B>Note:</B> setReadOnly cannot be called while in the middle
  477.    * of a transaction
  478.    *
  479.    * @param readOnly - true enables read-only mode; false disables it
  480.    * @exception SQLException if a database access error occurs
  481.    */
  482.   public void setReadOnly (boolean readOnly) throws SQLException
  483.   {
  484.     this.readOnly = readOnly;
  485.   }
  486.   
  487.   /**
  488.    * Tests to see if the connection is in Read Only Mode.  Note that
  489.    * we cannot really put the database in read only mode, but we pretend
  490.    * we can by returning the value of the readOnly flag
  491.    *
  492.    * @return true if the connection is read only
  493.    * @exception SQLException if a database access error occurs
  494.    */
  495.   public boolean isReadOnly() throws SQLException
  496.   {
  497.     return readOnly;
  498.   }
  499.   
  500.   /**
  501.    * A sub-space of this Connection's database may be selected by
  502.    * setting a catalog name.  If the driver does not support catalogs,
  503.    * it will silently ignore this request
  504.    *
  505.    * @exception SQLException if a database access error occurs
  506.    */
  507.   public void setCatalog(String catalog) throws SQLException
  508.   {
  509.     // No-op
  510.   }
  511.   
  512.   /**
  513.    * Return the connections current catalog name, or null if no
  514.    * catalog name is set, or we dont support catalogs.
  515.    *
  516.    * @return the current catalog name or null
  517.    * @exception SQLException if a database access error occurs
  518.    */
  519.   public String getCatalog() throws SQLException
  520.   {
  521.     return null;
  522.   }
  523.   
  524.   /**
  525.    * You can call this method to try to change the transaction
  526.    * isolation level using one of the TRANSACTION_* values.  
  527.    *
  528.    * <B>Note:</B> setTransactionIsolation cannot be called while
  529.    * in the middle of a transaction
  530.    *
  531.    * @param level one of the TRANSACTION_* isolation values with
  532.    * the exception of TRANSACTION_NONE; some databases may
  533.    * not support other values
  534.    * @exception SQLException if a database access error occurs
  535.    * @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
  536.    */
  537.   public void setTransactionIsolation(int level) throws SQLException
  538.   {
  539.     throw new SQLException("Transaction Isolation Levels are not implemented");
  540.   }
  541.   
  542.   /**
  543.    * Get this Connection's current transaction isolation mode.
  544.    * 
  545.    * @return the current TRANSACTION_* mode value
  546.    * @exception SQLException if a database access error occurs
  547.    */
  548.   public int getTransactionIsolation() throws SQLException
  549.   {
  550.     return java.sql.Connection.TRANSACTION_SERIALIZABLE;
  551.   }
  552.   
  553.   /**
  554.    * The first warning reported by calls on this Connection is
  555.    * returned.
  556.    *
  557.    * <B>Note:</B> Sebsequent warnings will be changed to this
  558.    * SQLWarning
  559.    *
  560.    * @return the first SQLWarning or null
  561.    * @exception SQLException if a database access error occurs
  562.    */
  563.   public SQLWarning getWarnings() throws SQLException
  564.   {
  565.     return firstWarning;
  566.   }
  567.   
  568.   /**
  569.    * After this call, getWarnings returns null until a new warning
  570.    * is reported for this connection.
  571.    *
  572.    * @exception SQLException if a database access error occurs
  573.    */
  574.   public void clearWarnings() throws SQLException
  575.   {
  576.     firstWarning = null;
  577.   }
  578.   
  579.   // **********************************************************
  580.   // END OF PUBLIC INTERFACE
  581.   // **********************************************************
  582.   
  583.   /**
  584.    * This adds a warning to the warning chain.
  585.    * @param msg message to add
  586.    */
  587.   public void addWarning(String msg)
  588.   {
  589.     DriverManager.println(msg);
  590.     
  591.     // Add the warning to the chain
  592.     if(firstWarning!=null)
  593.       firstWarning.setNextWarning(new SQLWarning(msg));
  594.     else
  595.       firstWarning = new SQLWarning(msg);
  596.     
  597.     // Now check for some specific messages
  598.     
  599.     // This is generated by the SQL "show datestyle"
  600.     if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) {
  601.       // 13 is the length off "DateStyle is "
  602.       msg = msg.substring(msg.indexOf("DateStyle is ")+13);
  603.       for(int i=0;i<dateStyles.length;i+=2)
  604. if(msg.startsWith(dateStyles[i]))
  605.   currentDateStyle=i+1; // this is the index of the format
  606.     }
  607.   }
  608.   
  609.   /**
  610.    * @return the date format for the current date style of the backend
  611.    */
  612.   public String getDateStyle()
  613.   {
  614.     return dateStyles[currentDateStyle];
  615.   }
  616.   
  617.   /**
  618.    * Send a query to the backend.  Returns one of the ResultSet
  619.    * objects.
  620.    *
  621.    * <B>Note:</B> there does not seem to be any method currently
  622.    * in existance to return the update count.
  623.    *
  624.    * @param sql the SQL statement to be executed
  625.    * @return a ResultSet holding the results
  626.    * @exception SQLException if a database error occurs
  627.    */
  628.   public ResultSet ExecSQL(String sql) throws SQLException
  629.   {
  630.     // added Oct 7 1998 to give us thread safety.
  631.     synchronized(pg_stream) {
  632.       
  633.     Field[] fields = null;
  634.     Vector tuples = new Vector();
  635.     byte[] buf = new byte[sql.length()];
  636.     int fqp = 0;
  637.     boolean hfr = false;
  638.     String recv_status = null, msg;
  639.     SQLException final_error = null;
  640.     
  641.     if (sql.length() > 8192)
  642.       throw new SQLException("SQL Statement too long: " + sql);
  643.     try
  644.       {
  645. pg_stream.SendChar('Q');
  646. buf = sql.getBytes();
  647. pg_stream.Send(buf);
  648. pg_stream.SendChar(0);
  649. pg_stream.flush();
  650.       } catch (IOException e) {
  651. throw new SQLException("I/O Error: " + e.toString());
  652.       }
  653.       
  654.       while (!hfr || fqp > 0)
  655. {
  656.   Object tup=null; // holds rows as they are recieved
  657.   
  658.   int c = pg_stream.ReceiveChar();
  659.   
  660.   switch (c)
  661.     {
  662.     case 'A': // Asynchronous Notify
  663.       int pid = pg_stream.ReceiveInteger(4);
  664.       msg = pg_stream.ReceiveString(8192);
  665.       break;
  666.     case 'B': // Binary Data Transfer
  667.       if (fields == null)
  668. throw new SQLException("Tuple received before MetaData");
  669.       tup = pg_stream.ReceiveTuple(fields.length, true);
  670.       // This implements Statement.setMaxRows()
  671.       if(maxrows==0 || tuples.size()<maxrows)
  672. tuples.addElement(tup);
  673.       break;
  674.     case 'C': // Command Status
  675.       recv_status = pg_stream.ReceiveString(8192);
  676.       if (fields != null)
  677. hfr = true;
  678.       else
  679. {
  680.   try
  681.     {
  682.       pg_stream.SendChar('Q');
  683.       pg_stream.SendChar(' ');
  684.       pg_stream.SendChar(0);
  685.       pg_stream.flush();
  686.     } catch (IOException e) {
  687.       throw new SQLException("I/O Error: " + e.toString());
  688.     }
  689.     fqp++;
  690. }
  691.       break;
  692.     case 'D': // Text Data Transfer
  693.       if (fields == null)
  694. throw new SQLException("Tuple received before MetaData");
  695.       tup = pg_stream.ReceiveTuple(fields.length, false);
  696.       // This implements Statement.setMaxRows()
  697.       if(maxrows==0 || tuples.size()<maxrows)
  698. tuples.addElement(tup);
  699.       break;
  700.     case 'E': // Error Message
  701.       msg = pg_stream.ReceiveString(4096);
  702.       final_error = new SQLException(msg);
  703.       hfr = true;
  704.       break;
  705.     case 'I': // Empty Query
  706.       int t = pg_stream.ReceiveChar();
  707.       
  708.       if (t != 0)
  709. throw new SQLException("Garbled Data");
  710.       if (fqp > 0)
  711. fqp--;
  712.       if (fqp == 0)
  713. hfr = true;
  714.       break;
  715.     case 'N': // Error Notification
  716.       addWarning(pg_stream.ReceiveString(4096));
  717.       break;
  718.     case 'P': // Portal Name
  719.       String pname = pg_stream.ReceiveString(8192);
  720.       break;
  721.     case 'T': // MetaData Field Description
  722.       if (fields != null)
  723. throw new SQLException("Cannot handle multiple result groups");
  724.       fields = ReceiveFields();
  725.       break;
  726.     default:
  727.       throw new SQLException("Unknown Response Type: " + (char)c);
  728.     }
  729. }
  730.       if (final_error != null)
  731. throw final_error;
  732.       return new ResultSet(this, fields, tuples, recv_status, 1);
  733.     }
  734.   }
  735.   
  736.   /**
  737.    * Receive the field descriptions from the back end
  738.    *
  739.    * @return an array of the Field object describing the fields
  740.    * @exception SQLException if a database error occurs
  741.    */
  742.   private Field[] ReceiveFields() throws SQLException
  743.   {
  744.     int nf = pg_stream.ReceiveIntegerR(2), i;
  745.     Field[] fields = new Field[nf];
  746.     
  747.     for (i = 0 ; i < nf ; ++i)
  748.       {
  749. String typname = pg_stream.ReceiveString(8192);
  750. int typid = pg_stream.ReceiveIntegerR(4);
  751. int typlen = pg_stream.ReceiveIntegerR(2);
  752. fields[i] = new Field(this, typname, typid, typlen);
  753.       }
  754.     return fields;
  755.   }
  756.   
  757.   /**
  758.    * In SQL, a result table can be retrieved through a cursor that
  759.    * is named.  The current row of a result can be updated or deleted
  760.    * using a positioned update/delete statement that references the
  761.    * cursor name.
  762.    *
  763.    * We support one cursor per connection.
  764.    *
  765.    * setCursorName sets the cursor name.
  766.    *
  767.    * @param cursor the cursor name
  768.    * @exception SQLException if a database access error occurs
  769.    */
  770.   public void setCursorName(String cursor) throws SQLException
  771.   {
  772.     this.cursor = cursor;
  773.   }
  774.   
  775.   /**
  776.    * getCursorName gets the cursor name.
  777.    *
  778.    * @return the current cursor name
  779.    * @exception SQLException if a database access error occurs
  780.    */
  781.   public String getCursorName() throws SQLException
  782.   {
  783.     return cursor;
  784.   }
  785.   
  786.   /**
  787.    * We are required to bring back certain information by
  788.    * the DatabaseMetaData class.  These functions do that.
  789.    *
  790.    * Method getURL() brings back the URL (good job we saved it)
  791.    *
  792.    * @return the url
  793.    * @exception SQLException just in case...
  794.    */
  795.   public String getURL() throws SQLException
  796.   {
  797.     return this_url;
  798.   }
  799.   
  800.   /**
  801.    * Method getUserName() brings back the User Name (again, we
  802.    * saved it)
  803.    *
  804.    * @return the user name
  805.    * @exception SQLException just in case...
  806.    */
  807.   public String getUserName() throws SQLException
  808.   {
  809.     return PG_USER;
  810.   }
  811.   
  812.   /**
  813.    * This returns the Fastpath API for the current connection.
  814.    *
  815.    * <p><b>NOTE:</b> This is not part of JDBC, but allows access to
  816.    * functions on the postgresql backend itself.
  817.    *
  818.    * <p>It is primarily used by the LargeObject API
  819.    *
  820.    * <p>The best way to use this is as follows:
  821.    *
  822.    * <p><pre>
  823.    * import postgresql.fastpath.*;
  824.    * ...
  825.    * Fastpath fp = ((postgresql.Connection)myconn).getFastpathAPI();
  826.    * </pre>
  827.    *
  828.    * <p>where myconn is an open Connection to postgresql.
  829.    *
  830.    * @return Fastpath object allowing access to functions on the postgresql
  831.    * backend.
  832.    * @exception SQLException by Fastpath when initialising for first time
  833.    */
  834.   public Fastpath getFastpathAPI() throws SQLException
  835.   {
  836.     if(fastpath==null)
  837.       fastpath = new Fastpath(this,pg_stream);
  838.     return fastpath;
  839.   }
  840.   
  841.   // This holds a reference to the Fastpath API if already open
  842.   private Fastpath fastpath = null;
  843.   
  844.   /**
  845.    * This returns the LargeObject API for the current connection.
  846.    *
  847.    * <p><b>NOTE:</b> This is not part of JDBC, but allows access to
  848.    * functions on the postgresql backend itself.
  849.    *
  850.    * <p>The best way to use this is as follows:
  851.    *
  852.    * <p><pre>
  853.    * import postgresql.largeobject.*;
  854.    * ...
  855.    * LargeObjectManager lo = ((postgresql.Connection)myconn).getLargeObjectAPI();
  856.    * </pre>
  857.    *
  858.    * <p>where myconn is an open Connection to postgresql.
  859.    *
  860.    * @return LargeObject object that implements the API
  861.    * @exception SQLException by LargeObject when initialising for first time
  862.    */
  863.   public LargeObjectManager getLargeObjectAPI() throws SQLException
  864.   {
  865.     if(largeobject==null)
  866.       largeobject = new LargeObjectManager(this);
  867.     return largeobject;
  868.   }
  869.   
  870.   // This holds a reference to the LargeObject API if already open
  871.   private LargeObjectManager largeobject = null;
  872.   
  873.   /**
  874.    * This method is used internally to return an object based around
  875.    * postgresql's more unique data types.
  876.    *
  877.    * <p>It uses an internal Hashtable to get the handling class. If the
  878.    * type is not supported, then an instance of postgresql.util.PGobject
  879.    * is returned.
  880.    *
  881.    * You can use the getValue() or setValue() methods to handle the returned
  882.    * object. Custom objects can have their own methods.
  883.    *
  884.    * In 6.4, this is extended to use the postgresql.util.Serialize class to
  885.    * allow the Serialization of Java Objects into the database without using
  886.    * Blobs. Refer to that class for details on how this new feature works.
  887.    *
  888.    * @return PGobject for this type, and set to value
  889.    * @exception SQLException if value is not correct for this type
  890.    * @see postgresql.util.Serialize
  891.    */
  892.   protected Object getObject(String type,String value) throws SQLException
  893.   {
  894.     try {
  895.       Object o = objectTypes.get(type);
  896.       
  897.       // If o is null, then the type is unknown, so check to see if type
  898.       // is an actual table name. If it does, see if a Class is known that
  899.       // can handle it
  900.       if(o == null) {
  901. Serialize ser = new Serialize(this,type);
  902. objectTypes.put(type,ser);
  903. return ser.fetch(Integer.parseInt(value));
  904.       }
  905.       
  906.       // If o is not null, and it is a String, then its a class name that
  907.       // extends PGobject.
  908.       //
  909.       // This is used to implement the postgresql unique types (like lseg,
  910.       // point, etc).
  911.       if(o instanceof String) {
  912. // 6.3 style extending PG_Object
  913. PGobject obj = null;
  914. obj = (PGobject)(Class.forName((String)o).newInstance());
  915. obj.setType(type);
  916. obj.setValue(value);
  917. return (Object)obj;
  918.       } else {
  919. // If it's an object, it should be an instance of our Serialize class
  920. // If so, then call it's fetch method.
  921. if(o instanceof Serialize)
  922.   return ((Serialize)o).fetch(Integer.parseInt(value));
  923.       }
  924.     } catch(SQLException sx) {
  925.       // rethrow the exception. Done because we capture any others next
  926.       sx.fillInStackTrace();
  927.       throw sx;
  928.     } catch(Exception ex) {
  929.       throw new SQLException("Failed to create object for "+type+": "+ex);
  930.     }
  931.     
  932.     // should never be reached
  933.     return null;
  934.   }
  935.   
  936.   /**
  937.    * This stores an object into the database.
  938.    * @param o Object to store
  939.    * @return OID of the new rectord
  940.    * @exception SQLException if value is not correct for this type
  941.    * @see postgresql.util.Serialize
  942.    */
  943.   protected int putObject(Object o) throws SQLException
  944.   {
  945.     try {
  946.       String type = o.getClass().getName();
  947.       Object x = objectTypes.get(type);
  948.       
  949.       // If x is null, then the type is unknown, so check to see if type
  950.       // is an actual table name. If it does, see if a Class is known that
  951.       // can handle it
  952.       if(x == null) {
  953. Serialize ser = new Serialize(this,type);
  954. objectTypes.put(type,ser);
  955. return ser.store(o);
  956.       }
  957.       
  958.       // If it's an object, it should be an instance of our Serialize class
  959.       // If so, then call it's fetch method.
  960.       if(x instanceof Serialize)
  961. return ((Serialize)x).store(o);
  962.       
  963.       // Thow an exception because the type is unknown
  964.       throw new SQLException("The object could not be stored. Check that any tables required have already been created in the database.");
  965.       
  966.     } catch(SQLException sx) {
  967.       // rethrow the exception. Done because we capture any others next
  968.       sx.fillInStackTrace();
  969.       throw sx;
  970.     } catch(Exception ex) {
  971.       throw new SQLException("Failed to store object: "+ex);
  972.     }
  973.   }
  974.   
  975.   /**
  976.    * This allows client code to add a handler for one of postgresql's
  977.    * more unique data types.
  978.    *
  979.    * <p><b>NOTE:</b> This is not part of JDBC, but an extension.
  980.    *
  981.    * <p>The best way to use this is as follows:
  982.    *
  983.    * <p><pre>
  984.    * ...
  985.    * ((postgresql.Connection)myconn).addDataType("mytype","my.class.name");
  986.    * ...
  987.    * </pre>
  988.    *
  989.    * <p>where myconn is an open Connection to postgresql.
  990.    *
  991.    * <p>The handling class must extend postgresql.util.PGobject
  992.    *
  993.    * @see postgresql.util.PGobject
  994.    */
  995.   public void addDataType(String type,String name)
  996.   {
  997.     objectTypes.put(type,name);
  998.   }
  999.   
  1000.   // This holds the available types
  1001.   private Hashtable objectTypes = new Hashtable();
  1002.   
  1003.   // This array contains the types that are supported as standard.
  1004.   //
  1005.   // The first entry is the types name on the database, the second
  1006.   // the full class name of the handling class.
  1007.   //
  1008.   private static final String defaultObjectTypes[][] = {
  1009.     {"box", "postgresql.geometric.PGbox"},
  1010.     {"circle", "postgresql.geometric.PGcircle"},
  1011.     {"line", "postgresql.geometric.PGline"},
  1012.     {"lseg", "postgresql.geometric.PGlseg"},
  1013.     {"path", "postgresql.geometric.PGpath"},
  1014.     {"point", "postgresql.geometric.PGpoint"},
  1015.     {"polygon", "postgresql.geometric.PGpolygon"},
  1016.     {"money", "postgresql.util.PGmoney"}
  1017.   };
  1018.   
  1019.   // This initialises the objectTypes hashtable
  1020.   private void initObjectTypes()
  1021.   {
  1022.     for(int i=0;i<defaultObjectTypes.length;i++)
  1023.       objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]);
  1024.   }
  1025. }
  1026. // ***********************************************************************