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, use setObject(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; } }