From 215d965f0e9b36ed06fe019bd4795782274787c4 Mon Sep 17 00:00:00 2001 From: Barry Lind Date: Thu, 18 Sep 2003 04:14:27 +0000 Subject: [PATCH] Applied patch from Oliver Jowett to clean up some instances where the wrong type was being reported for PREPAREs. Modified Files: jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java jdbc/org/postgresql/test/jdbc2/ServerPreparedStmtTest.java --- .../jdbc1/AbstractJdbc1Statement.java | 59 +++++++++------- .../test/jdbc2/ServerPreparedStmtTest.java | 68 +++++++++++++++++-- 2 files changed, 96 insertions(+), 31 deletions(-) diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java index 93133c51d6..1e23fa51af 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1Statement.java @@ -26,7 +26,7 @@ import java.sql.Timestamp; import java.sql.Types; import java.util.Vector; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.37 2003/09/17 05:07:37 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.38 2003/09/18 04:14:27 barry Exp $ * This class defines methods of the jdbc1 specification. This class is * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement @@ -893,6 +893,9 @@ public abstract class AbstractJdbc1Statement implements BaseStatement case Types.TIMESTAMP: l_pgType = PG_TIMESTAMPTZ; break; + case Types.BIT: + l_pgType = PG_BOOLEAN; + break; case Types.BINARY: case Types.VARBINARY: case Types.LONGVARBINARY: @@ -930,7 +933,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement */ public void setByte(int parameterIndex, byte x) throws SQLException { - bind(parameterIndex, Integer.toString(x), PG_TEXT); + bind(parameterIndex, Integer.toString(x), PG_INT2); } /* @@ -1457,6 +1460,21 @@ public abstract class AbstractJdbc1Statement implements BaseStatement } } + // Helper method that extracts numeric values from an arbitary Object. + private String numericValueOf(Object x) + { + if (x instanceof Boolean) + return ((Boolean)x).booleanValue() ? "1" :"0"; + else if (x instanceof Integer || x instanceof Long || + x instanceof Double || x instanceof Short || + x instanceof Number || x instanceof Float) + return x.toString(); + else + //ensure the value is a valid numeric value to avoid + //sql injection attacks + return new BigDecimal(x.toString()).toString(); + } + /* * Set the value of a parameter using an object; use the java.lang * equivalent objects for integral values. @@ -1486,35 +1504,25 @@ public abstract class AbstractJdbc1Statement implements BaseStatement switch (targetSqlType) { case Types.INTEGER: - if (x instanceof Boolean) - bind(parameterIndex,((Boolean)x).booleanValue() ? "1" :"0", PG_BOOLEAN); - else if (x instanceof Integer || x instanceof Long || - x instanceof Double || x instanceof Short || - x instanceof Number || x instanceof Float ) - bind(parameterIndex, x.toString(), PG_INTEGER); - else - //ensure the value is a valid numeric value to avoid - //sql injection attacks - bind(parameterIndex, new BigDecimal(x.toString()).toString(), PG_INTEGER); + bind(parameterIndex, numericValueOf(x), PG_INTEGER); break; case Types.TINYINT: case Types.SMALLINT: + bind(parameterIndex, numericValueOf(x), PG_INT2); + break; case Types.BIGINT: + bind(parameterIndex, numericValueOf(x), PG_INT8); + break; case Types.REAL: case Types.FLOAT: + bind(parameterIndex, numericValueOf(x), PG_FLOAT); + break; case Types.DOUBLE: + bind(parameterIndex, numericValueOf(x), PG_DOUBLE); + break; case Types.DECIMAL: case Types.NUMERIC: - if (x instanceof Boolean) - bind(parameterIndex, ((Boolean)x).booleanValue() ? "1" : "0", PG_BOOLEAN); - else if (x instanceof Integer || x instanceof Long || - x instanceof Double || x instanceof Short || - x instanceof Number || x instanceof Float ) - bind(parameterIndex, x.toString(), PG_NUMERIC); - else - //ensure the value is a valid numeric value to avoid - //sql injection attacks - bind(parameterIndex, new BigDecimal(x.toString()).toString(), PG_NUMERIC); + bind(parameterIndex, numericValueOf(x), PG_NUMERIC); break; case Types.CHAR: case Types.VARCHAR: @@ -1559,7 +1567,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement } else if (x instanceof Number) { - bind(parameterIndex, ((Number)x).intValue()==1 ? "'1'" : "'0'", PG_BOOLEAN); + bind(parameterIndex, ((Number)x).intValue()!=0 ? "'1'" : "'0'", PG_BOOLEAN); } else { @@ -1572,7 +1580,10 @@ public abstract class AbstractJdbc1Statement implements BaseStatement setObject(parameterIndex, x); break; case Types.OTHER: - setString(parameterIndex, ((PGobject)x).getValue(), PG_TEXT); + if (x instanceof PGobject) + setString(parameterIndex, ((PGobject)x).getValue(), ((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); diff --git a/src/interfaces/jdbc/org/postgresql/test/jdbc2/ServerPreparedStmtTest.java b/src/interfaces/jdbc/org/postgresql/test/jdbc2/ServerPreparedStmtTest.java index ea819b3633..aa5831385f 100644 --- a/src/interfaces/jdbc/org/postgresql/test/jdbc2/ServerPreparedStmtTest.java +++ b/src/interfaces/jdbc/org/postgresql/test/jdbc2/ServerPreparedStmtTest.java @@ -26,14 +26,14 @@ public class ServerPreparedStmtTest extends TestCase con = TestUtil.openDB(); Statement stmt = con.createStatement(); - TestUtil.createTable(con, "testsps", "id integer"); + TestUtil.createTable(con, "testsps", "id integer, value boolean"); - stmt.executeUpdate("INSERT INTO testsps VALUES (1)"); - stmt.executeUpdate("INSERT INTO testsps VALUES (2)"); - stmt.executeUpdate("INSERT INTO testsps VALUES (3)"); - stmt.executeUpdate("INSERT INTO testsps VALUES (4)"); - stmt.executeUpdate("INSERT INTO testsps VALUES (6)"); - stmt.executeUpdate("INSERT INTO testsps VALUES (9)"); + stmt.executeUpdate("INSERT INTO testsps VALUES (1,'t')"); + stmt.executeUpdate("INSERT INTO testsps VALUES (2,'t')"); + stmt.executeUpdate("INSERT INTO testsps VALUES (3,'t')"); + stmt.executeUpdate("INSERT INTO testsps VALUES (4,'t')"); + stmt.executeUpdate("INSERT INTO testsps VALUES (6,'t')"); + stmt.executeUpdate("INSERT INTO testsps VALUES (9,'f')"); stmt.close(); } @@ -125,6 +125,60 @@ public class ServerPreparedStmtTest extends TestCase pstmt.close(); } + // Verify we can bind booleans-as-objects ok. + public void testBooleanObjectBind() throws Exception + { + PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE value = ?"); + ((PGStatement)pstmt).setUseServerPrepare(true); + if (TestUtil.haveMinimumServerVersion(con,"7.3")) { + assertTrue(((PGStatement)pstmt).isUseServerPrepare()); + } else { + assertTrue(!((PGStatement)pstmt).isUseServerPrepare()); + } + + pstmt.setObject(1, new Boolean(false), java.sql.Types.BIT); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(9, rs.getInt(1)); + rs.close(); + } + + // Verify we can bind booleans-as-integers ok. + public void testBooleanIntegerBind() throws Exception + { + PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = ?"); + ((PGStatement)pstmt).setUseServerPrepare(true); + if (TestUtil.haveMinimumServerVersion(con,"7.3")) { + assertTrue(((PGStatement)pstmt).isUseServerPrepare()); + } else { + assertTrue(!((PGStatement)pstmt).isUseServerPrepare()); + } + + pstmt.setObject(1, new Boolean(true), java.sql.Types.INTEGER); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(1, rs.getInt(1)); + rs.close(); + } + + // Verify we can bind booleans-as-native-types ok. + public void testBooleanBind() throws Exception + { + PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE value = ?"); + ((PGStatement)pstmt).setUseServerPrepare(true); + if (TestUtil.haveMinimumServerVersion(con,"7.3")) { + assertTrue(((PGStatement)pstmt).isUseServerPrepare()); + } else { + assertTrue(!((PGStatement)pstmt).isUseServerPrepare()); + } + + pstmt.setBoolean(1, false); + ResultSet rs = pstmt.executeQuery(); + assertTrue(rs.next()); + assertEquals(9, rs.getInt(1)); + rs.close(); + } + public void testPreparedStatementsWithBinds() throws Exception { PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = ? or id = ?");