import java.io.*;
import java.lang.*;
+import java.lang.reflect.*;
import java.net.*;
import java.util.*;
import java.sql.*;
// 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
*/
* 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;
}
/**
*/
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;
}
{
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)
else if (x instanceof PGobject)
setString(parameterIndex, ((PGobject)x).getValue());
else
- throw new SQLException("Unknown object type");
+ setLong(parameterIndex, connection.putObject(x));
}
/**
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
// **************************************************************
return 16;
case Types.DOUBLE:
return 16;
+ case Types.VARCHAR:
+ return 0;
default:
return 0;
}