Re: tightening up on use of oid 0 - Mailing list pgsql-jdbc

From Oliver Jowett
Subject Re: tightening up on use of oid 0
Date
Msg-id 4167BC1A.4070809@opencloud.com
Whole thread Raw
In response to tightening up on use of oid 0  (Oliver Jowett <oliver@opencloud.com>)
Responses Re: tightening up on use of oid 0  (Kris Jurka <books@ejurka.com>)
List pgsql-jdbc
Oliver Jowett wrote:
> I am currently cleaning up a few places where OID 0 could get used as a
> parameter type (causing the backend to try to infer a type).

Here is a patch to do this, including the PGobject changes to handle SQL
NULLs.

The PGobject / geometric type changes are a bit ugly in places, mostly
because those types are mutable (unnecessarily, IMO).

-O
Index: org/postgresql/errors.properties
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/errors.properties,v
retrieving revision 1.38
diff -u -c -r1.38 errors.properties
*** org/postgresql/errors.properties    9 Oct 2004 06:02:58 -0000    1.38
--- org/postgresql/errors.properties    9 Oct 2004 10:13:41 -0000
***************
*** 73,78 ****
--- 73,80 ----
  postgresql.prep.type:Unknown Types value.
  postgresql.prep.typenotfound:Unknown type {0}.
  postgresql.prep.zeroinstring:Zero bytes may not occur in string parameters.
+ postgresql.prep.untypedsetnull:setNull(i,Types.OTHER) and setObject(i,null,Types.OTHER) are not supported. Instead,
usesetObject(i,object,Types.OTHER) where 'object' is an appropriate PGobject subclass instance representing a NULL. 
+ postgresql.prep.untypedsetobject:setObject(i,null) is not supported. Instead, use setNull(i,type) or
setObject(i,null,type).
  postgresql.res.badbigdec:Bad BigDecimal {0}
  postgresql.res.badbyte:Bad Byte {0}
  postgresql.res.baddate:Bad Date Format {0}
Index: org/postgresql/geometric/PGbox.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGbox.java,v
retrieving revision 1.8
diff -u -c -r1.8 PGbox.java
*** org/postgresql/geometric/PGbox.java    29 Jun 2004 06:43:26 -0000    1.8
--- org/postgresql/geometric/PGbox.java    9 Oct 2004 10:13:41 -0000
***************
*** 23,31 ****
  public class PGbox extends PGobject implements Serializable, Cloneable
  {
      /**
!      * These are the two points.
       */
!     public PGpoint point[] = new PGpoint[2];

      /**
       * @param x1 first x coordinate
--- 23,31 ----
  public class PGbox extends PGobject implements Serializable, Cloneable
  {
      /**
!      * These are the two points, or null for a SQL NULL.
       */
!     public PGpoint point[];

      /**
       * @param x1 first x coordinate
***************
*** 35,43 ****
       */
      public PGbox(double x1, double y1, double x2, double y2)
      {
!         this();
!         this.point[0] = new PGpoint(x1, y1);
!         this.point[1] = new PGpoint(x2, y2);
      }

      /**
--- 35,41 ----
       */
      public PGbox(double x1, double y1, double x2, double y2)
      {
!         this(new PGpoint(x1, y1), new PGpoint(x2, y2));
      }

      /**
***************
*** 47,54 ****
      public PGbox(PGpoint p1, PGpoint p2)
      {
          this();
!         this.point[0] = p1;
!         this.point[1] = p2;
      }

      /**
--- 45,51 ----
      public PGbox(PGpoint p1, PGpoint p2)
      {
          this();
!         this.point = new PGpoint[] { p1, p2 };
      }

      /**
***************
*** 82,89 ****
          if (t.getSize() != 2)
              throw new PSQLException("postgresql.geo.box", PSQLState.DATA_TYPE_MISMATCH, value);

!         point[0] = new PGpoint(t.getToken(0));
!         point[1] = new PGpoint(t.getToken(1));
      }

      /**
--- 79,88 ----
          if (t.getSize() != 2)
              throw new PSQLException("postgresql.geo.box", PSQLState.DATA_TYPE_MISMATCH, value);

!         point = new PGpoint[] {
!             new PGpoint(t.getToken(0)),
!             new PGpoint(t.getToken(1))
!         };
      }

      /**
***************
*** 96,101 ****
--- 95,106 ----
          {
              PGbox p = (PGbox)obj;

+             if (point == p.point)
+                 return true;
+
+             if (point == null || p.point == null)
+                 return false;
+
              // Same points.
              if (p.point[0].equals(point[0]) && p.point[1].equals(point[1]))
                  return true;
***************
*** 126,136 ****
--- 131,148 ----
          // its X and Y components; we end up with an exclusive-OR of the two X and
          // two Y components, which is equal whenever equals() would return true
          // since xor is commutative.
+
+         if (point == null)
+             return 0;
+
          return point[0].hashCode() ^ point[1].hashCode();
      }

      public Object clone()
      {
+         if (point == null)
+             return new PGbox();
+
          return new PGbox((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
      }

***************
*** 139,144 ****
--- 151,161 ----
       */
      public String getValue()
      {
+         if (point == null)
+             return null;
+
          return point[0].toString() + "," + point[1].toString();
      }
+
+     public final static PGbox NULL = new PGbox();
  }
Index: org/postgresql/geometric/PGcircle.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGcircle.java,v
retrieving revision 1.10
diff -u -c -r1.10 PGcircle.java
*** org/postgresql/geometric/PGcircle.java    29 Jun 2004 06:43:26 -0000    1.10
--- org/postgresql/geometric/PGcircle.java    9 Oct 2004 10:13:41 -0000
***************
*** 24,30 ****
  public class PGcircle extends PGobject implements Serializable, Cloneable
  {
      /**
!      * This is the center point
       */
      public PGpoint center;

--- 24,30 ----
  public class PGcircle extends PGobject implements Serializable, Cloneable
  {
      /**
!      * This is the center point, or null for a NULL value
       */
      public PGpoint center;

***************
*** 102,107 ****
--- 102,114 ----
          if (obj instanceof PGcircle)
          {
              PGcircle p = (PGcircle)obj;
+
+             if (center == null && p.center == null)
+                 return true;
+
+             if (center == null || p.center == null)
+                 return false;
+
              return p.center.equals(center) && p.radius == radius;
          }
          return false;
***************
*** 109,120 ****
--- 116,133 ----

      public int hashCode()
      {
+         if (center == null)
+             return 0;
+
          long v = Double.doubleToLongBits(radius);
          return (int) (center.hashCode() ^ v ^ (v>>>32));
      }

      public Object clone()
      {
+         if (center == null)
+             return new PGcircle();
+
          return new PGcircle((PGpoint)center.clone(), radius);
      }

***************
*** 123,128 ****
--- 136,146 ----
       */
      public String getValue()
      {
+         if (center == null)
+             return null;
+
          return "<" + center + "," + radius + ">";
      }
+
+     public final static PGcircle NULL = new PGcircle();
  }
Index: org/postgresql/geometric/PGline.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGline.java,v
retrieving revision 1.8
diff -u -c -r1.8 PGline.java
*** org/postgresql/geometric/PGline.java    29 Jun 2004 06:43:26 -0000    1.8
--- org/postgresql/geometric/PGline.java    9 Oct 2004 10:13:41 -0000
***************
*** 26,34 ****
  public class PGline extends PGobject implements Serializable, Cloneable
  {
      /**
!      * These are the two points.
       */
!     public PGpoint point[] = new PGpoint[2];

      /**
       * @param x1 coordinate for first point
--- 26,34 ----
  public class PGline extends PGobject implements Serializable, Cloneable
  {
      /**
!      * These are the two points, or null for a SQL NULL.
       */
!     public PGpoint point[];

      /**
       * @param x1 coordinate for first point
***************
*** 48,55 ****
      public PGline(PGpoint p1, PGpoint p2)
      {
          this();
!         this.point[0] = p1;
!         this.point[1] = p2;
      }

      /**
--- 48,54 ----
      public PGline(PGpoint p1, PGpoint p2)
      {
          this();
!         this.point = new PGpoint[] { p1, p2 };
      }

      /**
***************
*** 80,87 ****
          if (t.getSize() != 2)
              throw new PSQLException("postgresql.geo.line", PSQLState.DATA_TYPE_MISMATCH, s);

!         point[0] = new PGpoint(t.getToken(0));
!         point[1] = new PGpoint(t.getToken(1));
      }

      /**
--- 79,88 ----
          if (t.getSize() != 2)
              throw new PSQLException("postgresql.geo.line", PSQLState.DATA_TYPE_MISMATCH, s);

!         point = new PGpoint[] {
!             new PGpoint(t.getToken(0)),
!             new PGpoint(t.getToken(1))
!         };
      }

      /**
***************
*** 93,98 ****
--- 94,106 ----
          if (obj instanceof PGline)
          {
              PGline p = (PGline)obj;
+
+             if (point == p.point)
+                 return true;
+
+             if (point == null || p.point == null)
+                 return false;
+
              return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
                     (p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
          }
***************
*** 100,110 ****
--- 108,124 ----
      }

      public int hashCode() {
+         if (point == null)
+             return 0;
+
          return point[0].hashCode() ^ point[1].hashCode();
      }

      public Object clone()
      {
+         if (point == null)
+             return new PGline();
+
          return new PGline((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
      }

***************
*** 113,118 ****
--- 127,137 ----
       */
      public String getValue()
      {
+         if (point == null)
+             return null;
+
          return "[" + point[0] + "," + point[1] + "]";
      }
+
+     public static final PGline NULL = new PGline();
  }
Index: org/postgresql/geometric/PGlseg.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGlseg.java,v
retrieving revision 1.8
diff -u -c -r1.8 PGlseg.java
*** org/postgresql/geometric/PGlseg.java    29 Jun 2004 06:43:26 -0000    1.8
--- org/postgresql/geometric/PGlseg.java    9 Oct 2004 10:13:41 -0000
***************
*** 23,31 ****
  public class PGlseg extends PGobject implements Serializable, Cloneable
  {
      /**
!      * These are the two points.
       */
!     public PGpoint point[] = new PGpoint[2];

      /**
       * @param x1 coordinate for first point
--- 23,31 ----
  public class PGlseg extends PGobject implements Serializable, Cloneable
  {
      /**
!      * These are the two points, or null for a SQL NULL.
       */
!     public PGpoint point[];

      /**
       * @param x1 coordinate for first point
***************
*** 45,52 ****
      public PGlseg(PGpoint p1, PGpoint p2)
      {
          this();
!         this.point[0] = p1;
!         this.point[1] = p2;
      }

      /**
--- 45,51 ----
      public PGlseg(PGpoint p1, PGpoint p2)
      {
          this();
!         this.point = new PGpoint[] { p1, p2 };
      }

      /**
***************
*** 77,84 ****
          if (t.getSize() != 2)
              throw new PSQLException("postgresql.geo.lseg", PSQLState.DATA_TYPE_MISMATCH);

!         point[0] = new PGpoint(t.getToken(0));
!         point[1] = new PGpoint(t.getToken(1));
      }

      /**
--- 76,85 ----
          if (t.getSize() != 2)
              throw new PSQLException("postgresql.geo.lseg", PSQLState.DATA_TYPE_MISMATCH);

!         point = new PGpoint[] {
!             new PGpoint(t.getToken(0)),
!             new PGpoint(t.getToken(1))
!         };
      }

      /**
***************
*** 90,95 ****
--- 91,103 ----
          if (obj instanceof PGlseg)
          {
              PGlseg p = (PGlseg)obj;
+
+             if (point == p.point)
+                 return true;
+
+             if (point == null || p.point == null)
+                 return false;
+
              return (p.point[0].equals(point[0]) && p.point[1].equals(point[1])) ||
                     (p.point[0].equals(point[1]) && p.point[1].equals(point[0]));
          }
***************
*** 98,108 ****
--- 106,122 ----

      public int hashCode()
      {
+         if (point == null)
+             return 0;
+
          return point[0].hashCode() ^ point[1].hashCode();
      }

      public Object clone()
      {
+         if (point == null)
+             return new PGlseg();
+
          return new PGlseg((PGpoint)point[0].clone(), (PGpoint)point[1].clone());
      }

***************
*** 111,116 ****
--- 125,135 ----
       */
      public String getValue()
      {
+         if (point == null)
+             return null;
+
          return "[" + point[0] + "," + point[1] + "]";
      }
+
+     public final static PGlseg NULL = new PGlseg();
  }
Index: org/postgresql/geometric/PGpath.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGpath.java,v
retrieving revision 1.9
diff -u -c -r1.9 PGpath.java
*** org/postgresql/geometric/PGpath.java    29 Jun 2004 06:43:26 -0000    1.9
--- org/postgresql/geometric/PGpath.java    9 Oct 2004 10:13:41 -0000
***************
*** 28,34 ****
      public boolean open;

      /**
!      * The points defining this path
       */
      public PGpoint points[];

--- 28,34 ----
      public boolean open;

      /**
!      * The points defining this path, or null for a SQL NULL.
       */
      public PGpoint points[];

***************
*** 98,103 ****
--- 98,109 ----
          {
              PGpath p = (PGpath)obj;

+             if (points == null && p.points == null)
+                 return true;
+
+             if (points == null || p.points == null)
+                 return false;
+
              if (p.points.length != points.length)
                  return false;

***************
*** 115,120 ****
--- 121,130 ----

      public int hashCode() {
          // XXX not very good..
+
+         if (points == null)
+             return 0;
+
          int hash = 0;
          for (int i = 0; i < points.length && i < 5; ++i) {
              hash = hash ^ points[i].hashCode();
***************
*** 124,129 ****
--- 134,142 ----

      public Object clone()
      {
+         if (points == null)
+             return new PGpath();
+
          PGpoint ary[] = new PGpoint[points.length];
          for (int i = 0;i < points.length;i++)
              ary[i] = (PGpoint)points[i].clone();
***************
*** 135,140 ****
--- 148,156 ----
       */
      public String getValue()
      {
+         if (points == null)
+             return null;
+
          StringBuffer b = new StringBuffer(open ? "[" : "(");

          for (int p = 0;p < points.length;p++)
***************
*** 167,170 ****
--- 183,188 ----
      {
          open = true;
      }
+
+     public final static PGpath NULL = new PGpath();
  }
Index: org/postgresql/geometric/PGpoint.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGpoint.java,v
retrieving revision 1.9
diff -u -c -r1.9 PGpoint.java
*** org/postgresql/geometric/PGpoint.java    29 Jun 2004 06:43:26 -0000    1.9
--- org/postgresql/geometric/PGpoint.java    9 Oct 2004 10:13:41 -0000
***************
*** 94,99 ****
--- 94,106 ----
          if (obj instanceof PGpoint)
          {
              PGpoint p = (PGpoint)obj;
+
+             if (this == NULL && p == NULL)
+                 return true;
+
+             if (this == NULL || p == NULL)
+                 return false;
+
              return x == p.x && y == p.y;
          }
          return false;
***************
*** 101,106 ****
--- 108,116 ----

      public int hashCode()
      {
+         if (this == NULL)
+             return 0;
+
          long v1 = Double.doubleToLongBits(x);
          long v2 = Double.doubleToLongBits(y);
          return (int) (v1 ^ v2 ^ (v1>>>32) ^ (v2>>>32));
***************
*** 108,113 ****
--- 118,126 ----

      public Object clone()
      {
+         if (this == NULL)
+             return NULL;
+
          return new PGpoint(x, y);
      }

***************
*** 116,121 ****
--- 129,137 ----
       */
      public String getValue()
      {
+         if (this == NULL)
+             return null;
+
          return "(" + x + "," + y + ")";
      }

***************
*** 184,187 ****
--- 200,207 ----
          setLocation(p.x, p.y);
      }

+     // Ugly hack -- this unique object, by object identity, is a SQL NULL.
+     // Cloning NULL gives you NULL. You can mutate NULL, but it doesn't
+     // affect its NULL-ness.
+     public final static PGpoint NULL = new PGpoint();
  }
Index: org/postgresql/geometric/PGpolygon.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/geometric/PGpolygon.java,v
retrieving revision 1.8
diff -u -c -r1.8 PGpolygon.java
*** org/postgresql/geometric/PGpolygon.java    29 Jun 2004 06:43:26 -0000    1.8
--- org/postgresql/geometric/PGpolygon.java    9 Oct 2004 10:13:41 -0000
***************
*** 20,26 ****
  public class PGpolygon extends PGobject implements Serializable, Cloneable
  {
      /**
!      * The points defining the polygon
       */
      public PGpoint points[];

--- 20,26 ----
  public class PGpolygon extends PGobject implements Serializable, Cloneable
  {
      /**
!      * The points defining the polygon, or null if this is a SQL NULL.
       */
      public PGpoint points[];

***************
*** 76,81 ****
--- 76,87 ----
          {
              PGpolygon p = (PGpolygon)obj;

+             if (points == p.points)
+                 return true;
+
+             if (points == null || p.points == null)
+                 return false;
+
              if (p.points.length != points.length)
                  return false;

***************
*** 89,94 ****
--- 95,103 ----
      }

      public int hashCode() {
+         if (points == null)
+             return 0;
+
          // XXX not very good..
          int hash = 0;
          for (int i = 0; i < points.length && i < 5; ++i) {
***************
*** 99,104 ****
--- 108,116 ----

      public Object clone()
      {
+         if (points == null)
+             return new PGpolygon();
+
          PGpoint ary[] = new PGpoint[points.length];
          for (int i = 0;i < points.length;i++)
              ary[i] = (PGpoint)points[i].clone();
***************
*** 110,115 ****
--- 122,130 ----
       */
      public String getValue()
      {
+         if (points == null)
+             return null;
+
          StringBuffer b = new StringBuffer();
          b.append("(");
          for (int p = 0;p < points.length;p++)
***************
*** 121,124 ****
--- 136,141 ----
          b.append(")");
          return b.toString();
      }
+
+     public final static PGpolygon NULL = new PGpolygon();
  }
Index: org/postgresql/jdbc2/AbstractJdbc2ResultSet.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java,v
retrieving revision 1.48
diff -u -c -r1.48 AbstractJdbc2ResultSet.java
*** org/postgresql/jdbc2/AbstractJdbc2ResultSet.java    30 Sep 2004 18:16:52 -0000    1.48
--- org/postgresql/jdbc2/AbstractJdbc2ResultSet.java    9 Oct 2004 10:13:42 -0000
***************
*** 31,36 ****
--- 31,37 ----
  import org.postgresql.Driver;
  import org.postgresql.core.*;
  import org.postgresql.largeobject.*;
+ import org.postgresql.util.PGobject;
  import org.postgresql.util.PGbytea;
  import org.postgresql.util.PGtokenizer;
  import org.postgresql.util.PSQLException;
***************
*** 766,775 ****
              {
                  String key = (String) keys.nextElement();
                  Object o = updateValues.get(key);
!                 if (o instanceof NullObject)
!                     insertStatement.setNull(i,java.sql.Types.NULL);
!                 else
!                     insertStatement.setObject(i, o);
              }

              insertStatement.executeUpdate();
--- 767,773 ----
              {
                  String key = (String) keys.nextElement();
                  Object o = updateValues.get(key);
!                 insertStatement.setObject(i, o);
              }

              insertStatement.executeUpdate();
***************
*** 1084,1090 ****
      public synchronized void updateNull(int columnIndex)
      throws SQLException
      {
!         updateValue(columnIndex, new NullObject());
      }


--- 1082,1089 ----
      public synchronized void updateNull(int columnIndex)
      throws SQLException
      {
!         String columnTypeName = connection.getPGType(fields[columnIndex - 1].getOID());
!         updateValue(columnIndex, new NullObject(columnTypeName));
      }


***************
*** 1245,1254 ****
                  for (; iterator.hasNext(); i++)
                  {
                      Object o = iterator.next();
!                     if (o instanceof NullObject)
!                         updateStatement.setNull(i+1,java.sql.Types.NULL);
!                     else
!                         updateStatement.setObject( i + 1, o );

                  }
                  for ( int j = 0; j < numKeys; j++, i++)
--- 1244,1250 ----
                  for (; iterator.hasNext(); i++)
                  {
                      Object o = iterator.next();
!                     updateStatement.setObject( i + 1, o );

                  }
                  for ( int j = 0; j < numKeys; j++, i++)
***************
*** 2613,2620 ****
          }
      };

!     class NullObject {
!     };

  }

--- 2609,2628 ----
          }
      };

!     //
!     // We need to specify the type of NULL when updating a column to NULL, so
!     // NullObject is a simple extension of PGobject that always returns null
!     // values but retains column type info.
!     //

+     class NullObject extends PGobject {
+         NullObject(String type) {
+             setType(type);
+         }
+
+         public String getValue() {
+             return null;
+         }
+     };
  }

Index: org/postgresql/jdbc2/AbstractJdbc2Statement.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/jdbc2/AbstractJdbc2Statement.java,v
retrieving revision 1.32
diff -u -c -r1.32 AbstractJdbc2Statement.java
*** org/postgresql/jdbc2/AbstractJdbc2Statement.java    9 Oct 2004 06:02:58 -0000    1.32
--- org/postgresql/jdbc2/AbstractJdbc2Statement.java    9 Oct 2004 10:13:42 -0000
***************
*** 816,824 ****
                  oid = Oid.BYTEA;
                  break;
              case Types.OTHER:
              default:
!                 oid = 0;
!                 break;
          }

          preparedParameters.setNull(adjustParamIndex(parameterIndex), oid);
--- 816,826 ----
                  oid = Oid.BYTEA;
                  break;
              case Types.OTHER:
+                 // We cannot determine an appropriate OID in this case.
+                 throw new PSQLException("postgresql.prep.untypednull", PSQLState.INVALID_PARAMETER_TYPE);
              default:
!                 // Bad Types value.
!                 throw new PSQLException("postgresql.prep.type", PSQLState.INVALID_PARAMETER_TYPE);
          }

          preparedParameters.setNull(adjustParamIndex(parameterIndex), oid);
***************
*** 1372,1377 ****
--- 1374,1389 ----
              return new BigDecimal(x.toString()).toString();
      }

+     // Helper method for setting parameters to PGobject subclasses.
+     private void setPGobject(int parameterIndex, PGobject x) throws SQLException {
+         String typename = x.getType();
+         int oid = connection.getPGType(typename);
+         if (oid == Oid.INVALID)
+             throw new PSQLException("postgresql.prep.typenotfound", PSQLState.INVALID_PARAMETER_TYPE, typename);
+
+         setString(parameterIndex, x.getValue(), oid);
+     }
+
      /*
       * Set the value of a parameter using an object; use the java.lang
       * equivalent objects for integral values.
***************
*** 1478,1487 ****
                  setObject(parameterIndex, x);
                  break;
              case Types.OTHER:
!                 if (x instanceof PGobject)
!                     setString(parameterIndex, ((PGobject)x).getValue(), connection.getPGType( ((PGobject)x).getType()
));
!                 else
                      throw new PSQLException("postgresql.prep.type", PSQLState.INVALID_PARAMETER_TYPE);
                  break;
              default:
                  throw new PSQLException("postgresql.prep.type", PSQLState.INVALID_PARAMETER_TYPE);
--- 1490,1501 ----
                  setObject(parameterIndex, x);
                  break;
              case Types.OTHER:
!                 if (x instanceof PGobject) {
!                     setPGobject(parameterIndex, (PGobject)x);
!                 } else {
!                     // Nope. Go away!
                      throw new PSQLException("postgresql.prep.type", PSQLState.INVALID_PARAMETER_TYPE);
+                 }
                  break;
              default:
                  throw new PSQLException("postgresql.prep.type", PSQLState.INVALID_PARAMETER_TYPE);
***************
*** 1499,1509 ****
      public void setObject(int parameterIndex, Object x) throws SQLException
      {
          checkClosed();
!         if (x == null)
!         {
!             setNull(parameterIndex, Types.OTHER);
!             return;
          }
          if (x instanceof String)
              setString(parameterIndex, (String)x);
          else if (x instanceof BigDecimal)
--- 1513,1523 ----
      public void setObject(int parameterIndex, Object x) throws SQLException
      {
          checkClosed();
!         if (x == null) {
!             // We cannot determine an appropriate OID in this case.
!             throw new PSQLException("postgresql.prep.untypedsetobject", PSQLState.INVALID_PARAMETER_TYPE);
          }
+
          if (x instanceof String)
              setString(parameterIndex, (String)x);
          else if (x instanceof BigDecimal)
***************
*** 1529,1538 ****
          else if (x instanceof Boolean)
              setBoolean(parameterIndex, ((Boolean)x).booleanValue());
          else if (x instanceof PGobject)
!             setString(parameterIndex, ((PGobject)x).getValue(), connection.getPGType(((PGobject)x).getType()));
!         else
!             // Try to store as a string in database
!             setString(parameterIndex, x.toString(), 0);
      }

      /*
--- 1543,1553 ----
          else if (x instanceof Boolean)
              setBoolean(parameterIndex, ((Boolean)x).booleanValue());
          else if (x instanceof PGobject)
!             setPGobject(parameterIndex, (PGobject)x);
!         else {
!             // Nope. Go away!
!             throw new PSQLException("postgresql.prep.type", PSQLState.INVALID_PARAMETER_TYPE);
!         }
      }

      /*
Index: org/postgresql/test/jdbc2/GeometricTest.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/test/jdbc2/GeometricTest.java,v
retrieving revision 1.1
diff -u -c -r1.1 GeometricTest.java
*** org/postgresql/test/jdbc2/GeometricTest.java    29 Jun 2004 06:43:28 -0000    1.1
--- org/postgresql/test/jdbc2/GeometricTest.java    9 Oct 2004 10:13:42 -0000
***************
*** 44,50 ****
          Statement stmt = con.createStatement();
          ResultSet rs = stmt.executeQuery("SELECT " + column + " FROM testgeometric");
          assertTrue(rs.next());
!         assertEquals(obj, rs.getObject(1));
          rs.close();

          stmt.executeUpdate("DELETE FROM testgeometric");
--- 44,56 ----
          Statement stmt = con.createStatement();
          ResultSet rs = stmt.executeQuery("SELECT " + column + " FROM testgeometric");
          assertTrue(rs.next());
!         Object check = rs.getObject(1);
!         if (obj.getValue() == null) {
!             assertNull(check);
!             assertTrue(rs.wasNull());
!         } else {
!             assertEquals(obj, check);
!         }
          rs.close();

          stmt.executeUpdate("DELETE FROM testgeometric");
***************
*** 57,68 ****
--- 63,76 ----
          checkReadWrite(new PGbox(1.0, -2.0, 3.0, 4.0),  "boxval");
          checkReadWrite(new PGbox(1.0, 2.0, -3.0, 4.0),  "boxval");
          checkReadWrite(new PGbox(1.0, 2.0, 3.0, -4.0),  "boxval");
+         checkReadWrite(PGbox.NULL,  "boxval");
      }

      public void testPGcircle() throws Exception {
          checkReadWrite(new PGcircle(1.0, 2.0, 3.0),    "circleval");
          checkReadWrite(new PGcircle(-1.0, 2.0, 3.0),    "circleval");
          checkReadWrite(new PGcircle(1.0, -2.0, 3.0),    "circleval");
+         checkReadWrite(PGcircle.NULL, "circleval");
      }

      public void testPGlseg() throws Exception {
***************
*** 71,76 ****
--- 79,85 ----
          checkReadWrite(new PGlseg(1.0, -2.0, 3.0, 4.0), "lsegval");
          checkReadWrite(new PGlseg(1.0, 2.0, -3.0, 4.0), "lsegval");
          checkReadWrite(new PGlseg(1.0, 2.0, 3.0, -4.0), "lsegval");
+         checkReadWrite(PGlseg.NULL, "lsegval");
      }

      public void testPGpath() throws Exception {
***************
*** 85,90 ****
--- 94,100 ----

          checkReadWrite(new PGpath(points, true),  "pathval");
          checkReadWrite(new PGpath(points, false), "pathval");
+         checkReadWrite(PGpath.NULL, "pathval");
      }

      public void testPGpolygon() throws Exception {
***************
*** 98,106 ****
--- 108,118 ----
          };

          checkReadWrite(new PGpolygon(points), "polygonval");
+         checkReadWrite(PGpolygon.NULL, "polygonval");
      }

      public void testPGpoint() throws Exception {
          checkReadWrite(new PGpoint(1.0, 2.0), "pointval");
+         checkReadWrite(PGpoint.NULL, "pointval");
      }
  }
Index: org/postgresql/util/PGInterval.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/util/PGInterval.java,v
retrieving revision 1.2
diff -u -c -r1.2 PGInterval.java
*** org/postgresql/util/PGInterval.java    20 Sep 2004 08:36:51 -0000    1.2
--- org/postgresql/util/PGInterval.java    9 Oct 2004 10:13:42 -0000
***************
*** 4,23 ****

  public class PGInterval extends PGobject implements Serializable, Cloneable
  {
!   public PGInterval()
!   {
!     setType("interval");
!   }
!   public PGInterval(String value )
!   {
!     this.value = value;
!   }

!   /*
!    * This must be overidden to allow the object to be cloned
!    */
!   public Object clone()
!   {
!     return new PGInterval( value );
!   }
  }
--- 4,26 ----

  public class PGInterval extends PGobject implements Serializable, Cloneable
  {
!     public PGInterval()
!     {
!         setType("interval");
!     }

!     public PGInterval(String value)
!     {
!         this.value = value;
!     }
!
!     /*
!      * This must be overidden to allow the object to be cloned
!      */
!     public Object clone()
!     {
!         return new PGInterval( value );
!     }
!
!     public final static PGInterval NULL = new PGInterval();
  }
Index: org/postgresql/util/PGmoney.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/util/PGmoney.java,v
retrieving revision 1.7
diff -u -c -r1.7 PGmoney.java
*** org/postgresql/util/PGmoney.java    29 Nov 2003 19:52:11 -0000    1.7
--- org/postgresql/util/PGmoney.java    9 Oct 2004 10:13:42 -0000
***************
*** 81,86 ****
--- 81,93 ----
          if (obj instanceof PGmoney)
          {
              PGmoney p = (PGmoney)obj;
+
+             if (this == p)
+                 return true;
+
+             if (this == NULL || p == NULL)
+                 return false;
+
              return val == p.val;
          }
          return false;
***************
*** 91,101 ****
--- 98,114 ----
       */
      public Object clone()
      {
+         if (this == NULL)
+             return NULL;
+
          return new PGmoney(val);
      }

      public String getValue()
      {
+         if (this == NULL)
+             return null;
+
          if (val < 0)
          {
              return "-$" + ( -val);
***************
*** 105,108 ****
--- 118,127 ----
              return "$" + val;
          }
      }
+
+
+     // Ugly hack -- this unique object, by object identity, is a SQL NULL.
+     // Cloning NULL gives you NULL. You can mutate NULL, but it doesn't
+     // affect its NULL-ness.
+     public final static PGmoney NULL = new PGmoney();
  }
Index: org/postgresql/util/PGobject.java
===================================================================
RCS file: /usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/util/PGobject.java,v
retrieving revision 1.6
diff -u -c -r1.6 PGobject.java
*** org/postgresql/util/PGobject.java    7 Jun 2004 21:52:46 -0000    1.6
--- org/postgresql/util/PGobject.java    9 Oct 2004 10:13:42 -0000
***************
*** 62,68 ****

      /**
       * This must be overidden, to return the value of the object, in the
!      * form required by org.postgresql.
       * @return the value of this object
       */
      public String getValue()
--- 62,70 ----

      /**
       * This must be overidden, to return the value of the object, in the
!      * form required by org.postgresql. If this returns null, the object
!      * represents an appropriately-typed SQL NULL.
!      *
       * @return the value of this object
       */
      public String getValue()
***************
*** 99,104 ****
       */
      public String toString()
      {
!         return getValue();
      }
  }
--- 101,109 ----
       */
      public String toString()
      {
!         String value = getValue();
!         if (value == null)
!             return "NULL";
!         return value;
      }
  }

pgsql-jdbc by date:

Previous
From: Kris Jurka
Date:
Subject: Re: Using gettext
Next
From: Dave Cramer
Date:
Subject: Re: New jdbc website