]> granicus.if.org Git - postgresql/commitdiff
From: Peter T Mount <patches@maidast.demon.co.uk>
authorMarc G. Fournier <scrappy@hub.org>
Wed, 3 Jun 1998 19:43:29 +0000 (19:43 +0000)
committerMarc G. Fournier <scrappy@hub.org>
Wed, 3 Jun 1998 19:43:29 +0000 (19:43 +0000)
Bug fixes:

        PreparedStatement.setObject didn't handle short's

        ResultSet.getDate() now handles null dates (returns null rather
        than a NullPointerException)

        ResultSetMetaData.getPrecision() now returns 0 for VARCHAR

New features:

        Field now caches the typename->oid in a Hashtable to speed things
        up. It removes the need for some unnecessary queries to the
        backend.

        PreparedStatement.toString() now returns the sql statement that
        it will send to the backend. Before it did nothing.

        DatabaseMetaData.getTypeInfo() now does something.

src/interfaces/jdbc/postgresql/Connection.java
src/interfaces/jdbc/postgresql/DatabaseMetaData.java
src/interfaces/jdbc/postgresql/PreparedStatement.java
src/interfaces/jdbc/postgresql/ResultSetMetaData.java

index 103b4e4b8f2f2f0ed60e9272323f29be2ab0d73e..7c565e145fa05d34d35bc95442b480e66e7a886d 100644 (file)
@@ -2,6 +2,7 @@ package postgresql;
 
 import java.io.*;
 import java.lang.*;
+import java.lang.reflect.*;
 import java.net.*;
 import java.util.*;
 import java.sql.*;
@@ -87,6 +88,12 @@ 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
    */
@@ -916,23 +923,90 @@ public class Connection implements java.sql.Connection
    * You can use the getValue() or setValue() methods to handle the returned
    * object. Custom objects can have their own methods.
    *
+   * In 6.4, this is extended to use the postgresql.util.Serialize class to
+   * allow the Serialization of Java Objects into the database without using
+   * Blobs. Refer to that class for details on how this new feature works.
+   *
    * @return PGobject for this type, and set to value
    * @exception SQLException if value is not correct for this type
+   * @see postgresql.util.Serialize
    */
-  protected PGobject getObject(String type,String value) throws SQLException
+  protected Object getObject(String type,String value) throws SQLException
   {
-    PGobject obj = null;
     try {
-      String name = (String)objectTypes.get(type);
-      obj = (PGobject)(Class.forName(name==null?"postgresql.util.PGobject":name).newInstance());
+      Object o = objectTypes.get(type);
+      
+      // If o is null, then the type is unknown, so check to see if type
+      // is an actual table name. If it does, see if a Class is known that
+      // can handle it
+      if(o == null) {
+       Serialize ser = new Serialize(this,type);
+       objectTypes.put(type,ser);
+       return ser.fetch(Integer.parseInt(value));
+      }
+      
+      // If o is not null, and it is a String, then its a class name that
+      // extends PGobject.
+      //
+      // This is used to implement the postgresql unique types (like lseg,
+      // point, etc).
+      if(o instanceof String) {
+       // 6.3 style extending PG_Object
+       PGobject obj = null;
+       obj = (PGobject)(Class.forName((String)o).newInstance());
+       obj.setType(type);
+       obj.setValue(value);
+       return (Object)obj;
+      } else {
+       // If it's an object, it should be an instance of our Serialize class
+       // If so, then call it's fetch method.
+       if(o instanceof Serialize)
+         return ((Serialize)o).fetch(Integer.parseInt(value));
+      }
+    } catch(SQLException sx) {
+      throw sx;
     } catch(Exception ex) {
       throw new SQLException("Failed to create object for "+type+": "+ex);
     }
-    if(obj!=null) {
-      obj.setType(type);
-      obj.setValue(value);
+    
+    // should never be reached
+    return null;
+  }
+  
+  /**
+   * This stores an object into the database.
+   * @param o Object to store
+   * @return OID of the new rectord
+   * @exception SQLException if value is not correct for this type
+   * @see postgresql.util.Serialize
+   */
+  protected int putObject(Object o) throws SQLException
+  {
+    try {
+      String type = o.getClass().getName();
+      Object x = objectTypes.get(type);
+      
+      // If x is null, then the type is unknown, so check to see if type
+      // is an actual table name. If it does, see if a Class is known that
+      // can handle it
+      if(x == null) {
+       Serialize ser = new Serialize(this,type);
+       objectTypes.put(type,ser);
+       return ser.store(o);
+      }
+      
+      // If it's an object, it should be an instance of our Serialize class
+      // If so, then call it's fetch method.
+      if(x instanceof Serialize)
+       return ((Serialize)x).store(o);
+    } catch(SQLException sx) {
+      throw sx;
+    } catch(Exception ex) {
+      throw new SQLException("Failed to store object: "+ex);
     }
-    return obj;
+    
+    // should never be reached
+    return 0;
   }
   
   /**
index 3aef2068cd37f37a5533358b407aa6b35c9b2328..bfcfc6f7cf62923b8ff3ed28007fc4835b2f31ed 100644 (file)
@@ -2354,7 +2354,53 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
    */
   public java.sql.ResultSet getTypeInfo() throws SQLException
   {
-    // XXX-Not Implemented
+    ResultSet rs = connection.ExecSQL("select typname from pg_type");
+    if(rs!=null) {
+      Field f[] = new Field[18];
+      ResultSet r;     // ResultSet for the SQL query that we need to do
+      Vector v = new Vector();         // The new ResultSet tuple stuff
+      
+      f[0] = new Field(connection, new String("TYPE_NAME"), iVarcharOid, 32);
+      f[1] = new Field(connection, new String("DATA_TYPE"), iInt2Oid, 2);
+      f[2] = new Field(connection, new String("PRECISION"), iInt4Oid, 4);
+      f[3] = new Field(connection, new String("LITERAL_PREFIX"), iVarcharOid, 32);
+      f[4] = new Field(connection, new String("LITERAL_SUFFIX"), iVarcharOid, 32);
+      f[5] = new Field(connection, new String("CREATE_PARAMS"), iVarcharOid, 32);
+      f[6] = new Field(connection, new String("NULLABLE"), iInt2Oid, 2);
+      f[7] = new Field(connection, new String("CASE_SENSITIVE"), iBoolOid, 1);
+      f[8] = new Field(connection, new String("SEARCHABLE"), iInt2Oid, 2);
+      f[9] = new Field(connection, new String("UNSIGNED_ATTRIBUTE"), iBoolOid, 1);
+      f[10] = new Field(connection, new String("FIXED_PREC_SCALE"), iBoolOid, 1);
+      f[11] = new Field(connection, new String("AUTO_INCREMENT"), iBoolOid, 1);
+      f[12] = new Field(connection, new String("LOCAL_TYPE_NAME"), iVarcharOid, 32);
+      f[13] = new Field(connection, new String("MINIMUM_SCALE"), iInt2Oid, 2);
+      f[14] = new Field(connection, new String("MAXIMUM_SCALE"), iInt2Oid, 2);
+      f[15] = new Field(connection, new String("SQL_DATA_TYPE"), iInt4Oid, 4);
+      f[16] = new Field(connection, new String("SQL_DATETIME_SUB"), iInt4Oid, 4);
+      f[17] = new Field(connection, new String("NUM_PREC_RADIX"), iInt4Oid, 4);
+      
+      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
+       // 12 - LOCAL_TYPE_NAME is null
+       // 13 & 14 ?
+       // 15 & 16 are unused so we return null
+       tuple[17] = "10".getBytes(); // everything is base 10
+       v.addElement(tuple);
+      }
+      rs.close();
+      return new ResultSet(connection, f, v, "OK", 1);
+    }
+    
     return null;
   }
   
index 1f82314e115c5f31e7070884c7e1f2028bd6446f..86121c5734707b8a05f75da72c8504a751d56040 100644 (file)
@@ -492,13 +492,21 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
        {
                setObject(parameterIndex, x, targetSqlType, 0);
        }
-
+       
+  /**
+   * This stores an Object into a parameter.
+   * <p>New for 6.4, if the object is not recognised, but it is
+   * Serializable, then the object is serialised using the
+   * postgresql.util.Serialize class.
+   */
        public void setObject(int parameterIndex, Object x) throws SQLException
        {
                if (x instanceof String)
                        setString(parameterIndex, (String)x);
                else if (x instanceof BigDecimal)
                        setBigDecimal(parameterIndex, (BigDecimal)x);
+               else if (x instanceof Short)
+                       setShort(parameterIndex, ((Short)x).shortValue());
                else if (x instanceof Integer)
                        setInt(parameterIndex, ((Integer)x).intValue());
                else if (x instanceof Long)
@@ -520,7 +528,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
                else if (x instanceof PGobject)
                        setString(parameterIndex, ((PGobject)x).getValue());
                else
-                       throw new SQLException("Unknown object type");
+                       setLong(parameterIndex, connection.putObject(x));
        }
 
        /**
@@ -548,6 +556,26 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
                return super.execute(s.toString());     // in Statement class
        }
 
+       /**
+        * Returns the SQL statement with the current template values
+        * substituted.
+        */
+       public String toString() {
+               StringBuffer s = new StringBuffer();
+               int i;
+
+               for (i = 0 ; i < inStrings.length ; ++i)
+               {
+                       if (inStrings[i] == null)
+                               s.append( '?' );
+                       else
+                               s.append (templateStrings[i]);
+                       s.append (inStrings[i]);
+               }
+               s.append(templateStrings[inStrings.length]);
+               return s.toString();
+       }
+       
        // **************************************************************
        //      END OF PUBLIC INTERFACE 
        // **************************************************************
index 7a1dfbbf26bd55407fd1113962daedb4a6440b88..7a01a136ecdbaf440918c5366d8934104304b51a 100644 (file)
@@ -296,6 +296,8 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
        return 16;
       case Types.DOUBLE:
        return 16;
+      case Types.VARCHAR:
+       return 0;
       default:
        return 0;
       }