New stuff from Peter Mount for jdbc.
authorBruce Momjian
Thu, 3 Sep 1998 02:31:38 +0000 (02:31 +0000)
committerBruce Momjian
Thu, 3 Sep 1998 02:31:38 +0000 (02:31 +0000)
src/interfaces/jdbc/example/psql.java
src/interfaces/jdbc/postgresql/Connection.java
src/interfaces/jdbc/postgresql/DatabaseMetaData.java
src/interfaces/jdbc/postgresql/Driver.java
src/interfaces/jdbc/postgresql/PG_Stream.java
src/interfaces/jdbc/postgresql/PreparedStatement.java
src/interfaces/jdbc/postgresql/ResultSet.java
src/interfaces/jdbc/postgresql/ResultSetMetaData.java

index adad24f4d08e4eedeec8c0eadf3febc76a9af3b1..2ad18b198bf53a5ad765c760821c50d9e5c73221 100644 (file)
@@ -123,7 +123,7 @@ public class psql
    if(rs.wasNull())
      System.out.print("{null}"+(i
    else
-     System.out.print(rs.getObject(i).toString()+(i
+     System.out.print(o.toString()+(i
       }
     }
     
index 7c565e145fa05d34d35bc95442b480e66e7a886d..31f6e11980eef03bc0aa8a5e1db32e4109ccc136 100644 (file)
@@ -34,6 +34,9 @@ public class Connection implements java.sql.Connection
   // This is set by postgresql.Statement.setMaxRows()
   protected int maxrows = 0;       // maximum no. of rows; 0 = unlimited
   
+  // This is a cache of the DatabaseMetaData instance for this connection
+  protected DatabaseMetaData metadata;
+  
   private String PG_HOST;
   private int PG_PORT;
   private String PG_USER;
@@ -44,17 +47,6 @@ public class Connection implements java.sql.Connection
   public boolean CONNECTION_OK = true;
   public boolean CONNECTION_BAD = false;
   
-  //private static final int STARTUP_LEN  = 288;   // Length of a startup packet
-  
-  // These are defined in src/include/libpq/pqcomm.h
-  //private int STARTUP_CODE = STARTUP_USER;
-  //private static final int STARTUP_USER = 7; // User auth
-  //private static final int STARTUP_KRB4 = 10;    // Kerberos 4 (unused)
-  //private static final int STARTUP_KRB5 = 11;    // Kerberos 5 (unused)
-  //private static final int STARTUP_HBA  = 12;    // Host Based
-  //private static final int STARTUP_NONE = 13;    // Unauthenticated (unused)
-  //private static final int STARTUP_PASS = 14;    // Password auth
-  
   private boolean autoCommit = true;
   private boolean readOnly = false;
   
@@ -88,12 +80,6 @@ public class Connection implements java.sql.Connection
   // be across all connections, which could be to different backends.
   protected Hashtable fieldCache = new Hashtable();
   
-  // This is used by Field to cache oid -> names.
-  // It's here, because it's shared across this connection only.
-  // Hence it cannot be static within the Field class, because it would then
-  // be across all connections, which could be to different backends.
-  protected Hashtable fieldCache = new Hashtable();
-  
   /**
    * This is the current date style of the backend
    */
@@ -150,8 +136,6 @@ public class Connection implements java.sql.Connection
    */
   public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
   {
-    //int len = STARTUP_LEN;   // Length of a startup packet
-    
     // Throw an exception if the user or password properties are missing
     // This occasionally occurs when the client uses the properties version
     // of getConnection(), and is a common question on the email lists
@@ -169,30 +153,15 @@ public class Connection implements java.sql.Connection
     PG_HOST = new String(host);
     PG_STATUS = CONNECTION_BAD;
     
-    // Pre 6.3 code
-    // This handles the auth property. Any value begining with p enables
-    // password authentication, while anything begining with i enables
-    // ident (RFC 1413) authentication. Any other values default to trust.
-    //
-    // Also, the postgresql.auth system property can be used to change the
-    // local default, if the auth property is not present.
-    //
-    //String auth = info.getProperty("auth",System.getProperty("postgresql.auth","trust")).toLowerCase();
-    //if(auth.startsWith("p")) {
-    //// Password authentication
-    //STARTUP_CODE=STARTUP_PASS;
-    //} else if(auth.startsWith("i")) {
-    //// Ident (RFC 1413) authentication
-    //STARTUP_CODE=STARTUP_HBA;
-    //} else {
-    //// Anything else defaults to trust authentication
-    //STARTUP_CODE=STARTUP_USER;
-    //}
-    
     // Now make the initial connection
     try
       {
    pg_stream = new PG_Stream(host, port);
+      } catch (ConnectException cex) {
+   // Added by Peter Mount 
+   // ConnectException is thrown when the connection cannot be made.
+   // we trap this an return a more meaningful message for the end user
+   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.");
       } catch (IOException e) {
    throw new SQLException ("Connection failed: " + e.toString());
       }
@@ -200,30 +169,17 @@ public class Connection implements java.sql.Connection
       // Now we need to construct and send a startup packet
       try
    {
-     // Pre 6.3 code
-     //pg_stream.SendInteger(len, 4);          len -= 4;
-     //pg_stream.SendInteger(STARTUP_CODE, 4);     len -= 4;
-     //pg_stream.Send(database.getBytes(), 64);    len -= 64;
-     //pg_stream.Send(PG_USER.getBytes(), len);
-     //
-     //// Send the password packet if required
-     //if(STARTUP_CODE == STARTUP_PASS) {
-     //len=STARTUP_LEN;
-     //pg_stream.SendInteger(len, 4);          len -= 4;
-     //pg_stream.SendInteger(STARTUP_PASS, 4);     len -= 4;
-     //pg_stream.Send(PG_USER.getBytes(), PG_USER.length());
-     //len-=PG_USER.length();
-     //pg_stream.SendInteger(0,1);         len -= 1;
-     //pg_stream.Send(PG_PASSWORD.getBytes(), len);
-     //}
-     
      // Ver 6.3 code
      pg_stream.SendInteger(4+4+SM_DATABASE+SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY,4);
      pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2);
      pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2);
      pg_stream.Send(database.getBytes(),SM_DATABASE);
+     
+     // This last send includes the unused fields
      pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY);
-     // The last send includes the unused fields
+     
+     // now flush the startup packets to the backend
+     pg_stream.flush();
      
      // Now get the response from the backend, either an error message
      // or an authentication request
@@ -233,6 +189,12 @@ public class Connection implements java.sql.Connection
        switch(beresp)
          {
          case 'E':
+       // An error occured, so pass the error message to the
+       // user.
+       //
+       // The most common one to be thrown here is:
+       // "User authentication failed"
+       //
        throw new SQLException(pg_stream.ReceiveString(4096));
        
          case 'R':
@@ -267,7 +229,7 @@ public class Connection implements java.sql.Connection
            pg_stream.SendInteger(5+PG_PASSWORD.length(),4);
            pg_stream.Send(PG_PASSWORD.getBytes());
            pg_stream.SendInteger(0,1);
-           //pg_stream.SendPacket(PG_PASSWORD.getBytes());
+           pg_stream.flush();
            break;
            
          case AUTH_REQ_CRYPT:
@@ -276,11 +238,11 @@ public class Connection implements java.sql.Connection
            pg_stream.SendInteger(5+crypted.length(),4);
            pg_stream.Send(crypted.getBytes());
            pg_stream.SendInteger(0,1);
-           //pg_stream.SendPacket(UnixCrypt.crypt(salt,PG_PASSWORD).getBytes());
+           pg_stream.flush();
            break;
            
          default:
-           throw new SQLException("Authentication type "+areq+" not supported");
+           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.");
          }
        break;
        
@@ -511,7 +473,9 @@ public class Connection implements java.sql.Connection
    */
   public java.sql.DatabaseMetaData getMetaData() throws SQLException
   {
-    return new DatabaseMetaData(this);
+    if(metadata==null)
+      metadata = new DatabaseMetaData(this);
+    return metadata;
   }
   
   /**
@@ -631,8 +595,6 @@ public class Connection implements java.sql.Connection
    */
   public void addWarning(String msg)
   {
-    //PrintStream log = DriverManager.getLogStream();
-    //if(log!=null) 
     DriverManager.println(msg);
     
     // Add the warning to the chain
@@ -691,6 +653,7 @@ public class Connection implements java.sql.Connection
    buf = sql.getBytes();
    pg_stream.Send(buf);
    pg_stream.SendChar(0);
+   pg_stream.flush();
       } catch (IOException e) {
    throw new SQLException("I/O Error: " + e.toString());
       }
@@ -726,6 +689,7 @@ public class Connection implements java.sql.Connection
              pg_stream.SendChar('Q');
              pg_stream.SendChar(' ');
              pg_stream.SendChar(0);
+             pg_stream.flush();
            } catch (IOException e) {
              throw new SQLException("I/O Error: " + e.toString());
            }
@@ -964,6 +928,8 @@ public class Connection implements java.sql.Connection
      return ((Serialize)o).fetch(Integer.parseInt(value));
       }
     } catch(SQLException sx) {
+      // rethrow the exception. Done because we capture any others next
+      sx.fillInStackTrace();
       throw sx;
     } catch(Exception ex) {
       throw new SQLException("Failed to create object for "+type+": "+ex);
@@ -999,14 +965,17 @@ public class Connection implements java.sql.Connection
       // If so, then call it's fetch method.
       if(x instanceof Serialize)
    return ((Serialize)x).store(o);
+      
+      // Thow an exception because the type is unknown
+      throw new SQLException("The object could not be stored. Check that any tables required have already been created in the database.");
+      
     } catch(SQLException sx) {
+      // rethrow the exception. Done because we capture any others next
+      sx.fillInStackTrace();
       throw sx;
     } catch(Exception ex) {
       throw new SQLException("Failed to store object: "+ex);
     }
-    
-    // should never be reached
-    return 0;
   }
   
   /**
@@ -1045,10 +1014,12 @@ public class Connection implements java.sql.Connection
   private static final String defaultObjectTypes[][] = {
     {"box",    "postgresql.geometric.PGbox"},
     {"circle", "postgresql.geometric.PGcircle"},
+    {"line",   "postgresql.geometric.PGline"},
     {"lseg",   "postgresql.geometric.PGlseg"},
     {"path",   "postgresql.geometric.PGpath"},
     {"point",  "postgresql.geometric.PGpoint"},
-    {"polygon",    "postgresql.geometric.PGpolygon"}
+    {"polygon",    "postgresql.geometric.PGpolygon"},
+    {"money",  "postgresql.util.PGmoney"}
   };
   
   // This initialises the objectTypes hashtable
index bfcfc6f7cf62923b8ff3ed28007fc4835b2f31ed..da1cb52962ddd60a5a8843bbbf3982a34018820f 100644 (file)
@@ -37,6 +37,9 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
   static final int iInt4Oid = 23;  // OID for int4
   static final int VARHDRSZ =  4;  // length for int4
   
+  // This is a default value for remarks
+  private static final byte defaultRemarks[]="no remarks".getBytes();
+  
   public DatabaseMetaData(Connection conn)
   {
     this.connection = conn;
@@ -170,7 +173,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    */
   public String getDatabaseProductVersion() throws SQLException
   {
-    return ("6.3");
+    return ("6.4");
   }
   
   /**
@@ -1473,39 +1476,37 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     Field f[] = new Field[8];
     ResultSet r;   // ResultSet for the SQL query that we need to do
     Vector v = new Vector();       // The new ResultSet tuple stuff
-    String remarks = new String("no remarks");
     
-    f[0] = new Field(connection, new String("PROCEDURE_CAT"), iVarcharOid, 32);
-    f[1] = new Field(connection, new String("PROCEDURE_SCHEM"), iVarcharOid, 32);
-    f[2] = new Field(connection, new String("PROCEDURE_NAME"), iVarcharOid, 32);
-    f[3] = null;
-    f[4] = null;
-    f[5] = null;
-    f[6] = new Field(connection, new String("REMARKS"), iVarcharOid, 8192);
-    f[7] = new Field(connection, new String("PROCEDURE_TYPE"), iInt2Oid, 2);
-    r = connection.ExecSQL("select proname, proretset from pg_proc order by proname");
-    if (r.getColumnCount() != 2 || r.getTupleCount() <= 1)
-      throw new SQLException("Unexpected return from query for procedure list");
+    byte remarks[] = defaultRemarks;
+    
+    f[0] = new Field(connection, "PROCEDURE_CAT",   iVarcharOid, 32);
+    f[1] = new Field(connection, "PROCEDURE_SCHEM", iVarcharOid, 32);
+    f[2] = new Field(connection, "PROCEDURE_NAME",  iVarcharOid, 32);
+    f[3] = f[4] = f[5] = null; // reserved, must be null for now
+    f[6] = new Field(connection, "REMARKS",       iVarcharOid, 8192);
+    f[7] = new Field(connection, "PROCEDURE_TYPE", iInt2Oid,   2);
+    
+    // If the pattern is null, then set it to the default
+    if(procedureNamePattern==null)
+      procedureNamePattern="%";
+    
+    r = connection.ExecSQL("select proname, proretset from pg_proc where proname like '"+procedureNamePattern.toLowerCase()+"' order by proname");
+    
     while (r.next())
       {
    byte[][] tuple = new byte[8][0];
    
-   String name = r.getString(1);
-   remarks = new String("no remarks");
-   boolean retset = r.getBoolean(2);
-   
    tuple[0] = null;            // Catalog name
    tuple[1] = null;            // Schema name
-   tuple[2] = name.getBytes(); // Procedure name
-   tuple[3] = null;            // Reserved
-   tuple[4] = null;            // Reserved
-   tuple[5] = null;            // Reserved
-   tuple[6] = remarks.getBytes();  // Remarks
-   tuple[7] = new byte[1];
-   if (retset)
-     tuple[7][0] = (byte)java.sql.DatabaseMetaData.procedureReturnsResult;
+   tuple[2] = r.getBytes(1);       // Procedure name
+   tuple[3] = tuple[4] = tuple[5] = null;  // Reserved
+   tuple[6] = remarks;         // Remarks
+   
+   if (r.getBoolean(2))
+     tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureReturnsResult).getBytes();
    else
-     tuple[7][0] = (byte)java.sql.DatabaseMetaData.procedureNoResult;
+     tuple[7] = Integer.toString(java.sql.DatabaseMetaData.procedureNoResult).getBytes();
+   
    v.addElement(tuple);
       }
     return new ResultSet(connection, f, v, "OK", 1);
@@ -1559,6 +1560,12 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
   // Implementation note: This is required for Borland's JBuilder to work
   public java.sql.ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException
   {
+    if(procedureNamePattern==null)
+      procedureNamePattern="%";
+    
+    if(columnNamePattern==null)
+      columnNamePattern="%";
+    
     // for now, this returns an empty result set.
     Field f[] = new Field[13];
     ResultSet r;   // ResultSet for the SQL query that we need to do
@@ -1578,6 +1585,8 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     f[11] = new Field(connection, new String("NULLABLE"), iInt2Oid, 2);
     f[12] = new Field(connection, new String("REMARKS"), iVarcharOid, 32);
     
+    // add query loop here
+    
     return new ResultSet(connection, f, v, "OK", 1);
   }
   
@@ -1612,7 +1621,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    * @param types a list of table types to include; null returns
    * all types
    * @return each row is a table description      
-   * @exception SQLException if a database-access error occurs.                     
+   * @exception SQLException if a database-access error occurs.
    */
   public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException
   {
@@ -1620,6 +1629,9 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     if(types==null)
       types = defaultTableTypes;
     
+    if(tableNamePattern==null)
+      tableNamePattern="%";
+    
     // the field descriptors for the new ResultSet
     Field f[] = new Field[5];
     ResultSet r;   // ResultSet for the SQL query that we need to do
@@ -1632,7 +1644,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     f[4] = new Field(connection, new String("REMARKS"), iVarcharOid, 32);
     
     // Now form the query
-    StringBuffer sql = new StringBuffer("select relname,oid from pg_class where ");
+    StringBuffer sql = new StringBuffer("select relname,oid from pg_class where (");
     boolean notFirst=false;
     for(int i=0;i
       if(notFirst)
@@ -1644,32 +1656,35 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    }
     }
     
+    // Added by Stefan Andreasen 
+    // Now take the pattern into account
+    sql.append(") and relname like '");
+    sql.append(tableNamePattern.toLowerCase());
+    sql.append("'");
+    
     // Now run the query
     r = connection.ExecSQL(sql.toString());
     
-    if (r.getColumnCount() != 2)
-      throw new SQLException("Unexpected return from query for table list");
+    byte remarks[];
     
     while (r.next())
       {
    byte[][] tuple = new byte[5][0];
    
-   String name = r.getString(1);
-   String remarks = new String("no remarks");
-   
    // Fetch the description for the table (if any)
    ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(2));
    if(dr.getTupleCount()==1) {
      dr.next();
-     remarks=dr.getString(1);
-   }
+     remarks = dr.getBytes(1);
+   } else
+     remarks = defaultRemarks;
    dr.close();
    
-   tuple[0] = null;            // Catalog name
-   tuple[1] = null;            // Schema name
-   tuple[2] = name.getBytes();     // Table name
-   tuple[3] = null;            // Table type
-   tuple[4] = remarks.getBytes();      // Remarks
+   tuple[0] = null;        // Catalog name
+   tuple[1] = null;        // Schema name
+   tuple[2] = r.getBytes(1);   // Table name
+   tuple[3] = null;        // Table type
+   tuple[4] = remarks;     // Remarks
    v.addElement(tuple);
       }
     r.close();
@@ -1848,28 +1863,34 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     f[16] = new Field(connection, new String("ORDINAL_POSITION"), iInt4Oid,4);
     f[17] = new Field(connection, new String("IS_NULLABLE"), iVarcharOid, 32);
     
+    // Added by Stefan Andreasen 
+    // If the pattern are  null then set them to %
+    if (tableNamePattern == null) tableNamePattern="%";
+    if (columnNamePattern == null) columnNamePattern="%";
+    
     // Now form the query
-    r = connection.ExecSQL("select a.oid,c.relname,a.attname,a.atttypid,a.attnum,a.attnotnull,a.attlen,a.atttypmod from pg_class c, pg_attribute a where a.attrelid=c.oid and c.relname like '"+tableNamePattern+"' and a.attname like '"+columnNamePattern+"' and a.attnum>0 order by c.relname,a.attnum");
+    // Modified by Stefan Andreasen 
+    r = connection.ExecSQL("select a.oid,c.relname,a.attname,a.atttypid,a.attnum,a.attnotnull,a.attlen,a.atttypmod from pg_class c, pg_attribute a where a.attrelid=c.oid and c.relname like '"+tableNamePattern.toLowerCase()+"' and a.attname like '"+columnNamePattern.toLowerCase()+"' and a.attnum>0 order by c.relname,a.attnum");
+    
+    byte remarks[];
     
     while(r.next()) {
    byte[][] tuple = new byte[18][0];
    
-   String name = r.getString(1);
-   String remarks = new String("no remarks");
-   String columnSize;
-   
    // Fetch the description for the table (if any)
    ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(1));
    if(dr.getTupleCount()==1) {
      dr.next();
-     remarks=dr.getString(1);
-   }
+     tuple[11] = dr.getBytes(1);
+   } else
+     tuple[11] = defaultRemarks;
+   
    dr.close();
    
    tuple[0] = "".getBytes();   // Catalog name
    tuple[1] = "".getBytes();   // Schema name
-   tuple[2] = r.getString(2).getBytes();   // Table name
-   tuple[3] = r.getString(3).getBytes();   // Column name
+   tuple[2] = r.getBytes(2);   // Table name
+   tuple[3] = r.getBytes(3);   // Column name
    
    dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4));
    dr.next();
@@ -1877,16 +1898,16 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    dr.close();
    tuple[4] = Integer.toString(Field.getSQLType(typname)).getBytes();  // Data type
    tuple[5] = typname.getBytes();  // Type name
-
+   
+   // Column size
    // Looking at the psql source,
    // I think the length of a varchar as specified when the table was created
    // should be extracted from atttypmod which contains this length + sizeof(int32)
    if (typname.equals("bpchar") || typname.equals("varchar")) {
      int atttypmod = r.getInt(8);
-     columnSize = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0);
+     tuple[6] = Integer.toString(atttypmod != -1 ? atttypmod - VARHDRSZ : 0).getBytes();
    } else
-     columnSize = r.getString(7);
-   tuple[6] = columnSize.getBytes();   // Column size
+     tuple[6] = r.getBytes(7);
    
    tuple[7] = null;    // Buffer length
    
@@ -1894,8 +1915,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    tuple[9] = "10".getBytes(); // Num Prec Radix - assume decimal
    
    // tuple[10] is below
-   
-   tuple[11] = remarks.getBytes();     // Remarks
+   // tuple[11] is above
    
    tuple[12] = null;   // column default
    
@@ -1904,7 +1924,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    
    tuple[15] = tuple[6];   // char octet length
    
-   tuple[16] = r.getString(5).getBytes();  // ordinal position
+   tuple[16] = r.getBytes(5);  // ordinal position
    
    String nullFlag = r.getString(6);
    tuple[10] = Integer.toString(nullFlag.equals("f")?java.sql.DatabaseMetaData.columnNullable:java.sql.DatabaseMetaData.columnNoNulls).getBytes(); // Nullable
@@ -1948,6 +1968,14 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     Field f[] = new Field[8];
     Vector v = new Vector();
     
+    if(table==null)
+      table="%";
+    
+    if(columnNamePattern==null)
+      columnNamePattern="%";
+    else
+      columnNamePattern=columnNamePattern.toLowerCase();
+    
     f[0] = new Field(connection,new String("TABLE_CAT"),iVarcharOid,32);
     f[1] = new Field(connection,new String("TABLE_SCHEM"),iVarcharOid,32);
     f[2] = new Field(connection,new String("TABLE_NAME"),iVarcharOid,32);
@@ -1958,11 +1986,13 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
     f[7] = new Field(connection,new String("IS_GRANTABLE"),iVarcharOid,32);
     
     // This is taken direct from the psql source
-    ResultSet r = connection.ExecSQL("SELECT relname, relacl FROM pg_class, pg_user WHERE ( relkind = 'r' OR relkind = 'i') and relname !~ '^pg_' and relname !~ '^xin[vx][0-9]+' and usesysid = relowner ORDER BY relname");
+    ResultSet r = connection.ExecSQL("SELECT relname, relacl FROM pg_class, pg_user WHERE ( relkind = 'r' OR relkind = 'i') and relname !~ '^pg_' and relname !~ '^xin[vx][0-9]+' and usesysid = relowner and relname like '"+table.toLowerCase()+"' ORDER BY relname");
     while(r.next()) {
       byte[][] tuple = new byte[8][0];
       tuple[0] = tuple[1]= "".getBytes();
       DriverManager.println("relname=\""+r.getString(1)+"\" relacl=\""+r.getString(2)+"\"");
+      
+      // For now, don't add to the result as relacl needs to be processed.
       //v.addElement(tuple);
     }
     
@@ -2122,7 +2152,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
                             "'1' as KEY_SEQ,"+ // -- fake it as a String for now
                             "t.typname as PK_NAME " +
                             " FROM pg_class bc, pg_class ic, pg_index i, pg_attribute a, pg_type t " +
-                            " WHERE relkind = 'r' " + //    -- not indices
+                            " WHERE bc.relkind = 'r' " + //    -- not indices
                             "  and bc.relname ~ '"+table+"'" +
                             "  and i.indrelid = bc.oid" +
                             "  and i.indexrelid = ic.oid" +
@@ -2379,22 +2409,30 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
       f[16] = new Field(connection, new String("SQL_DATETIME_SUB"), iInt4Oid, 4);
       f[17] = new Field(connection, new String("NUM_PREC_RADIX"), iInt4Oid, 4);
       
+      // cache some results, this will keep memory useage down, and speed
+      // things up a little.
+      byte b9[]  = "9".getBytes();
+      byte b10[] = "10".getBytes();
+      byte bf[]  = "f".getBytes();
+      byte bnn[] = Integer.toString(typeNoNulls).getBytes();
+      byte bts[] = Integer.toString(typeSearchable).getBytes();
+      
       while(rs.next()) {
    byte[][] tuple = new byte[18][];
    String typname=rs.getString(1);
    tuple[0] = typname.getBytes();
    tuple[1] = Integer.toString(Field.getSQLType(typname)).getBytes();
-   tuple[2] = "9".getBytes();  // for now
-   tuple[6] = Integer.toString(typeNoNulls).getBytes(); // for now
-   tuple[7] = "f".getBytes(); // false for now - not case sensitive
-   tuple[8] = Integer.toString(typeSearchable).getBytes();
-   tuple[9] = "f".getBytes(); // false for now - it's signed
-   tuple[10] = "f".getBytes(); // false for now - must handle money
-   tuple[11] = "f".getBytes(); // false for now - handle autoincrement
+   tuple[2] = b9;  // for now
+   tuple[6] = bnn; // for now
+   tuple[7] = bf; // false for now - not case sensitive
+   tuple[8] = bts;
+   tuple[9] = bf; // false for now - it's signed
+   tuple[10] = bf; // false for now - must handle money
+   tuple[11] = bf; // false for now - handle autoincrement
    // 12 - LOCAL_TYPE_NAME is null
    // 13 & 14 ?
    // 15 & 16 are unused so we return null
-   tuple[17] = "10".getBytes(); // everything is base 10
+   tuple[17] = b10; // everything is base 10
    v.addElement(tuple);
       }
       rs.close();
@@ -2431,7 +2469,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    *      within index; zero when TYPE is tableIndexStatistic
    *   
  • COLUMN_NAME String => column name; null when TYPE is
  •     *      tableIndexStatistic
    -   *   
  • ASC_OR_DESC String => column sort sequence, "A" => ascending,
  • +   *   
  • ASC_OR_DESC String => column sort sequence, "A" => ascending
  •     *      "D" => descending, may be null if sort sequence is not supported;
        *      null when TYPE is tableIndexStatistic
        *   
  • CARDINALITY int => When TYPE is tableIndexStatisic then
  • index c8ef8b9a15ab789ff814570a8eae3d80ece3ab36..90563d5460712084e9fc3f16800cd7632edac070 100644 (file)
    @@ -27,7 +27,7 @@ public class Driver implements java.sql.Driver
       // These should be in sync with the backend that the driver was
       // distributed with
       static final int MAJORVERSION = 6;
    -  static final int MINORVERSION = 3;
    +  static final int MINORVERSION = 4;
       
       static 
       {
    index f786b507d1b4d900b075fd627226e95a0a4cbf7b..9002ccda7bd70e9c4c598030b9b637a9bb1d69dc 100644 (file)
    @@ -20,7 +20,16 @@ public class PG_Stream
     {
       private Socket connection;
       private InputStream pg_input;
    -  private OutputStream pg_output;
    +  private BufferedOutputStream pg_output;
    +  
    +  // This is the error message returned when an EOF occurs
    +  private static final String EOF_MSG = "The backend has broken the connection. Possibly the action you have attempted has caused it to close.";
    +  
    +  // This is the error message returned when an IOException occurs
    +  private static final String IOE_MSG = "IOError while reading from backend: ";
    +  
    +  // This is the error message returned when flushing the stream.
    +  private static final String FLUSH_MSG = "Error flushing output: ";
       
       /**
        * Constructor:  Connect to the PostgreSQL back end and return
    @@ -33,8 +42,13 @@ public class PG_Stream
       public PG_Stream(String host, int port) throws IOException
       {
         connection = new Socket(host, port);
    +    
    +    // Submitted by Jason Venner  adds a 10x speed
    +    // improvement on FreeBSD machines (caused by a bug in their TCP Stack)
    +    connection.setTcpNoDelay(true);
    +    
         pg_input = connection.getInputStream();
    -    pg_output = connection.getOutputStream();  
    +    pg_output = new BufferedOutputStream(connection.getOutputStream());
       }
       
       /**
    @@ -45,7 +59,6 @@ public class PG_Stream
        */
       public void SendChar(int val) throws IOException
       {
    -    //pg_output.write(val);
         byte b[] = new byte[1];
         b[0] = (byte)val;
         pg_output.write(b);
    @@ -165,9 +178,9 @@ public class PG_Stream
         try
           {
        c = pg_input.read();
    -   if (c < 0) throw new IOException("EOF");
    +   if (c < 0) throw new IOException(EOF_MSG);
           } catch (IOException e) {
    -   throw new SQLException("Error reading from backend: " + e.toString());
    +   throw new SQLException(IOE_MSG + e.toString());
           }
           return c;
       }
    @@ -190,11 +203,11 @@ public class PG_Stream
            int b = pg_input.read();
            
            if (b < 0)
    -         throw new IOException("EOF");
    +         throw new IOException(EOF_MSG);
            n = n | (b << (8 * i)) ;
          }
           } catch (IOException e) {
    -   throw new SQLException("Error reading from backend: " + e.toString());
    +   throw new SQLException(IOE_MSG + e.toString());
           }
           return n;
       }
    @@ -217,11 +230,11 @@ public class PG_Stream
            int b = pg_input.read();
            
            if (b < 0)
    -         throw new IOException("EOF");
    +         throw new IOException(EOF_MSG);
            n = b | (n << 8);
          }
           } catch (IOException e) {
    -   throw new SQLException("Error reading from backend: " + e.toString());
    +   throw new SQLException(IOE_MSG + e.toString());
           }
           return n;
       }
    @@ -246,7 +259,7 @@ public class PG_Stream
          {
            int c = pg_input.read();
            if (c < 0)
    -         throw new IOException("EOF");
    +         throw new IOException(EOF_MSG);
            else if (c == 0)
              break;
            else
    @@ -255,7 +268,7 @@ public class PG_Stream
        if (s >= maxsiz)
          throw new IOException("Too Much Data");
           } catch (IOException e) {
    -   throw new SQLException("Error reading from backend: " + e.toString());
    +   throw new SQLException(IOE_MSG + e.toString());
           }
           String v = new String(rst, 0, s);
           return v;
    @@ -314,21 +327,8 @@ public class PG_Stream
       private byte[] Receive(int siz) throws SQLException
       {
         byte[] answer = new byte[siz];
    -    int s = 0;
    -    
    -    try 
    -      {
    -   while (s < siz)
    -     {
    -       int w = pg_input.read(answer, s, siz - s);
    -       if (w < 0)
    -         throw new IOException("EOF");
    -       s += w;
    -     }
    -      } catch (IOException e) {
    -   throw new SQLException("Error reading from backend: " + e.toString());
    -      }
    -      return answer;
    +    Receive(answer,0,siz);
    +    return answer;
       }
       
       /**
    @@ -349,11 +349,11 @@ public class PG_Stream
          {
            int w = pg_input.read(b, off+s, siz - s);
            if (w < 0)
    -         throw new IOException("EOF");
    +         throw new IOException(EOF_MSG);
            s += w;
          }
           } catch (IOException e) {
    -   throw new SQLException("Error reading from backend: " + e.toString());
    +   throw new SQLException(IOE_MSG + e.toString());
           }
       }
       
    @@ -367,7 +367,7 @@ public class PG_Stream
         try {
           pg_output.flush();
         } catch (IOException e) {
    -      throw new SQLException("Error flushing output: " + e.toString());
    +      throw new SQLException(FLUSH_MSG + e.toString());
         }
       }
       
    index 86121c5734707b8a05f75da72c8504a751d56040..85ee2f67d96b41bfb2314b2d9f8a79a70c091913 100644 (file)
    @@ -308,24 +308,21 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
        public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
        {
          SimpleDateFormat df = new SimpleDateFormat("''"+connection.getDateStyle()+"''");
    -         
    -     // Ideally the following should work:
    +     
    +     set(parameterIndex, df.format(x));
    +     
    +     // The above is how the date should be handled.
          //
    -     //    set(parameterIndex, df.format(x));
    +     // However, in JDK's prior to 1.1.6 (confirmed with the
    +     // Linux jdk1.1.3 and the Win95 JRE1.1.5), SimpleDateFormat seems
    +     // to format a date to the previous day. So the fix is to add a day
    +     // before formatting.
          //
    -     // however, SimpleDateFormat seems to format a date to the previous
    -     // day. So a fix (for now) is to add a day before formatting.
    -     // This needs more people to confirm this is really happening, or
    -     // possibly for us to implement our own formatting code.
    +     // PS: 86400000 is one day
          //
    -     // I've tested this with the Linux jdk1.1.3 and the Win95 JRE1.1.5
    -     //
    -     set(parameterIndex, df.format(new java.util.Date(x.getTime()+DAY)));
    +     //set(parameterIndex, df.format(new java.util.Date(x.getTime()+86400000)));
        }
       
    -  // This equates to 1 day
    -  private static final int DAY = 86400000;
    -
        /**
         * Set a parameter to a java.sql.Time value.  The driver converts
         * this to a SQL TIME value when it sends it to the database.
    index ba98bd97c9174f34c987b1b0bf441efd73a07b85..12dcc476af43d117544253087e7859fe468012f4 100644 (file)
    @@ -714,6 +714,12 @@ public class ResultSet implements java.sql.ResultSet
           throw new SQLException("Column index out of range");
         field = fields[columnIndex - 1];
         
    +    // some fields can be null, mainly from those returned by MetaData methods
    +    if(field==null) {
    +      wasNullFlag=true;
    +      return null;
    +    }
    +    
         switch (field.getSQLType())
           {
           case Types.BIT:
    index 7a01a136ecdbaf440918c5366d8934104304b51a..33f2d78f1d3c2b78a5d409743d52ad58d0d90721 100644 (file)
    @@ -121,11 +121,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
       {
         String type_name = getField(column).getTypeName();
         
    -    if (type_name.equals("cash"))
    -      return true;
    -    if (type_name.equals("money"))
    -      return true;
    -    return false;
    +    return type_name.equals("cash") || type_name.equals("money");
       }
       
       /**
    @@ -214,11 +210,14 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
        *
        * @param column the first column is 1, the second is 2, etc.
        * @return the column name
    -   * @exception SQLException if a databvase access error occurs
    +   * @exception SQLException if a database access error occurs
        */
       public String getColumnName(int column) throws SQLException
       {
    -    return getField(column).name;
    +    Field f = getField(column);
    +    if(f!=null)
    +      return f.name;
    +    return "field"+column;
       }
       
       /**
    @@ -233,13 +232,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
        */
       public String getSchemaName(int column) throws SQLException
       {
    -    String table_name = getTableName(column);
    -    
    -    // If the table name is invalid, so are we.
    -    if (table_name.equals(""))
    -      return "";   
    -    return "";     // Ok, so I don't know how to
    -    // do this as yet.
    +    return "";
       }
       
       /**
    @@ -328,12 +321,7 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
        */
       public String getCatalogName(int column) throws SQLException
       {
    -    String table_name = getTableName(column);
    -    
    -    if (table_name.equals(""))
    -      return "";
    -    return "";     // As with getSchemaName(), this
    -    // is just the start of it.
    +    return "";
       }
       
       /**