Commit 7c553901 authored by Dave Cramer's avatar Dave Cramer

schema awareness patch provided by Kris Jurka

parent 2a1e4a90
...@@ -14,7 +14,7 @@ import org.postgresql.largeobject.LargeObjectManager; ...@@ -14,7 +14,7 @@ import org.postgresql.largeobject.LargeObjectManager;
import org.postgresql.util.*; import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.9 2002/09/11 05:38:44 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.10 2002/10/01 00:39:01 davec Exp $
* This class defines methods of the jdbc1 specification. This class is * This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2 * extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds the jdbc2
* methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection * methods. The real Connection class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Connection
...@@ -1147,6 +1147,11 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec ...@@ -1147,6 +1147,11 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
return dbVersionNumber; return dbVersionNumber;
} }
/**
* Is the server we are connected to running at least this version?
* This comparison method will fail whenever a major or minor version
* goes to two digits (10.3.0) or (7.10.1).
*/
public boolean haveMinimumServerVersion(String ver) throws SQLException public boolean haveMinimumServerVersion(String ver) throws SQLException
{ {
return (getDBVersionNumber().compareTo(ver) >= 0); return (getDBVersionNumber().compareTo(ver) >= 0);
...@@ -1184,16 +1189,29 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec ...@@ -1184,16 +1189,29 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
// it's not in the cache, so perform a query, and add the result to the cache // it's not in the cache, so perform a query, and add the result to the cache
if (sqlType == null) if (sqlType == null)
{ {
ResultSet result = ExecSQL("select typname from pg_type where oid = " + oid); String pgType;
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) // The opaque type does not exist in the system catalogs.
throw new PSQLException("postgresql.unexpected"); if (oid == 0) {
result.next(); pgType = "opaque";
String pgType = result.getString(1); } else {
String sql;
if (haveMinimumServerVersion("7.3")) {
sql = "SELECT typname FROM pg_catalog.pg_type WHERE oid = " +oid;
} else {
sql = "SELECT typname FROM pg_type WHERE oid = " +oid;
}
ResultSet result = ExecSQL(sql);
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) {
throw new PSQLException("postgresql.unexpected");
}
result.next();
pgType = result.getString(1);
result.close();
}
Integer iOid = new Integer(oid); Integer iOid = new Integer(oid);
sqlType = new Integer(getSQLType(result.getString(1))); sqlType = new Integer(getSQLType(pgType));
sqlTypeCache.put(iOid, sqlType); sqlTypeCache.put(iOid, sqlType);
pgTypeCache.put(iOid, pgType); pgTypeCache.put(iOid, pgType);
result.close();
} }
return sqlType.intValue(); return sqlType.intValue();
...@@ -1217,8 +1235,13 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec ...@@ -1217,8 +1235,13 @@ public abstract class AbstractJdbc1Connection implements org.postgresql.PGConnec
else else
{ {
// it's not in the cache, so perform a query, and add the result to the cache // it's not in the cache, so perform a query, and add the result to the cache
ResultSet result = ExecSQL("select oid from pg_type where typname='" String sql;
+ typeName + "'"); if (haveMinimumServerVersion("7.3")) {
sql = "SELECT oid FROM pg_catalog.pg_type WHERE typname='" + typeName + "'";
} else {
sql = "SELECT oid FROM pg_type WHERE typname='" + typeName + "'";
}
ResultSet result = ExecSQL(sql);
if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1) if (((AbstractJdbc1ResultSet)result).getColumnCount() != 1 || ((AbstractJdbc1ResultSet)result).getTupleCount() != 1)
throw new PSQLException("postgresql.unexpected"); throw new PSQLException("postgresql.unexpected");
result.next(); result.next();
......
...@@ -8,7 +8,7 @@ import java.util.Vector; ...@@ -8,7 +8,7 @@ import java.util.Vector;
import org.postgresql.largeobject.*; import org.postgresql.largeobject.*;
import org.postgresql.util.*; import org.postgresql.util.*;
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.10 2002/09/14 03:52:56 barry Exp $ /* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.11 2002/10/01 00:39:02 davec Exp $
* This class defines methods of the jdbc1 specification. This class is * This class defines methods of the jdbc1 specification. This class is
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2 * extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement * methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
...@@ -1757,8 +1757,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme ...@@ -1757,8 +1757,8 @@ public abstract class AbstractJdbc1Statement implements org.postgresql.PGStateme
*/ */
private void setSerialize(int parameterIndex, long x, String classname) throws SQLException private void setSerialize(int parameterIndex, long x, String classname) throws SQLException
{ {
// converts . to _, toLowerCase, and ensures length<32 // converts . to _, toLowerCase, and ensures length < max name length
String tablename = Serialize.toPostgreSQL( classname ); String tablename = Serialize.toPostgreSQL((java.sql.Connection)connection, classname );
DriverManager.println("setSerialize: setting " + x + "::" + tablename ); DriverManager.println("setSerialize: setting " + x + "::" + tablename );
// OID reference to tablerow-type must be cast like: <oid>::<tablename> // OID reference to tablerow-type must be cast like: <oid>::<tablename>
......
...@@ -103,15 +103,24 @@ public class LargeObjectManager ...@@ -103,15 +103,24 @@ public class LargeObjectManager
// //
// This is an example of Fastpath.addFunctions(); // This is an example of Fastpath.addFunctions();
// //
ResultSet res = conn.createStatement().executeQuery("select proname, oid from pg_proc" + String sql;
" where proname = 'lo_open'" + if (conn.getMetaData().supportsSchemasInTableDefinitions()) {
" or proname = 'lo_close'" + sql = "SELECT p.proname,p.oid "+
" or proname = 'lo_creat'" + " FROM pg_catalog.pg_proc p, pg_catalog.pg_namespace n "+
" or proname = 'lo_unlink'" + " WHERE p.pronamespace=n.oid AND n.nspname='pg_catalog' AND ";
" or proname = 'lo_lseek'" + } else {
" or proname = 'lo_tell'" + sql = "SELECT proname,oid FROM pg_proc WHERE ";
" or proname = 'loread'" + }
" or proname = 'lowrite'"); sql += " proname = 'lo_open'" +
" or proname = 'lo_close'" +
" or proname = 'lo_creat'" +
" or proname = 'lo_unlink'" +
" or proname = 'lo_lseek'" +
" or proname = 'lo_tell'" +
" or proname = 'loread'" +
" or proname = 'lowrite'";
ResultSet res = conn.createStatement().executeQuery(sql);
if (res == null) if (res == null)
throw new PSQLException("postgresql.lo.init"); throw new PSQLException("postgresql.lo.init");
......
...@@ -110,7 +110,7 @@ public class TestUtil ...@@ -110,7 +110,7 @@ public class TestUtil
try try
{ {
String sql = "DROP TABLE " + table; String sql = "DROP TABLE " + table;
if (con instanceof org.postgresql.jdbc1.AbstractJdbc1Connection && ((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3")) { if (haveMinimumServerVersion(con,"7.3")) {
sql += " CASCADE "; sql += " CASCADE ";
} }
stmt.executeUpdate(sql); stmt.executeUpdate(sql);
...@@ -190,4 +190,41 @@ public class TestUtil ...@@ -190,4 +190,41 @@ public class TestUtil
String s = "0000000000".substring(0, l) + Integer.toString(v); String s = "0000000000".substring(0, l) + Integer.toString(v);
return s.substring(s.length() - l); return s.substring(s.length() - l);
} }
/**
* Determine if the given connection is connected to a server with
* a version of at least the given version.
* This is convenient because we are working with a java.sql.Connection,
* not an Postgres connection.
*/
public static boolean haveMinimumServerVersion(Connection con, String version) throws SQLException {
if (con instanceof org.postgresql.jdbc1.AbstractJdbc1Connection) {
return ((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion(version);
}
return false;
}
/**
* Print a ResultSet to System.out.
* This is useful for debugging tests.
*/
public static void printResultSet(ResultSet rs) throws SQLException {
ResultSetMetaData rsmd = rs.getMetaData();
for (int i=1; i<=rsmd.getColumnCount(); i++) {
if (i != 1) {
System.out.print(", ");
}
System.out.print(rsmd.getColumnName(i));
}
System.out.println();
while (rs.next()) {
for (int i=1; i<=rsmd.getColumnCount(); i++) {
if (i != 1) {
System.out.print(", ");
}
System.out.print(rs.getString(i));
}
System.out.println();
}
}
} }
...@@ -25,8 +25,7 @@ public class Jdbc2TestSuite extends TestSuite ...@@ -25,8 +25,7 @@ public class Jdbc2TestSuite extends TestSuite
// complexity. // complexity.
// ANTTest should be first as it ensures that test parameters are // ANTTest should be first as it ensures that test parameters are
// being sent to the suite. It also initialises the database (if required) // being sent to the suite.
// with some simple global tables (will make each testcase use its own later).
// //
suite.addTestSuite(ANTTest.class); suite.addTestSuite(ANTTest.class);
...@@ -34,6 +33,7 @@ public class Jdbc2TestSuite extends TestSuite ...@@ -34,6 +33,7 @@ public class Jdbc2TestSuite extends TestSuite
suite.addTestSuite(DriverTest.class); suite.addTestSuite(DriverTest.class);
suite.addTestSuite(ConnectionTest.class); suite.addTestSuite(ConnectionTest.class);
suite.addTestSuite(DatabaseMetaDataTest.class); suite.addTestSuite(DatabaseMetaDataTest.class);
suite.addTestSuite(DatabaseMetaDataPropertiesTest.class);
suite.addTestSuite(EncodingTest.class); suite.addTestSuite(EncodingTest.class);
// Connectivity/Protocols // Connectivity/Protocols
...@@ -48,13 +48,12 @@ public class Jdbc2TestSuite extends TestSuite ...@@ -48,13 +48,12 @@ public class Jdbc2TestSuite extends TestSuite
// PreparedStatement // PreparedStatement
// ServerSide Prepared Statements // ServerSide Prepared Statements
suite.addTestSuite(ServerPreparedStmtTest.class); suite.addTestSuite(ServerPreparedStmtTest.class);
// BatchExecute // BatchExecute
suite.addTestSuite(BatchExecuteTest.class); suite.addTestSuite(BatchExecuteTest.class);
// MetaData
// Other misc tests, based on previous problems users have had or specific // Other misc tests, based on previous problems users have had or specific
// features some applications require. // features some applications require.
...@@ -63,6 +62,8 @@ public class Jdbc2TestSuite extends TestSuite ...@@ -63,6 +62,8 @@ public class Jdbc2TestSuite extends TestSuite
// Fastpath/LargeObject // Fastpath/LargeObject
suite.addTestSuite(BlobTest.class); suite.addTestSuite(BlobTest.class);
suite.addTestSuite(SerializeTest.class);
suite.addTestSuite(UpdateableResultTest.class ); suite.addTestSuite(UpdateableResultTest.class );
suite.addTestSuite(CallableStmtTest.class ); suite.addTestSuite(CallableStmtTest.class );
......
...@@ -45,7 +45,7 @@ public class ServerPreparedStmtTest extends TestCase ...@@ -45,7 +45,7 @@ public class ServerPreparedStmtTest extends TestCase
{ {
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = 2"); PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = 2");
((PGStatement)pstmt).setUseServerPrepare(true); ((PGStatement)pstmt).setUseServerPrepare(true);
if (((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3")) { if (TestUtil.haveMinimumServerVersion(con,"7.3")) {
assertTrue(((PGStatement)pstmt).isUseServerPrepare()); assertTrue(((PGStatement)pstmt).isUseServerPrepare());
} else { } else {
assertTrue(!((PGStatement)pstmt).isUseServerPrepare()); assertTrue(!((PGStatement)pstmt).isUseServerPrepare());
...@@ -85,7 +85,7 @@ public class ServerPreparedStmtTest extends TestCase ...@@ -85,7 +85,7 @@ public class ServerPreparedStmtTest extends TestCase
{ {
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = ?"); PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = ?");
((PGStatement)pstmt).setUseServerPrepare(true); ((PGStatement)pstmt).setUseServerPrepare(true);
if (((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3")) { if (TestUtil.haveMinimumServerVersion(con,"7.3")) {
assertTrue(((PGStatement)pstmt).isUseServerPrepare()); assertTrue(((PGStatement)pstmt).isUseServerPrepare());
} else { } else {
assertTrue(!((PGStatement)pstmt).isUseServerPrepare()); assertTrue(!((PGStatement)pstmt).isUseServerPrepare());
...@@ -126,7 +126,7 @@ public class ServerPreparedStmtTest extends TestCase ...@@ -126,7 +126,7 @@ public class ServerPreparedStmtTest extends TestCase
{ {
PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = ? or id = ?"); PreparedStatement pstmt = con.prepareStatement("SELECT * FROM testsps WHERE id = ? or id = ?");
((PGStatement)pstmt).setUseServerPrepare(true); ((PGStatement)pstmt).setUseServerPrepare(true);
if (((org.postgresql.jdbc1.AbstractJdbc1Connection)con).haveMinimumServerVersion("7.3")) { if (TestUtil.haveMinimumServerVersion(con,"7.3")) {
assertTrue(((PGStatement)pstmt).isUseServerPrepare()); assertTrue(((PGStatement)pstmt).isUseServerPrepare());
} else { } else {
assertTrue(!((PGStatement)pstmt).isUseServerPrepare()); assertTrue(!((PGStatement)pstmt).isUseServerPrepare());
......
...@@ -124,14 +124,14 @@ public class Serialize ...@@ -124,14 +124,14 @@ public class Serialize
* This creates an instance that can be used to serialize or deserialize * This creates an instance that can be used to serialize or deserialize
* a Java object from a PostgreSQL table. * a Java object from a PostgreSQL table.
*/ */
public Serialize(Connection c, String type) throws SQLException public Serialize(Connection conn, String type) throws SQLException
{ {
try try
{ {
conn = c; this.conn = conn;
if (Driver.logDebug) if (Driver.logDebug)
Driver.debug("Serialize: initializing instance for type: " + type); Driver.debug("Serialize: initializing instance for type: " + type);
tableName = toPostgreSQL(type); tableName = toPostgreSQL(conn,type);
className = type; className = type;
ourClass = Class.forName(className); ourClass = Class.forName(className);
} }
...@@ -144,7 +144,14 @@ public class Serialize ...@@ -144,7 +144,14 @@ public class Serialize
// Second check, the type must be a table // Second check, the type must be a table
boolean status = false; boolean status = false;
ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL("select typname from pg_type,pg_class where typname=relname and typname='" + tableName + "'"); String sql;
if (conn.getMetaData().supportsSchemasInTableDefinitions()) {
sql = "SELECT 1 FROM pg_catalog.pg_type t, pg_catalog.pg_class c WHERE t.typrelid=c.oid AND c.relkind='r' AND t.typname='" + tableName + "' AND pg_table_is_visible(c.oid) ";
} else {
sql = "SELECT 1 FROM pg_type t, pg_class c WHERE t.typrelid=c.oid AND c.relkind='r' AND t.typname='"+tableName+"'";
}
ResultSet rs = conn.createStatement().executeQuery(sql);
if (rs != null) if (rs != null)
{ {
if (rs.next()) if (rs.next())
...@@ -187,7 +194,7 @@ public class Serialize ...@@ -187,7 +194,7 @@ public class Serialize
* @return Object relating to oid * @return Object relating to oid
* @exception SQLException on error * @exception SQLException on error
*/ */
public Object fetch(int oid) throws SQLException public Object fetch(long oid) throws SQLException
{ {
try try
{ {
...@@ -228,7 +235,7 @@ public class Serialize ...@@ -228,7 +235,7 @@ public class Serialize
if (Driver.logDebug) if (Driver.logDebug)
Driver.debug("Serialize.fetch: " + sb.toString()); Driver.debug("Serialize.fetch: " + sb.toString());
ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)conn).ExecSQL(sb.toString()); ResultSet rs = conn.createStatement().executeQuery(sb.toString());
if (rs != null) if (rs != null)
{ {
...@@ -493,15 +500,22 @@ public class Serialize ...@@ -493,15 +500,22 @@ public class Serialize
* @param o Class to base table on * @param o Class to base table on
* @exception SQLException on error * @exception SQLException on error
*/ */
public static void create(Connection con, Class c) throws SQLException public static void create(Connection conn, Class c) throws SQLException
{ {
if (c.isInterface()) if (c.isInterface())
throw new PSQLException("postgresql.serial.interface"); throw new PSQLException("postgresql.serial.interface");
// See if the table exists // See if the table exists
String tableName = toPostgreSQL(c.getName()); String tableName = toPostgreSQL(conn,c.getName());
ResultSet rs = ((org.postgresql.jdbc1.AbstractJdbc1Connection)con).ExecSQL("select relname from pg_class where relname = '" + tableName + "'"); String sql;
if (conn.getMetaData().supportsSchemasInTableDefinitions()) {
sql = "SELECT 1 FROM pg_catalog.pg_class WHERE relkind='r' AND relname='" + tableName + "' AND pg_table_is_visible(oid) ";
} else {
sql = "SELECT 1 FROM pg_class WHERE relkind='r' AND relname='"+tableName+"'";
}
ResultSet rs = conn.createStatement().executeQuery(sql);
if ( rs.next() ) if ( rs.next() )
{ {
if (Driver.logDebug) if (Driver.logDebug)
...@@ -549,8 +563,8 @@ public class Serialize ...@@ -549,8 +563,8 @@ public class Serialize
sb.append(tp[j][1]); sb.append(tp[j][1]);
else else
{ {
create(con, type); create(conn, type);
sb.append(toPostgreSQL(n)); sb.append(toPostgreSQL(conn,n));
} }
} }
} }
...@@ -560,7 +574,7 @@ public class Serialize ...@@ -560,7 +574,7 @@ public class Serialize
// Now create the table // Now create the table
if (Driver.logDebug) if (Driver.logDebug)
Driver.debug("Serialize.create: " + sb ); Driver.debug("Serialize.create: " + sb );
((org.postgresql.jdbc1.AbstractJdbc1Connection)con).ExecSQL(sb.toString()); conn.createStatement().executeUpdate(sb.toString());
} }
// This is used to translate between Java primitives and PostgreSQL types. // This is used to translate between Java primitives and PostgreSQL types.
...@@ -582,35 +596,53 @@ public class Serialize ...@@ -582,35 +596,53 @@ public class Serialize
{"byte", "int2"} {"byte", "int2"}
}; };
/* /**
* This converts a Java Class name to a org.postgresql table, by replacing . with * This converts a Java Class name to a org.postgresql table, by replacing . with
* _<p> * _<p>
* *
* Because of this, a Class name may not have _ in the name.<p> * Because of this, a Class name may not have _ in the name.<p>
* Another limitation, is that the entire class name (including packages) * Another limitation, is that the entire class name (including packages)
* cannot be longer than 64 characters (a limit forced by PostgreSQL). * cannot be longer than the maximum table name length.
* *
* @param con The database connection
* @param name Class name * @param name Class name
* @return PostgreSQL table name * @return PostgreSQL table name
* @exception SQLException on error * @exception SQLException on error
* @since 7.3
*/ */
public static String toPostgreSQL(String name) throws SQLException public static String toPostgreSQL(Connection con, String name) throws SQLException
{ {
DatabaseMetaData dbmd = con.getMetaData();
int maxNameLength = dbmd.getMaxTableNameLength();
return toPostgreSQL(maxNameLength,name);
}
/**
* Convert a Java Class Name to an org.postgresql table name, by replacing .
* with _ <p>
*
* @deprecated Replaced by toPostgresql(connection, name) in 7.3
*/
public static String toPostgreSQL(String name) throws SQLException {
return toPostgreSQL(31,name);
}
private static String toPostgreSQL(int maxNameLength, String name) throws SQLException {
name = name.toLowerCase(); name = name.toLowerCase();
if (name.indexOf("_") > -1) if (name.indexOf("_") > -1)
throw new PSQLException("postgresql.serial.underscore"); throw new PSQLException("postgresql.serial.underscore");
// Postgres table names can only be 64 character long. // Postgres table names can only be so many characters long.
// Reserve 1 char, so allow only up to 63 chars.
// If the full class name with package is too long // If the full class name with package is too long
// then just use the class name. If the class name is // then just use the class name. If the class name is
// too long throw an exception. // too long throw an exception.
// //
if ( name.length() > 63 ) if ( name.length() > maxNameLength )
{ {
name = name.substring(name.lastIndexOf(".") + 1); name = name.substring(name.lastIndexOf(".") + 1);
if ( name.length() > 63 ) if ( name.length() > maxNameLength )
throw new PSQLException("postgresql.serial.namelength", name, new Integer(name.length())); throw new PSQLException("postgresql.serial.namelength", name, new Integer(name.length()));
} }
return name.replace('.', '_'); return name.replace('.', '_');
......
Markdown is supported
0% or
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment