Peter's Mega-Patch for JDBC...

see README_6.3 for list of changes
This commit is contained in:
Marc G. Fournier 1998-01-11 21:14:56 +00:00
parent 4bad5be7bc
commit ba977c086c
13 changed files with 1276 additions and 306 deletions

View File

@ -4,7 +4,7 @@
# Makefile for Java JDBC interface
#
# IDENTIFICATION
# $Header: /cvsroot/pgsql/src/interfaces/jdbc/Attic/Makefile,v 1.2 1997/09/29 20:11:42 scrappy Exp $
# $Header: /cvsroot/pgsql/src/interfaces/jdbc/Attic/Makefile,v 1.3 1998/01/11 21:14:29 scrappy Exp $
#
#-------------------------------------------------------------------------
@ -22,41 +22,70 @@ RM = rm -f
$(JAVAC) $<
.SUFFIXES: .class .java
.PHONY: all clean doc
.PHONY: all clean doc examples
all: postgresql.jar
@echo ------------------------------------------------------------
@echo The JDBC driver has now been built. To make it available to
@echo other applications, copy the postgresql.jar file to a public
@echo "place (under unix this could be /usr/local/lib) and add it"
@echo to the class path.
@echo
@echo Then either add -Djdbc.drivers=postgresql.Driver to the
@echo commandline when running your application, or edit the
@echo "properties file (~/.hotjava/properties under unix), and"
@echo add a line containing jdbc.drivers=postgresql.Driver
@echo
@echo More details are in the README file.
@echo ------------------------------------------------------------
@echo To build the examples, type:
@echo " make examples"
@echo ------------------------------------------------------------
@echo
# This rule builds the javadoc documentation
doc:
$(JAVADOC) -public postgresql
export CLASSPATH=.;\
$(JAVADOC) -public \
postgresql \
postgresql.fastpath \
postgresql.largeobject
# These classes form the driver. These, and only these are placed into
# the jar file.
OBJS= postgresql/CallableStatement.class \
postgresql/Connection.class \
postgresql/DatabaseMetaData.class \
postgresql/Driver.class \
postgresql/Field.class \
postgresql/PG_Object.class \
postgresql/PG_Stream.class \
postgresql/PGbox.class \
postgresql/PGcircle.class \
postgresql/PGlobj.class \
postgresql/PGlseg.class \
postgresql/PGpath.class \
postgresql/PGpoint.class \
postgresql/PGpolygon.class \
postgresql/PGtokenizer.class \
postgresql/PreparedStatement.class \
postgresql/ResultSet.class \
postgresql/ResultSetMetaData.class \
postgresql/Statement.class
postgresql/Statement.class \
postgresql/fastpath/Fastpath.class \
postgresql/fastpath/FastpathArg.class \
postgresql/geometric/PGbox.class \
postgresql/geometric/PGcircle.class \
postgresql/geometric/PGlseg.class \
postgresql/geometric/PGpath.class \
postgresql/geometric/PGpoint.class \
postgresql/geometric/PGpolygon.class \
postgresql/largeobject/LargeObject.class \
postgresql/largeobject/LargeObjectManager.class \
postgresql/util/PGobject.class \
postgresql/util/PGtokenizer.class
postgresql.jar: $(OBJS)
$(JAR) -c0vf $@ $^
$(JAR) -c0vf $@ $$($(FIND) postgresql -name "*.class" -print)
# This rule removes any temporary and compiled files from the source tree.
clean:
$(FIND) . -name "*~" -exec $(RM) {} \;
$(FIND) . -name "*.class" -exec $(RM) {} \;
$(FIND) . -name "*.html" -exec $(RM) {} \;
$(RM) postgresql.jar
-$(RM) -rf Package-postgresql *output
#######################################################################
# This helps make workout what classes are from what source files
@ -69,21 +98,56 @@ postgresql/Connection.class: postgresql/Connection.java
postgresql/DatabaseMetaData.class: postgresql/DatabaseMetaData.java
postgresql/Driver.class: postgresql/Driver.java
postgresql/Field.class: postgresql/Field.java
postgresql/PG_Object.class: postgresql/PG_Object.java
postgresql/PG_Stream.class: postgresql/PG_Stream.java
postgresql/PGbox.class: postgresql/PGbox.java
postgresql/PGcircle.class: postgresql/PGcircle.java
postgresql/PGlobj.class: postgresql/PGlobj.java
postgresql/PGlseg.class: postgresql/PGlseg.java
postgresql/PGpath.class: postgresql/PGpath.java
postgresql/PGpoint.class: postgresql/PGpoint.java
postgresql/PGpolygon.class: postgresql/PGpolygon.java
postgresql/PGtokenizer.class: postgresql/PGtokenizer.java
postgresql/PreparedStatement.class: postgresql/PreparedStatement.java
postgresql/ResultSet.class: postgresql/ResultSet.java
postgresql/ResultSetMetaData.class: postgresql/ResultSetMetaData.java
postgresql/Statement.class: postgresql/Statement.java
postgresql/fastpath/Fastpath.class: postgresql/fastpath/Fastpath.java
postgresql/fastpath/FastpathArg.class: postgresql/fastpath/FastpathArg.java
postgresql/geometric/PGbox.class: postgresql/geometric/PGbox.java
postgresql/geometric/PGcircle.class: postgresql/geometric/PGcircle.java
postgresql/geometric/PGlseg.class: postgresql/geometric/PGlseg.java
postgresql/geometric/PGpath.class: postgresql/geometric/PGpath.java
postgresql/geometric/PGpoint.class: postgresql/geometric/PGpoint.java
postgresql/geometric/PGpolygon.class: postgresql/geometric/PGpolygon.java
postgresql/largeobject/LargeObject.class: postgresql/largeobject/LargeObject.java
postgresql/largeobject/LargeObjectManager.class: postgresql/largeobject/LargeObjectManager.java
postgresql/util/PGobject.class: postgresql/util/PGobject.java
postgresql/util/PGtokenizer.class: postgresql/util/PGtokenizer.java
#######################################################################
# These classes are in the example directory, and form the examples
EX= example/basic.class \
example/blobtest.class \
example/datestyle.class \
example/psql.class \
example/ImageViewer.class
# This rule builds the examples
examples: postgresql.jar $(EX)
@echo ------------------------------------------------------------
@echo The examples have been built.
@echo
@echo For instructions on how to use them, simply run them. For example:
@echo
@echo " java example.blobtest"
@echo
@echo This would display instructions on how to run the example.
@echo ------------------------------------------------------------
@echo Available examples:
@echo
@echo " example.basic Basic JDBC useage"
@echo " example.blobtest Binary Large Object tests"
@echo " example.datestyle Shows how datestyles are handled"
@echo " example.ImageViewer Example application storing images"
@echo " example.psql Simple java implementation of psql"
@echo ------------------------------------------------------------
@echo
example/basic.class: example/basic.java
example/blobtest.class: example/blobtest.java
example/datestyle.class: example/datestyle.java
example/psql.class: example/psql.java
example/ImageViewer.class: example/ImageViewer.java
#######################################################################

View File

@ -10,6 +10,14 @@ or the JDBC mailing list:
http://www.blackdown.org
For problems with this driver, then refer to the postgres-interfaces email
list:
http://www.postgresql.org
By the time V6.3 is released, full documentation will be on the web, and in
the distribution.
---------------------------------------------------------------------------
COMPILING
@ -115,15 +123,21 @@ them to the URL. eg:
By default, the driver doesn't use password authentication. You can enable
this by adding the argument auth. ie:
jdbc:postgresql:database?user=me&password=mypass&auth=y
jdbc:postgresql:database?user=me&password=mypass&auth=password
or if passing the user & password directly via DriverManager.getConnection():
jdbc:postgresql:database?auth=y
jdbc:postgresql:database?auth=password
PS: Password authentication is enabled if the value of auth starts with 'y'.
PS: Password authentication is enabled if the value of auth starts with 'p'.
It is case insensitive.
As of postgresql 6.3, Ident (RFC 1413) authentication is also supported.
Simply use auth=ident in the url.
Also, as of 6.3, a system property of postgresql.auth is supported. This
defines the default authentication to use. The auth property overides this.
---------------------------------------------------------------------------
That's the basics related to this driver. You'll need to read the JDBC Docs
@ -180,7 +194,7 @@ syntax for writing these to the database.
---------------------------------------------------------------------------
Peter T Mount, October 28 1997
Peter T Mount, January 11 1998
home email: pmount@maidast.demon.co.uk http://www.demon.co.uk/finder
work email: peter@maidstone.gov.uk http://www.maidstone.gov.uk

View File

@ -0,0 +1,78 @@
Ok, here's the JDBC patch.
The jdbc6.3.tar.gz file that I've uploaded ftp.postgresql.org contains the
following files:
README_6.3 This message
blob.patch The patch to src/backend/tcop/fastpath.c fixing large objects
jdbc.tar The entire jdbc driver
I've put the entire driver here, rather than a patch, because its become
too complicated to do one this time. Files have been moved, two files
removed because they were obsolete, and there are a lot of new files.
Heres what the patch does:
* Memory overflow problem in the backend causing large objects to fail in
both libpq & jdbc (causing the backend to crash with a Segmentation
Violation)
* Problem with equals() method on the geometric support classes if the
class being checked wasn't the same class
* Fixed output of PGpath and PGpolygon support classes (missing , separator)
* Optimised the geometric support classes
* HTMLised the inline documentation, so the output of javadoc is easier
to read (mainly paragraphs)
* Removed obsolete class PGlobj (it never worked, and has been replaced
to read (mainly paragraphs)
* Removed obsolete class PGlobj (it never worked, and has been replaced
by the postgresql.largeobject package)
* Removed obsolete example JDBC_Test.java (replaced by new examples)
* Added < and > to nesting in PGtokenizer.
* Added fastpath support as a new package
* Added large object support as a new package
* Added ability of user code to handle custom storage types.
* Added new example testing the importing and exporting of a large object
* Added example application showing how to store and display images stored
as large objects
* Added example implementing part of psql client. This shows how to find out
what tables/columns are in a database (not yet complete)
* ResultSet.getBytes() now returns large object if field is an oid
* ResultSet.getString() now doesn't call getBytes() as this now would
cause an infinite loop because of large object support in getBytes()
* PreparedStatement.setBytes() now create a large object, and store its
oid into the column
* Reworked date style handling to make it easier to support new styles
* Added german and ISO styles, now all styles supported by postgresql
are now supported by the driver
* Fixed DatabaseMetaData.getTables()
* DatabaseMetaData.getTableTypes() returns our supported types.
* Fixed DatabaseMetaData.getColumns()
These three are required for Borland's JBuilder to work. For now they
return an empty result, as I'm not sure yet on how to get the
required results.
* DatabaseMetaData.getBestRowIdentifier()
* DatabaseMetaData.getProcedureColumns()
* DatabaseMetaData.getIndexInfo()
Finally, one change that is incompatible with earlier versions of the
driver. This change only affects any client code that uses the geometric
classes (eg: PGpoint) or the getObject()/setObject() methods.
Because of a problem with javac, if user code includes the line:
import postgresql.*;
then javac will fail, saying that interfaces cannot be instanciated.
To fix this, I've moved these classes into a new sub package,
postgresql.geometric and the PG_Object (renamed PGobject), and PGtokenizer
to postgresql.util.So the above line would become:
import postgresql.geometric.*;
Anyhow, I'm going to start writing some proper documentation for the
driver. For now, there is some available temporarily at:
http://www.demon.co.uk/finder/postgres/jdbc/packages.html

View File

@ -4,46 +4,114 @@ import java.sql.*;
import java.math.*;
/**
* JDBC Interface to Postgres95 functions
* CallableStatement is used to execute SQL stored procedures.
*
* <p>JDBC provides a stored procedure SQL escape that allows stored
* procedures to be called in a standard way for all RDBMS's. This escape
* syntax has one form that includes a result parameter and one that does
* not. If used, the result parameter must be registered as an OUT
* parameter. The other parameters may be used for input, output or both.
* Parameters are refered to sequentially, by number. The first parameter
* is 1.
*
* {?= call <procedure-name>[<arg1>,<arg2>, ...]}
* {call <procedure-name>[<arg1>,<arg2>, ...]}
*
*
* <p>IN parameter values are set using the set methods inherited from
* PreparedStatement. The type of all OUT parameters must be registered
* prior to executing the stored procedure; their values are retrieved
* after execution via the get methods provided here.
*
* <p>A Callable statement may return a ResultSet or multiple ResultSets.
* Multiple ResultSets are handled using operations inherited from
* Statement.
*
* <p>For maximum portability, a call's ResultSets and update counts should
* be processed prior to getting the values of output parameters.
*
* @see Connection#prepareCall
* @see ResultSet
*/
// Copy methods from the Result set object here.
public class CallableStatement extends PreparedStatement implements java.sql.CallableStatement
{
/**
* @exception SQLException on failure
*/
CallableStatement(Connection c,String q) throws SQLException
{
super(c,q);
}
// Before executing a stored procedure call you must explicitly
// call registerOutParameter to register the java.sql.Type of each
// out parameter.
/**
* Before executing a stored procedure call you must explicitly
* call registerOutParameter to register the java.sql.Type of each
* out parameter.
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType SQL type code defined by java.sql.Types; for
* parameters of type Numeric or Decimal use the version of
* registerOutParameter that accepts a scale value
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType) throws SQLException {
}
// You must also specify the scale for numeric/decimal types:
/**
* You must also specify the scale for numeric/decimal types:
*
* <p>Note: When reading the value of an out parameter, you must use
* the getXXX method whose Java type XXX corresponds to the
* parameter's registered SQL type.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param sqlType use either java.sql.Type.NUMERIC or java.sql.Type.DECIMAL
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @exception SQLException if a database-access error occurs.
*/
public void registerOutParameter(int parameterIndex, int sqlType,
int scale) throws SQLException
{
}
public boolean isNull(int parameterIndex) throws SQLException {
return true;
}
// Old api?
//public boolean isNull(int parameterIndex) throws SQLException {
//return true;
//}
// New API (JPM)
/**
* An OUT parameter may have the value of SQL NULL; wasNull
* reports whether the last value read has this special value.
*
* <p>Note: You must first call getXXX on a parameter to read its
* value and then call wasNull() to see if the value was SQL NULL.
* @return true if the last parameter read was SQL NULL
* @exception SQLException if a database-access error occurs.
*/
public boolean wasNull() throws SQLException {
// check to see if the last access threw an exception
return false; // fake it for now
}
// Methods for retrieving OUT parameters from this statement.
public String getChar(int parameterIndex) throws SQLException {
return null;
}
// Old api?
//public String getChar(int parameterIndex) throws SQLException {
//return null;
//}
// New API (JPM)
/**
* Get the value of a CHAR, VARCHAR, or LONGVARCHAR parameter as a
* Java String.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public String getString(int parameterIndex) throws SQLException {
return null;
}
@ -51,64 +119,148 @@ public class CallableStatement extends PreparedStatement implements java.sql.Cal
// return null;
//}
public String getLongVarChar(int parameterIndex) throws SQLException {
return null;
}
//public String getLongVarChar(int parameterIndex) throws SQLException {
//return null;
//}
// New API (JPM) (getBit)
/**
* Get the value of a BIT parameter as a Java boolean.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is false
* @exception SQLException if a database-access error occurs.
*/
public boolean getBoolean(int parameterIndex) throws SQLException {
return false;
}
// New API (JPM) (getTinyInt)
/**
* Get the value of a TINYINT parameter as a Java byte.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public byte getByte(int parameterIndex) throws SQLException {
return 0;
}
// New API (JPM) (getSmallInt)
/**
* Get the value of a SMALLINT parameter as a Java short.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public short getShort(int parameterIndex) throws SQLException {
return 0;
}
// New API (JPM) (getInteger)
public int getInt(int parameterIndex) throws SQLException {
/**
* Get the value of an INTEGER parameter as a Java int.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public int getInt(int parameterIndex) throws SQLException {
return 0;
}
// New API (JPM) (getBigInt)
/**
* Get the value of a BIGINT parameter as a Java long.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public long getLong(int parameterIndex) throws SQLException {
return 0;
}
/**
* Get the value of a FLOAT parameter as a Java float.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public float getFloat(int parameterIndex) throws SQLException {
return (float) 0.0;
}
/**
* Get the value of a DOUBLE parameter as a Java double.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is 0
* @exception SQLException if a database-access error occurs.
*/
public double getDouble(int parameterIndex) throws SQLException {
return 0.0;
}
/**
* Get the value of a NUMERIC parameter as a java.math.BigDecimal
* object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @param scale a value greater than or equal to zero representing the
* desired number of digits to the right of the decimal point
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public BigDecimal getBigDecimal(int parameterIndex, int scale)
throws SQLException {
return null;
}
// New API (JPM) (getBinary)
/**
* Get the value of a SQL BINARY or VARBINARY parameter as a Java
* byte[]
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public byte[] getBytes(int parameterIndex) throws SQLException {
return null;
}
// New API (JPM) (getLongVarBinary)
public byte[] getBinaryStream(int parameterIndex) throws SQLException {
return null;
}
//public byte[] getBinaryStream(int parameterIndex) throws SQLException {
//return null;
//}
/**
* Get the value of a SQL DATE parameter as a java.sql.Date object
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Date getDate(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL TIME parameter as a java.sql.Time object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Time getTime(int parameterIndex) throws SQLException {
return null;
}
/**
* Get the value of a SQL TIMESTAMP parameter as a java.sql.Timestamp object.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return the parameter value; if the value is SQL NULL, the result is null
* @exception SQLException if a database-access error occurs.
*/
public java.sql.Timestamp getTimestamp(int parameterIndex)
throws SQLException {
return null;
@ -119,12 +271,30 @@ public class CallableStatement extends PreparedStatement implements java.sql.Cal
// You can obtain a ParameterMetaData object to get information
// about the parameters to this CallableStatement.
public DatabaseMetaData getMetaData() {
return null;
}
//public DatabaseMetaData getMetaData() {
//return null;
//}
// getObject returns a Java object for the parameter.
// See the JDBC spec's "Dynamic Programming" chapter for details.
/**
* Get the value of a parameter as a Java object.
*
* <p>This method returns a Java object whose type coresponds to the
* SQL type that was registered for this parameter using
* registerOutParameter.
*
* <P>Note that this method may be used to read datatabase-specific,
* abstract data types. This is done by specifying a targetSqlType
* of java.sql.types.OTHER, which allows the driver to return a
* database-specific Java type.
*
* <p>See the JDBC spec's "Dynamic Programming" chapter for details.
*
* @param parameterIndex the first parameter is 1, the second is 2,...
* @return A java.lang.Object holding the OUT parameter value.
* @exception SQLException if a database-access error occurs.
*/
public Object getObject(int parameterIndex)
throws SQLException {
return null;

View File

@ -5,22 +5,21 @@ import java.lang.*;
import java.net.*;
import java.util.*;
import java.sql.*;
import postgresql.*;
import postgresql.fastpath.*;
import postgresql.largeobject.*;
import postgresql.util.*;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
* returned.
*
* A Connection's database is able to provide information describing
* <P>A Connection's database is able to provide information describing
* its tables, its supported SQL grammar, its stored procedures, the
* capabilities of this connection, etc. This information is obtained
* with the getMetaData method.
*
* <B>Note:</B> By default, the Connection automatically commits changes
* <p><B>Note:</B> By default, the Connection automatically commits changes
* after executing each statement. If auto-commit has been disabled, an
* explicit commit must be done or database changes will not be saved.
*
@ -28,8 +27,12 @@ import postgresql.*;
*/
public class Connection implements java.sql.Connection
{
// This is the network stream associated with this connection
protected PG_Stream pg_stream;
// This is set by postgresql.Statement.setMaxRows()
protected int maxrows = 0; // maximum no. of rows; 0 = unlimited
private String PG_HOST;
private int PG_PORT;
private String PG_USER;
@ -59,7 +62,39 @@ public class Connection implements java.sql.Connection
private String cursor = null; // The positioned update cursor name
// This is false for US, true for European date formats
protected boolean europeanDates = false;
//protected boolean europeanDates = false;
/**
* This is the current date style of the backend
*/
protected int currentDateStyle;
/**
* This defines the formats for dates, according to the various date styles.
*
* <p>There are two strings for each entry. The first is the string to search
* for in the datestyle message, and the second the format to use.
*
* <p>To add a new date style, work out the format. Then with psql running
* in the date style you wish to add, type: show datestyle;
*
* <p>eg:
* <br><pre>
* => show datestyle;
* NOTICE: Datestyle is SQL with European conventions
* ^^^^^^^^^^^^^^^^^
* </pre>The marked part of the string is the first string below. The second
* is your format. If a style (like ISO) ignores the US/European variants,
* then you can ignore the "with" part of the string.
*/
protected static final String dateStyles[] = {
"Postgres with European", "dd-MM-yyyy",
"Postgres with US", "MM-dd-yyyy",
"ISO", "yyyy-MM-dd",
"SQL with European", "dd/MM/yyyy",
"SQL with US", "MM/dd/yyyy",
"German", "dd.MM.yyyy"
};
// Now handle notices as warnings, so things like "show" now work
protected SQLWarning firstWarning = null;
@ -67,6 +102,13 @@ public class Connection implements java.sql.Connection
/**
* Connect to a PostgreSQL database back end.
*
* <p><b>Important Notice</b>
*
* <br>Although this will connect to the database, user code should open
* the connection via the DriverManager.getConnection() methods only.
*
* <br>This should only be called from the postgresql.Driver class.
*
* @param host the hostname of the database back end
* @param port the port number of the postmaster process
* @param info a Properties[] thing of the user and password
@ -108,6 +150,7 @@ public class Connection implements java.sql.Connection
STARTUP_CODE=STARTUP_USER;
}
// Now make the initial connection
try
{
pg_stream = new PG_Stream(host, port);
@ -148,6 +191,9 @@ public class Connection implements java.sql.Connection
clearWarnings();
ExecSQL("show datestyle");
// Initialise object handling
initObjectTypes();
// Mark the connection as ok, and cleanup
clearWarnings();
PG_STATUS = CONNECTION_OK;
@ -468,10 +514,15 @@ public class Connection implements java.sql.Connection
// **********************************************************
/**
* This adds a warning to the warning chain
* This adds a warning to the warning chain.
* @param msg message to add
*/
public void addWarning(String msg)
{
//PrintStream log = DriverManager.getLogStream();
//if(log!=null)
DriverManager.println(msg);
// Add the warning to the chain
if(firstWarning!=null)
firstWarning.setNextWarning(new SQLWarning(msg));
@ -481,15 +532,24 @@ public class Connection implements java.sql.Connection
// Now check for some specific messages
// This is generated by the SQL "show datestyle"
if(msg.startsWith("NOTICE:DateStyle")) {
if(msg.indexOf("with US")==-1)
europeanDates=true;
else
europeanDates=false;
System.err.println("europeanDates="+europeanDates);
if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) {
// 13 is the length off "DateStyle is "
msg = msg.substring(msg.indexOf("DateStyle is ")+13);
for(int i=0;i<dateStyles.length;i+=2)
if(msg.startsWith(dateStyles[i]))
currentDateStyle=i+1; // this is the index of the format
}
}
/**
* @return the date format for the current date style of the backend
*/
public String getDateStyle()
{
return dateStyles[currentDateStyle];
}
/**
* Send a query to the backend. Returns one of the ResultSet
* objects.
@ -525,6 +585,8 @@ public class Connection implements java.sql.Connection
while (!hfr || fqp > 0)
{
Object tup=null; // holds rows as they are recieved
int c = pg_stream.ReceiveChar();
switch (c)
@ -536,7 +598,10 @@ public class Connection implements java.sql.Connection
case 'B': // Binary Data Transfer
if (fields == null)
throw new SQLException("Tuple received before MetaData");
tuples.addElement(pg_stream.ReceiveTuple(fields.length, true));
tup = pg_stream.ReceiveTuple(fields.length, true);
// This implements Statement.setMaxRows()
if(maxrows==0 || tuples.size()<maxrows)
tuples.addElement(tup);
break;
case 'C': // Command Status
recv_status = pg_stream.ReceiveString(8192);
@ -558,7 +623,10 @@ public class Connection implements java.sql.Connection
case 'D': // Text Data Transfer
if (fields == null)
throw new SQLException("Tuple received before MetaData");
tuples.addElement(pg_stream.ReceiveTuple(fields.length, false));
tup = pg_stream.ReceiveTuple(fields.length, false);
// This implements Statement.setMaxRows()
if(maxrows==0 || tuples.size()<maxrows)
tuples.addElement(tup);
break;
case 'E': // Error Message
msg = pg_stream.ReceiveString(4096);
@ -576,10 +644,7 @@ public class Connection implements java.sql.Connection
hfr = true;
break;
case 'N': // Error Notification
msg = pg_stream.ReceiveString(4096);
PrintStream log = DriverManager.getLogStream();
if(log!=null) log.println(msg);
addWarning(msg);
addWarning(pg_stream.ReceiveString(4096));
break;
case 'P': // Portal Name
String pname = pg_stream.ReceiveString(8192);
@ -675,14 +740,143 @@ public class Connection implements java.sql.Connection
}
/**
* This method is not part of the Connection interface. Its is an extension
* that allows access to the PostgreSQL Large Object API
* This returns the Fastpath API for the current connection.
*
* @return PGlobj class that implements the API
* <p><b>NOTE:</b> This is not part of JDBC, but allows access to
* functions on the postgresql backend itself.
*
* <p>It is primarily used by the LargeObject API
*
* <p>The best way to use this is as follows:
*
* <p><pre>
* import postgresql.fastpath.*;
* ...
* Fastpath fp = ((postgresql.Connection)myconn).getFastpathAPI();
* </pre>
*
* <p>where myconn is an open Connection to postgresql.
*
* @return Fastpath object allowing access to functions on the postgresql
* backend.
* @exception SQLException by Fastpath when initialising for first time
*/
public PGlobj getLargeObjectAPI() throws SQLException
public Fastpath getFastpathAPI() throws SQLException
{
return new PGlobj(this);
if(fastpath==null)
fastpath = new Fastpath(this,pg_stream);
return fastpath;
}
// This holds a reference to the Fastpath API if already open
private Fastpath fastpath = null;
/**
* This returns the LargeObject API for the current connection.
*
* <p><b>NOTE:</b> This is not part of JDBC, but allows access to
* functions on the postgresql backend itself.
*
* <p>The best way to use this is as follows:
*
* <p><pre>
* import postgresql.largeobject.*;
* ...
* LargeObjectManager lo = ((postgresql.Connection)myconn).getLargeObjectAPI();
* </pre>
*
* <p>where myconn is an open Connection to postgresql.
*
* @return LargeObject object that implements the API
* @exception SQLException by LargeObject when initialising for first time
*/
public LargeObjectManager getLargeObjectAPI() throws SQLException
{
if(largeobject==null)
largeobject = new LargeObjectManager(this);
return largeobject;
}
// This holds a reference to the LargeObject API if already open
private LargeObjectManager largeobject = null;
/**
* This method is used internally to return an object based around
* postgresql's more unique data types.
*
* <p>It uses an internal Hashtable to get the handling class. If the
* type is not supported, then an instance of postgresql.util.PGobject
* is returned.
*
* You can use the getValue() or setValue() methods to handle the returned
* object. Custom objects can have their own methods.
*
* @return PGobject for this type, and set to value
* @exception SQLException if value is not correct for this type
*/
protected PGobject getObject(String type,String value) throws SQLException
{
PGobject obj = null;
try {
String name = (String)objectTypes.get(type);
obj = (PGobject)(Class.forName(name==null?"postgresql.util.PGobject":name).newInstance());
} catch(Exception ex) {
throw new SQLException("Failed to create object for "+type+": "+ex);
}
if(obj!=null) {
obj.setType(type);
obj.setValue(value);
}
return obj;
}
/**
* This allows client code to add a handler for one of postgresql's
* more unique data types.
*
* <p><b>NOTE:</b> This is not part of JDBC, but an extension.
*
* <p>The best way to use this is as follows:
*
* <p><pre>
* ...
* ((postgresql.Connection)myconn).addDataType("mytype","my.class.name");
* ...
* </pre>
*
* <p>where myconn is an open Connection to postgresql.
*
* <p>The handling class must extend postgresql.util.PGobject
*
* @see postgresql.util.PGobject
*/
public void addDataType(String type,String name)
{
objectTypes.put(type,name);
}
// This holds the available types
private Hashtable objectTypes = new Hashtable();
// This array contains the types that are supported as standard.
//
// The first entry is the types name on the database, the second
// the full class name of the handling class.
//
private static final String defaultObjectTypes[][] = {
{"box", "postgresql.geometric.PGbox"},
{"circle", "postgresql.geometric.PGcircle"},
{"lseg", "postgresql.geometric.PGlseg"},
{"path", "postgresql.geometric.PGpath"},
{"point", "postgresql.geometric.PGpoint"},
{"polygon", "postgresql.geometric.PGpolygon"}
};
// This initialises the objectTypes hashtable
private void initObjectTypes()
{
for(int i=0;i<defaultObjectTypes.length;i++)
objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]);
}
}

View File

@ -4,17 +4,14 @@ import java.sql.*;
import java.util.*;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* This class provides information about the database as a whole.
*
* Many of the methods here return lists of information in ResultSets. You
* <p>Many of the methods here return lists of information in ResultSets. You
* can use the normal ResultSet methods such as getString and getInt to
* retrieve the data from these ResultSets. If a given form of metadata is
* not available, these methods should throw a SQLException.
*
* Some of these methods take arguments that are String patterns. These
* <p>Some of these methods take arguments that are String patterns. These
* arguments all have names such as fooPattern. Within a pattern String,
* "%" means match any substring of 0 or more characters, and "_" means
* match any one character. Only metadata entries matching the search
@ -22,7 +19,7 @@ import java.util.*;
* ref, it means that argument's criteria should be dropped from the
* search.
*
* A SQLException will be throws if a driver does not support a meta
* <p>A SQLException will be throws if a driver does not support a meta
* data method. In the case of methods that return a ResultSet, either
* a ResultSet (which may be empty) is returned or a SQLException is
* thrown.
@ -33,6 +30,12 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
{
Connection connection; // The connection association
// These define various OID's. Hopefully they will stay constant.
static final int iVarcharOid = 1043; // OID for varchar
static final int iBoolOid = 16; // OID for bool
static final int iInt2Oid = 21; // OID for int2
static final int iInt4Oid = 23; // OID for int4
public DatabaseMetaData(Connection conn)
{
this.connection = conn;
@ -152,19 +155,21 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
}
/**
* What is the version of this database product. Note that
* PostgreSQL 6.1 has a system catalog called pg_version -
* What is the version of this database product.
*
* <p>Note that PostgreSQL 6.3 has a system catalog called pg_version -
* however, select * from pg_version on any database retrieves
* no rows. For now, we will return the version 6.1 (in the
* hopes that we change this driver as often as we change the
* database)
* no rows.
*
* <p>For now, we will return the version 6.3 (in the hope that we change
* this driver as often as we change the database)
*
* @return the database version
* @exception SQLException if a database access error occurs
*/
public String getDatabaseProductVersion() throws SQLException
{
return ("6.2");
return ("6.3");
}
/**
@ -240,7 +245,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* as case sensitive and as a result store them in mixed case?
* A JDBC-Compliant driver will always return false.
*
* Predicament - what do they mean by "SQL identifiers" - if it
* <p>Predicament - what do they mean by "SQL identifiers" - if it
* means the names of the tables and columns, then the answers
* given below are correct - otherwise I don't know.
*
@ -290,7 +295,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* case sensitive and as a result store them in mixed case? A
* JDBC compliant driver will always return true.
*
* Predicament - what do they mean by "SQL identifiers" - if it
* <p>Predicament - what do they mean by "SQL identifiers" - if it
* means the names of the tables and columns, then the answers
* given below are correct - otherwise I don't know.
*
@ -340,7 +345,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* a space if identifier quoting isn't supported. A JDBC Compliant
* driver will always use a double quote character.
*
* If an SQL identifier is a table name, column name, etc. then
* <p>If an SQL identifier is a table name, column name, etc. then
* we do not support it.
*
* @return the quoting string
@ -355,10 +360,12 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* Get a comma separated list of all a database's SQL keywords that
* are NOT also SQL92 keywords.
*
* Within PostgreSQL, the keywords are found in
* <p>Within PostgreSQL, the keywords are found in
* src/backend/parser/keywords.c
* For SQL Keywords, I took the list provided at
* http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt
*
* <p>For SQL Keywords, I took the list provided at
* <a href="http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt">
* http://web.dementia.org/~shadow/sql/sql3bnf.sep93.txt</a>
* which is for SQL3, not SQL-92, but it is close enough for
* this purpose.
*
@ -410,7 +417,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* Get all the "extra" characters that can bew used in unquoted
* identifier names (those beyond a-zA-Z0-9 and _)
*
* From the file src/backend/parser/scan.l, an identifier is
* <p>From the file src/backend/parser/scan.l, an identifier is
* {letter}{letter_or_digit} which makes it just those listed
* above.
*
@ -449,14 +456,16 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
/**
* Is column aliasing supported?
*
* If so, the SQL AS clause can be used to provide names for
* <p>If so, the SQL AS clause can be used to provide names for
* computed columns or to provide alias names for columns as
* required. A JDBC Compliant driver always returns true.
*
* e.g.
* <p>e.g.
*
* <br><pre>
* select count(C) as C_COUNT from T group by C;
*
* </pre><br>
* should return a column named as C_COUNT instead of count(C)
*
* @return true if so
@ -506,7 +515,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
/**
* Are expressions in "ORCER BY" lists supported?
*
* e.g. select * from t order by a + b;
* <br>e.g. select * from t order by a + b;
*
* @return true if so
* @exception SQLException if a database access error occurs
@ -607,7 +616,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* Can columns be defined as non-nullable. A JDBC Compliant driver
* always returns true.
*
* This changed from false to true in v6.2 of the driver, as this
* <p>This changed from false to true in v6.2 of the driver, as this
* support was added to the backend.
*
* @return true if so
@ -622,9 +631,9 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* Does this driver support the minimum ODBC SQL grammar. This
* grammar is defined at:
*
* http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm
* <p><a href="http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm">http://www.microsoft.com/msdn/sdk/platforms/doc/odbc/src/intropr.htm</a>
*
* In Appendix C. From this description, we seem to support the
* <p>In Appendix C. From this description, we seem to support the
* ODBC minimal (Level 0) grammar.
*
* @return true if so
@ -1142,7 +1151,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* What is the maximum number of columns in a table? From the
* create_table(l) manual page...
*
* "The new class is created as a heap with no initial data. A
* <p>"The new class is created as a heap with no initial data. A
* class can have no more than 1600 attributes (realistically,
* this is limited by the fact that tuple sizes must be less than
* 8192 bytes)..."
@ -1393,6 +1402,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* Does a data definition statement within a transaction force
* the transaction to commit? I think this means something like:
*
* <p><pre>
* CREATE TABLE T (A INT);
* INSERT INTO T (A) VALUES (2);
* BEGIN;
@ -1400,6 +1410,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* CREATE TABLE X (A INT);
* SELECT A FROM T INTO X;
* COMMIT;
* </pre><p>
*
* does the CREATE TABLE call cause a commit? The answer is no.
*
@ -1412,7 +1423,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
}
/**
* Is a data definition statement within a transaction ignored?
* Is a data definition statement within a transaction ignored?
* It seems to be (from experiment in previous method)
*
* @return true if so
@ -1426,22 +1437,26 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
/**
* Get a description of stored procedures available in a catalog
*
* Only procedure descriptions matching the schema and procedure
* <p>Only procedure descriptions matching the schema and procedure
* name criteria are returned. They are ordered by PROCEDURE_SCHEM
* and PROCEDURE_NAME
*
* Each procedure description has the following columns:
* PROCEDURE_CAT String => procedure catalog (may be null)
* PROCEDURE_SCHEM String => procedure schema (may be null)
* PROCEDURE_NAME String => procedure name
* Field 4 reserved (make it null)
* Field 5 reserved (make it null)
* Field 6 reserved (make it null)
* REMARKS String => explanatory comment on the procedure
* PROCEDURE_TYPE short => kind of procedure
* * procedureResultUnknown - May return a result
* * procedureNoResult - Does not return a result
* * procedureReturnsResult - Returns a result
* <p>Each procedure description has the following columns:
* <ol>
* <li><b>PROCEDURE_CAT</b> String => procedure catalog (may be null)
* <li><b>PROCEDURE_SCHEM</b> String => procedure schema (may be null)
* <li><b>PROCEDURE_NAME</b> String => procedure name
* <li><b>Field 4</b> reserved (make it null)
* <li><b>Field 5</b> reserved (make it null)
* <li><b>Field 6</b> reserved (make it null)
* <li><b>REMARKS</b> String => explanatory comment on the procedure
* <li><b>PROCEDURE_TYPE</b> short => kind of procedure
* <ul>
* <li> procedureResultUnknown - May return a result
* <li> procedureNoResult - Does not return a result
* <li> procedureReturnsResult - Returns a result
* </ul>
* </ol>
*
* @param catalog - a catalog name; "" retrieves those without a
* catalog; null means drop catalog name from criteria
@ -1451,8 +1466,6 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* @return ResultSet - each row is a procedure description
* @exception SQLException if a database access error occurs
*/
static final int iVarcharOid = 1043; // This is the OID for a varchar()
static final int iInt2Oid = 21; // This is the OID for an int2
public java.sql.ResultSet getProcedures(String catalog, String schemaPattern, String procedureNamePattern) throws SQLException
{
// the field descriptors for the new ResultSet
@ -1497,17 +1510,183 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
return new ResultSet(connection, f, v, "OK", 1);
}
/**
* Get a description of a catalog's stored procedure parameters
* and result columns.
*
* <p>Only descriptions matching the schema, procedure and parameter
* name criteria are returned. They are ordered by PROCEDURE_SCHEM
* and PROCEDURE_NAME. Within this, the return value, if any, is
* first. Next are the parameter descriptions in call order. The
* column descriptions follow in column number order.
*
* <p>Each row in the ResultSet is a parameter description or column
* description with the following fields:
* <ol>
* <li><b>PROCEDURE_CAT</b> String => procedure catalog (may be null)
* <li><b>PROCEDURE_SCHE</b>M String => procedure schema (may be null)
* <li><b>PROCEDURE_NAME</b> String => procedure name
* <li><b>COLUMN_NAME</b> String => column/parameter name
* <li><b>COLUMN_TYPE</b> Short => kind of column/parameter:
* <ul><li>procedureColumnUnknown - nobody knows
* <li>procedureColumnIn - IN parameter
* <li>procedureColumnInOut - INOUT parameter
* <li>procedureColumnOut - OUT parameter
* <li>procedureColumnReturn - procedure return value
* <li>procedureColumnResult - result column in ResultSet
* </ul>
* <li><b>DATA_TYPE</b> short => SQL type from java.sql.Types
* <li><b>TYPE_NAME</b> String => SQL type name
* <li><b>PRECISION</b> int => precision
* <li><b>LENGTH</b> int => length in bytes of data
* <li><b>SCALE</b> short => scale
* <li><b>RADIX</b> short => radix
* <li><b>NULLABLE</b> short => can it contain NULL?
* <ul><li>procedureNoNulls - does not allow NULL values
* <li>procedureNullable - allows NULL values
* <li>procedureNullableUnknown - nullability unknown
* <li><b>REMARKS</b> String => comment describing parameter/column
* </ol>
* @param catalog This is ignored in postgresql, advise this is set to null
* @param schemaPattern This is ignored in postgresql, advise this is set to null
* @param procedureNamePattern a procedure name pattern
* @param columnNamePattern a column name pattern
* @return each row is a stored procedure parameter or column description
* @exception SQLException if a database-access error occurs
* @see #getSearchStringEscape
*/
// Implementation note: This is required for Borland's JBuilder to work
public java.sql.ResultSet getProcedureColumns(String catalog, String schemaPattern, String procedureNamePattern, String columnNamePattern) throws SQLException
{
// XXX-Not Implemented
return null;
// for now, this returns an empty result set.
Field f[] = new Field[13];
ResultSet r; // ResultSet for the SQL query that we need to do
Vector v = new Vector(); // The new ResultSet tuple stuff
f[0] = new Field(connection, new String("PROCEDURE_CAT"), iVarcharOid, 32);
f[1] = new Field(connection, new String("PROCEDURE_SCHEM"), iVarcharOid, 32);
f[2] = new Field(connection, new String("PROCEDURE_NAME"), iVarcharOid, 32);
f[3] = new Field(connection, new String("COLUMN_NAME"), iVarcharOid, 32);
f[4] = new Field(connection, new String("COLUMN_TYPE"), iInt2Oid, 2);
f[5] = new Field(connection, new String("DATA_TYPE"), iInt2Oid, 2);
f[6] = new Field(connection, new String("TYPE_NAME"), iVarcharOid, 32);
f[7] = new Field(connection, new String("PRECISION"), iInt4Oid, 4);
f[8] = new Field(connection, new String("LENGTH"), iInt4Oid, 4);
f[9] = new Field(connection, new String("SCALE"), iInt2Oid, 2);
f[10] = new Field(connection, new String("RADIX"), iInt2Oid, 2);
f[11] = new Field(connection, new String("NULLABLE"), iInt2Oid, 2);
f[12] = new Field(connection, new String("REMARKS"), iVarcharOid, 32);
return new ResultSet(connection, f, v, "OK", 1);
}
/**
* Get a description of tables available in a catalog.
*
* <p>Only table descriptions matching the catalog, schema, table
* name and type criteria are returned. They are ordered by
* TABLE_TYPE, TABLE_SCHEM and TABLE_NAME.
*
* <p>Each table description has the following columns:
*
* <ol>
* <li><b>TABLE_CAT</b> String => table catalog (may be null)
* <li><b>TABLE_SCHEM</b> String => table schema (may be null)
* <li><b>TABLE_NAME</b> String => table name
* <li><b>TABLE_TYPE</b> String => table type. Typical types are "TABLE",
* "VIEW", "SYSTEM TABLE", "GLOBAL TEMPORARY", "LOCAL
* TEMPORARY", "ALIAS", "SYNONYM".
* <li><b>REMARKS</b> String => explanatory comment on the table
* </ol>
*
* <p>The valid values for the types parameter are:
* "TABLE", "INDEX", "LARGE OBJECT", "SEQUENCE", "SYSTEM TABLE" and
* "SYSTEM INDEX"
*
* @param catalog a catalog name; For postgresql, this is ignored, and
* should be set to null
* @param schemaPattern a schema name pattern; For postgresql, this is ignored, and
* should be set to null
* @param tableNamePattern a table name pattern. For all tables this should be "%"
* @param types a list of table types to include; null returns
* all types
* @return each row is a table description
* @exception SQLException if a database-access error occurs.
*/
public java.sql.ResultSet getTables(String catalog, String schemaPattern, String tableNamePattern, String types[]) throws SQLException
{
return connection.createStatement().executeQuery("SELECT '' as TABLE_CAT,'' AS TABLE_SCHEM,relname AS TABLE_NAME,'TABLE' AS TABLE_TYPE,'' AS REMARKS FROM pg_class WHERE relkind = 'r' and relname !~ '^pg_' and relname !~ '^Inv' and relname ~ '"+tableNamePattern+"' ORDER BY TABLE_NAME");
// the field descriptors for the new ResultSet
Field f[] = new Field[5];
ResultSet r; // ResultSet for the SQL query that we need to do
Vector v = new Vector(); // The new ResultSet tuple stuff
f[0] = new Field(connection, new String("TABLE_CAT"), iVarcharOid, 32);
f[1] = new Field(connection, new String("TABLE_SCHEM"), iVarcharOid, 32);
f[2] = new Field(connection, new String("TABLE_NAME"), iVarcharOid, 32);
f[3] = new Field(connection, new String("TABLE_TYPE"), iVarcharOid, 32);
f[4] = new Field(connection, new String("REMARKS"), iVarcharOid, 32);
// Now form the query
StringBuffer sql = new StringBuffer("select relname,oid from pg_class where ");
boolean notFirst=false;
for(int i=0;i<types.length;i++) {
if(notFirst)
sql.append(" or ");
for(int j=0;j<getTableTypes.length;j++)
if(getTableTypes[j][0].equals(types[i])) {
sql.append(getTableTypes[j][1]);
notFirst=true;
}
}
// Now run the query
r = connection.ExecSQL(sql.toString());
if (r.getColumnCount() != 2)
throw new SQLException("Unexpected return from query for table list");
while (r.next())
{
byte[][] tuple = new byte[5][0];
String name = r.getString(1);
String remarks = new String("no remarks");
// Fetch the description for the table (if any)
ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(2));
if(dr.getTupleCount()==1) {
dr.next();
remarks=dr.getString(1);
}
dr.close();
tuple[0] = null; // Catalog name
tuple[1] = null; // Schema name
tuple[2] = name.getBytes(); // Table name
tuple[3] = null; // Table type
tuple[4] = remarks.getBytes(); // Remarks
v.addElement(tuple);
}
r.close();
return new ResultSet(connection, f, v, "OK", 1);
}
// This array contains the valid values for the types argument
// in getTables().
//
// Each supported type consists of it's name, and the sql where
// clause to retrieve that value.
//
// IMPORTANT: the query must be enclosed in ( )
private static final String getTableTypes[][] = {
{"TABLE", "(relkind='r' and relname !~ '^pg_' and relname !~ '^xinv')"},
{"INDEX", "(relkind='i' and relname !~ '^pg_' and relname !~ '^xinx')"},
{"LARGE OBJECT", "(relkind='r' and relname ~ '^xinv')"},
{"SEQUENCE", "(relkind='S' and relname !~ '^pg_')"},
{"SYSTEM TABLE", "(relkind='r' and relname ~ '^pg_')"},
{"SYSTEM INDEX", "(relkind='i' and relname ~ '^pg_')"}
};
/**
* Get the schema names available in this database. The results
* are ordered by schema name.
@ -1522,8 +1701,15 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
*/
public java.sql.ResultSet getSchemas() throws SQLException
{
// XXX-Not Implemented
return null;
// We don't use schemas, so we simply return a single schema name "".
//
Field f[] = new Field[1];
Vector v = new Vector();
byte[][] tuple = new byte[1][0];
f[0] = new Field(connection,new String("TABLE_SCHEM"),iVarcharOid,32);
tuple[0] = "".getBytes();
v.addElement(tuple);
return new ResultSet(connection,f,v,"OK",1);
}
/**
@ -1538,10 +1724,16 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* @return ResultSet each row has a single String column that is a
* catalog name
*/
// We don't use catalog names, so this returns a single catalog
public java.sql.ResultSet getCatalogs() throws SQLException
{
return connection.createStatement().executeQuery("SELECT '' as TABLE_CAT");
// We don't use catalogs, so we simply return a single catalog name "".
Field f[] = new Field[1];
Vector v = new Vector();
byte[][] tuple = new byte[1][0];
f[0] = new Field(connection,new String("TABLE_CAT"),iVarcharOid,32);
tuple[0] = "".getBytes();
v.addElement(tuple);
return new ResultSet(connection,f,v,"OK",1);
}
/**
@ -1560,8 +1752,15 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
*/
public java.sql.ResultSet getTableTypes() throws SQLException
{
// XXX-Not Implemented
return null;
Field f[] = new Field[1];
Vector v = new Vector();
byte[][] tuple = new byte[1][0];
f[0] = new Field(connection,new String("TABLE_TYPE"),iVarcharOid,32);
for(int i=0;i<getTableTypes.length;i++) {
tuple[0] = getTableTypes[i][0].getBytes();
v.addElement(tuple);
}
return new ResultSet(connection,f,v,"OK",1);
}
/**
@ -1614,10 +1813,87 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
*/
public java.sql.ResultSet getColumns(String catalog, String schemaPattern, String tableNamePattern, String columnNamePattern) throws SQLException
{
// XXX-Not Implemented
// PM: this will be implemented, as soon as I sort out how to convert the
// code from the other driver (private note: look at getProcedures() )
return null;
// the field descriptors for the new ResultSet
Field f[] = new Field[18];
ResultSet r; // ResultSet for the SQL query that we need to do
Vector v = new Vector(); // The new ResultSet tuple stuff
f[0] = new Field(connection, new String("TABLE_CAT"), iVarcharOid, 32);
f[1] = new Field(connection, new String("TABLE_SCHEM"), iVarcharOid, 32);
f[2] = new Field(connection, new String("TABLE_NAME"), iVarcharOid, 32);
f[3] = new Field(connection, new String("COLUMN_NAME"), iVarcharOid, 32);
f[4] = new Field(connection, new String("DATA_TYPE"), iInt2Oid, 2);
f[5] = new Field(connection, new String("TYPE_NAME"), iVarcharOid, 32);
f[6] = new Field(connection, new String("COLUMN_SIZE"), iInt4Oid, 4);
f[7] = new Field(connection, new String("BUFFER_LENGTH"), iVarcharOid, 32);
f[8] = new Field(connection, new String("DECIMAL_DIGITS"), iInt4Oid, 4);
f[9] = new Field(connection, new String("NUM_PREC_RADIX"), iInt4Oid, 4);
f[10] = new Field(connection, new String("NULLABLE"), iInt4Oid, 4);
f[11] = new Field(connection, new String("REMARKS"), iVarcharOid, 32);
f[12] = new Field(connection, new String("COLUMN_DEF"), iVarcharOid, 32);
f[13] = new Field(connection, new String("SQL_DATA_TYPE"), iInt4Oid, 4);
f[14] = new Field(connection, new String("SQL_DATETIME_SUB"), iInt4Oid, 4);
f[15] = new Field(connection, new String("CHAR_OCTET_LENGTH"), iVarcharOid, 32);
f[16] = new Field(connection, new String("ORDINAL_POSITION"), iInt4Oid,4);
f[17] = new Field(connection, new String("IS_NULLABLE"), iVarcharOid, 32);
// Now form the query
r = connection.ExecSQL("select a.oid,c.relname,a.attname,a.atttypid,a.attnum,a.attnotnull,a.attlen from pg_class c, pg_attribute a where a.attrelid=c.oid and c.relname like '"+tableNamePattern+"' and a.attname like '"+columnNamePattern+"' and a.attnum>0 order by c.relname,a.attnum");
while(r.next()) {
byte[][] tuple = new byte[18][0];
String name = r.getString(1);
String remarks = new String("no remarks");
// Fetch the description for the table (if any)
ResultSet dr = connection.ExecSQL("select description from pg_description where objoid="+r.getInt(1));
if(dr.getTupleCount()==1) {
dr.next();
remarks=dr.getString(1);
}
dr.close();
tuple[0] = "".getBytes(); // Catalog name
tuple[1] = "".getBytes(); // Schema name
tuple[2] = r.getString(2).getBytes(); // Table name
tuple[3] = r.getString(3).getBytes(); // Column name
dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4));
dr.next();
String typname=dr.getString(1);
dr.close();
tuple[4] = Integer.toString(Field.getSQLType(typname)).getBytes(); // Data type
tuple[5] = typname.getBytes(); // Type name
tuple[6] = r.getString(7).getBytes(); // Column size
tuple[7] = null; // Buffer length
tuple[8] = "0".getBytes(); // Decimal Digits - how to get this?
tuple[9] = "10".getBytes(); // Num Prec Radix - assume decimal
// tuple[10] is below
tuple[11] = remarks.getBytes(); // Remarks
tuple[12] = null; // column default
tuple[13] = null; // sql data type (unused)
tuple[14] = null; // sql datetime sub (unused)
tuple[15] = tuple[6]; // char octet length
tuple[16] = r.getString(5).getBytes(); // ordinal position
String nullFlag = r.getString(6);
tuple[10] = Integer.toString(nullFlag.equals("f")?java.sql.DatabaseMetaData.columnNullable:java.sql.DatabaseMetaData.columnNoNulls).getBytes(); // Nullable
tuple[17] = (nullFlag.equals("f")?"YES":"NO").getBytes(); // is nullable
v.addElement(tuple);
}
r.close();
return new ResultSet(connection, f, v, "OK", 1);
}
/**
@ -1649,8 +1925,30 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
*/
public java.sql.ResultSet getColumnPrivileges(String catalog, String schema, String table, String columnNamePattern) throws SQLException
{
// XXX-Not Implemented
// XXX-Not Implemented as grant is broken
return null;
//Field f[] = new Field[8];
//Vector v = new Vector();
//
//f[0] = new Field(connection,new String("TABLE_CAT"),iVarcharOid,32);
//f[1] = new Field(connection,new String("TABLE_SCHEM"),iVarcharOid,32);
//f[2] = new Field(connection,new String("TABLE_NAME"),iVarcharOid,32);
//f[3] = new Field(connection,new String("COLUMN_NAME"),iVarcharOid,32);
//f[4] = new Field(connection,new String("GRANTOR"),iVarcharOid,32);
//f[5] = new Field(connection,new String("GRANTEE"),iVarcharOid,32);
//f[6] = new Field(connection,new String("PRIVILEGE"),iVarcharOid,32);
//f[7] = new Field(connection,new String("IS_GRANTABLE"),iVarcharOid,32);
//
//// This is taken direct from the psql source
//ResultSet r = connection.ExecSQL("SELECT relname, relacl FROM pg_class, pg_user WHERE ( relkind = 'r' OR relkind = 'i') and relname !~ '^pg_' and relname !~ '^xin[vx][0-9]+' and usesysid = relowner ORDER BY relname");
//while(r.next()) {
//byte[][] tuple = new byte[8][0];
//tuple[0] = tuple[1]= "default".getBytes();
//
//v.addElement(tuple);
//}
//
//return new ResultSet(connection,f,v,"OK",1);
}
/**
@ -1722,10 +2020,24 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* @param nullable include columns that are nullable?
* @return ResultSet each row is a column description
*/
// Implementation note: This is required for Borland's JBuilder to work
public java.sql.ResultSet getBestRowIdentifier(String catalog, String schema, String table, int scope, boolean nullable) throws SQLException
{
// XXX-Not Implemented
return null;
// for now, this returns an empty result set.
Field f[] = new Field[8];
ResultSet r; // ResultSet for the SQL query that we need to do
Vector v = new Vector(); // The new ResultSet tuple stuff
f[0] = new Field(connection, new String("SCOPE"), iInt2Oid, 2);
f[1] = new Field(connection, new String("COLUMN_NAME"), iVarcharOid, 32);
f[2] = new Field(connection, new String("DATA_TYPE"), iInt2Oid, 2);
f[3] = new Field(connection, new String("TYPE_NAME"), iVarcharOid, 32);
f[4] = new Field(connection, new String("COLUMN_SIZE"), iInt4Oid, 4);
f[5] = new Field(connection, new String("BUFFER_LENGTH"), iInt4Oid, 4);
f[6] = new Field(connection, new String("DECIMAL_DIGITS"), iInt2Oid, 2);
f[7] = new Field(connection, new String("PSEUDO_COLUMN"), iInt2Oid, 2);
return new ResultSet(connection, f, v, "OK", 1);
}
/**
@ -2078,9 +2390,29 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData
* accurate
* @return ResultSet each row is an index column description
*/
// Implementation note: This is required for Borland's JBuilder to work
public java.sql.ResultSet getIndexInfo(String catalog, String schema, String table, boolean unique, boolean approximate) throws SQLException
{
// XXX-Not Implemented
return null;
// for now, this returns an empty result set.
Field f[] = new Field[13];
ResultSet r; // ResultSet for the SQL query that we need to do
Vector v = new Vector(); // The new ResultSet tuple stuff
f[0] = new Field(connection, new String("TABLE_CAT"), iVarcharOid, 32);
f[1] = new Field(connection, new String("TABLE_SCHEM"), iVarcharOid, 32);
f[2] = new Field(connection, new String("TABLE_NAME"), iVarcharOid, 32);
f[3] = new Field(connection, new String("NON_UNIQUE"), iBoolOid, 1);
f[4] = new Field(connection, new String("INDEX_QUALIFIER"), iVarcharOid, 32);
f[5] = new Field(connection, new String("INDEX_NAME"), iVarcharOid, 32);
f[6] = new Field(connection, new String("TYPE"), iInt2Oid, 2);
f[7] = new Field(connection, new String("ORDINAL_POSITION"), iInt2Oid, 2);
f[8] = new Field(connection, new String("COLUMN_NAME"), iVarcharOid, 32);
f[9] = new Field(connection, new String("ASC_OR_DESC"), iVarcharOid, 32);
f[10] = new Field(connection, new String("CARDINALITY"), iInt4Oid, 4);
f[11] = new Field(connection, new String("PAGES"), iInt4Oid, 4);
f[12] = new Field(connection, new String("FILTER_CONDITION"), iVarcharOid, 32);
return new ResultSet(connection, f, v, "OK", 1);
}
}

View File

@ -7,17 +7,17 @@ import java.util.*;
* The Java SQL framework allows for multiple database drivers. Each
* driver should supply a class that implements the Driver interface
*
* The DriverManager will try to load as many drivers as it can find and then
* for any given connection request, it will ask each driver in turn to try
* to connect to the target URL.
* <p>The DriverManager will try to load as many drivers as it can find and
* then for any given connection request, it will ask each driver in turn
* to try to connect to the target URL.
*
* It is strongly recommended that each Driver class should be small and
* <p>It is strongly recommended that each Driver class should be small and
* standalone so that the Driver class can be loaded and queried without
* bringing in vast quantities of supporting code.
*
* When a Driver class is loaded, it should create an instance of itself and
* register it with the DriverManager. This means that a user can load and
* register a driver by doing Class.forName("foo.bah.Driver")
* <p>When a Driver class is loaded, it should create an instance of itself
* and register it with the DriverManager. This means that a user can load
* and register a driver by doing Class.forName("foo.bah.Driver")
*
* @see postgresql.Connection
* @see java.sql.Driver
@ -58,18 +58,18 @@ public class Driver implements java.sql.Driver
* when the JDBC driverManager is asked to connect to a given URL,
* it passes the URL to each loaded driver in turn.
*
* The driver should raise an SQLException if it is the right driver
* <p>The driver should raise an SQLException if it is the right driver
* to connect to the given URL, but has trouble connecting to the
* database.
*
* The java.util.Properties argument can be used to pass arbitrary
* <p>The java.util.Properties argument can be used to pass arbitrary
* string tag/value pairs as connection arguments. Normally, at least
* "user" and "password" properties should be included in the
* properties.
*
* Our protocol takes the form:
* Our protocol takes the forms:
* <PRE>
* jdbc:postgresql://host:port/database
* jdbc:postgresql://host:port/database?param1=val1&...
* </PRE>
*
* @param url the URL of the database to connect to
@ -110,7 +110,8 @@ public class Driver implements java.sql.Driver
* The getPropertyInfo method is intended to allow a generic GUI
* tool to discover what properties it should prompt a human for
* in order to get enough information to connect to a database.
* Note that depending on the values the human has supplied so
*
* <p>Note that depending on the values the human has supplied so
* far, additional values may become necessary, so it may be necessary
* to iterate through several calls to getPropertyInfo
*
@ -169,6 +170,9 @@ public class Driver implements java.sql.Driver
* tests, otherwise it is required to return false. JDBC compliance
* requires full support for the JDBC API and full support for SQL 92
* Entry Level.
*
* <p>For PostgreSQL, this is not yet possible, as we are not SQL92
* compliant (yet).
*/
public boolean jdbcCompliant()
{
@ -185,7 +189,7 @@ public class Driver implements java.sql.Driver
* @param url JDBC URL to parse
* @param defaults Default properties
* @return Properties with elements added from the url
* @throws SQLException
* @exception SQLException
*/
Properties parseURL(String url,Properties defaults) throws SQLException
{
@ -280,7 +284,7 @@ public class Driver implements java.sql.Driver
}
/**
* Returns the hostname portion of the URL
* @return the hostname portion of the URL
*/
public String host()
{
@ -288,8 +292,7 @@ public class Driver implements java.sql.Driver
}
/**
* Returns the port number portion of the URL
* or -1 if no port was specified
* @return the port number portion of the URL or -1 if no port was specified
*/
public int port()
{
@ -297,7 +300,7 @@ public class Driver implements java.sql.Driver
}
/**
* Returns the database name of the URL
* @return the database name of the URL
*/
public String database()
{
@ -305,7 +308,8 @@ public class Driver implements java.sql.Driver
}
/**
* Returns any property
* @return the value of any property specified in the URL or properties
* passed to connect(), or null if not found.
*/
public String property(String name)
{

View File

@ -6,10 +6,8 @@ import java.util.*;
import postgresql.*;
/**
* postgresql.Field is a class used to describe fields in a PostgreSQL ResultSet
*
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
* postgresql.Field is a class used to describe fields in a PostgreSQL
* ResultSet
*/
public class Field
{
@ -22,7 +20,7 @@ public class Field
String type_name = null;// The sql type name
/**
* Construct a field based on the information fed to it.
* Construct a field based on the information fed to it.
*
* @param conn the connection this field came from
* @param name the name of the field
@ -37,6 +35,14 @@ public class Field
this.length = length;
}
/**
* @return the oid of this Field's data type
*/
public int getOID()
{
return oid;
}
/**
* the ResultSet and ResultMetaData both need to handle the SQL
* type, which is gained from another query. Note that we cannot
@ -47,47 +53,77 @@ public class Field
*/
public int getSQLType() throws SQLException
{
if (sql_type == -1)
{
ResultSet result = (postgresql.ResultSet)conn.ExecSQL("select typname from pg_type where oid = " + oid);
if (result.getColumnCount() != 1 || result.getTupleCount() != 1)
throw new SQLException("Unexpected return from query for type");
result.next();
type_name = result.getString(1);
if (type_name.equals("int2"))
sql_type = Types.SMALLINT;
else if (type_name.equals("int4"))
sql_type = Types.INTEGER;
else if (type_name.equals("int8"))
sql_type = Types.BIGINT;
else if (type_name.equals("cash"))
sql_type = Types.DECIMAL;
else if (type_name.equals("money"))
sql_type = Types.DECIMAL;
else if (type_name.equals("float4"))
sql_type = Types.REAL;
else if (type_name.equals("float8"))
sql_type = Types.DOUBLE;
else if (type_name.equals("bpchar"))
sql_type = Types.CHAR;
else if (type_name.equals("varchar"))
sql_type = Types.VARCHAR;
else if (type_name.equals("bool"))
sql_type = Types.BIT;
else if (type_name.equals("date"))
sql_type = Types.DATE;
else if (type_name.equals("time"))
sql_type = Types.TIME;
else if (type_name.equals("abstime"))
sql_type = Types.TIMESTAMP;
else if (type_name.equals("timestamp"))
sql_type = Types.TIMESTAMP;
else
sql_type = Types.OTHER;
}
if(sql_type == -1) {
ResultSet result = (postgresql.ResultSet)conn.ExecSQL("select typname from pg_type where oid = " + oid);
if (result.getColumnCount() != 1 || result.getTupleCount() != 1)
throw new SQLException("Unexpected return from query for type");
result.next();
sql_type = getSQLType(result.getString(1));
result.close();
}
return sql_type;
}
/**
* This returns the SQL type. It is called by the Field and DatabaseMetaData classes
* @param type_name PostgreSQL type name
* @return java.sql.Types value for oid
*/
public static int getSQLType(String type_name)
{
int sql_type = Types.OTHER; // default value
for(int i=0;i<types.length;i++)
if(type_name.equals(types[i]))
sql_type=typei[i];
return sql_type;
}
/**
* This table holds the postgresql names for the types supported.
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
* They default automatically to Types.OTHER
*
* Note: This must be in the same order as below.
*
* Tip: keep these grouped together by the Types. value
*/
private static final String types[] = {
"int2",
"int4","oid",
"int8",
"cash","money",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
"bool",
"date",
"time",
"abstime","timestamp"
};
/**
* This table holds the JDBC type for each entry above.
*
* Note: This must be in the same order as above
*
* Tip: keep these grouped together by the Types. value
*/
private static final int typei[] = {
Types.SMALLINT,
Types.INTEGER,Types.INTEGER,
Types.BIGINT,
Types.DECIMAL,Types.DECIMAL,
Types.REAL,
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP
};
/**
* We also need to get the type name as returned by the back end.
* This is held in type_name AFTER a call to getSQLType. Since

View File

@ -70,6 +70,28 @@ public class PG_Stream
Send(buf);
}
/**
* Sends an integer to the back end in reverse order.
*
* This is required when the backend uses the routines in the
* src/backend/libpq/pqcomprim.c module.
*
* @param val the integer to be sent
* @param siz the length of the integer in bytes (size of structure)
* @exception IOException if an I/O error occurs
*/
public void SendIntegerReverse(int val, int siz) throws IOException
{
byte[] buf = new byte[siz];
int p=0;
while (siz-- > 0)
{
buf[p++] = (byte)(val & 0xff);
val >>= 8;
}
Send(buf);
}
/**
* Send an array of bytes to the backend
*
@ -295,6 +317,20 @@ public class PG_Stream
}
}
/**
* This flushes any pending output to the backend. It is used primarily
* by the Fastpath code.
* @exception SQLException if an I/O error occurs
*/
public void flush() throws SQLException
{
try {
pg_output.flush();
} catch (IOException e) {
throw new SQLException("Error flushing output: " + e.toString());
}
}
/**
* Closes the connection
*

View File

@ -5,21 +5,20 @@ import java.math.*;
import java.sql.*;
import java.text.*;
import java.util.*;
import postgresql.largeobject.*;
import postgresql.util.*;
/**
* @version 6.3 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A><A HREF="mailto:petermount@earthling.net">Peter Mount</A>
*
* A SQL Statement is pre-compiled and stored in a PreparedStatement object.
* This object can then be used to efficiently execute this statement multiple
* times.
*
* <B>Note:</B> The setXXX methods for setting IN parameter values must
* <p><B>Note:</B> The setXXX methods for setting IN parameter values must
* specify types that are compatible with the defined SQL type of the input
* parameter. For instance, if the IN parameter has SQL type Integer, then
* setInt should be used.
*
* If arbitrary parameter type conversions are required, then the setObject
* <p>If arbitrary parameter type conversions are required, then the setObject
* method should be used with a target SQL type.
*
* @see ResultSet
@ -33,10 +32,10 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
Connection connection;
/**
* Constructor for the PreparedStatement class. Split the SQL statement
* into segments - separated by the arguments. When we rebuild the
* thing with the arguments, we can substitute the args and join the
* whole thing together.
* Constructor for the PreparedStatement class.
* Split the SQL statement into segments - separated by the arguments.
* When we rebuild the thing with the arguments, we can substitute the
* args and join the whole thing together.
*
* @param conn the instanatiating connection
* @param sql the SQL statement with ? for IN markers
@ -125,7 +124,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
/**
* Set a parameter to SQL NULL
*
* <B>Note:</B> You must specify the parameters SQL type (although
* <p><B>Note:</B> You must specify the parameters SQL type (although
* PostgreSQL ignores it)
*
* @param parameterIndex the first parameter is 1, etc...
@ -254,35 +253,49 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setString(int parameterIndex, String x) throws SQLException
{
StringBuffer b = new StringBuffer();
int i;
b.append('\'');
for (i = 0 ; i < x.length() ; ++i)
{
char c = x.charAt(i);
if (c == '\\' || c == '\'')
b.append((char)'\\');
b.append(c);
}
b.append('\'');
set(parameterIndex, b.toString());
// if the passed string is null, then set this column to null
if(x==null)
set(parameterIndex,"null");
else {
StringBuffer b = new StringBuffer();
int i;
b.append('\'');
for (i = 0 ; i < x.length() ; ++i)
{
char c = x.charAt(i);
if (c == '\\' || c == '\'')
b.append((char)'\\');
b.append(c);
}
b.append('\'');
set(parameterIndex, b.toString());
}
}
/**
* Set a parameter to a Java array of bytes. The driver converts this
* to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
* size relative to the driver's limits on VARBINARYs) when it sends
* it to the database.
*
* @param parameterIndex the first parameter is 1...
* @param x the parameter value
* @exception SQLException if a database access error occurs
*/
public void setBytes(int parameterIndex, byte x[]) throws SQLException
{
throw new SQLException("Binary Data not supported");
}
/**
* Set a parameter to a Java array of bytes. The driver converts this
* to a SQL VARBINARY or LONGVARBINARY (depending on the argument's
* size relative to the driver's limits on VARBINARYs) when it sends
* it to the database.
*
* <p>Implementation note:
* <br>With postgresql, this creates a large object, and stores the
* objects oid in this column.
*
* @param parameterIndex the first parameter is 1...
* @param x the parameter value
* @exception SQLException if a database access error occurs
*/
public void setBytes(int parameterIndex, byte x[]) throws SQLException
{
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
lob.write(x);
lob.close();
setInt(parameterIndex,oid);
}
/**
* Set a parameter to a java.sql.Date value. The driver converts this
@ -294,16 +307,30 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setDate(int parameterIndex, java.sql.Date x) throws SQLException
{
SimpleDateFormat df = new SimpleDateFormat(connection.europeanDates?"''dd-MM-yyyy''":"''MM-dd-yyyy''");
set(parameterIndex, df.format(x));
SimpleDateFormat df = new SimpleDateFormat("''"+connection.getDateStyle()+"''");
// Ideally the following should work:
//
// set(parameterIndex, df.format(x));
//
// however, SimpleDateFormat seems to format a date to the previous
// day. So a fix (for now) is to add a day before formatting.
// This needs more people to confirm this is really happening, or
// possibly for us to implement our own formatting code.
//
// I've tested this with the Linux jdk1.1.3 and the Win95 JRE1.1.5
//
set(parameterIndex, df.format(new java.util.Date(x.getTime()+DAY)));
}
// This equates to 1 day
private static final int DAY = 86400000;
/**
* Set a parameter to a java.sql.Time value. The driver converts
* this to a SQL TIME value when it sends it to the database.
*
* @param parameterIndex the first parameter is 1...
* @param parameterIndex the first parameter is 1...));
* @param x the parameter value
* @exception SQLException if a database access error occurs
*/
@ -332,7 +359,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* end-of-file. The JDBC driver will do any necessary conversion from
* ASCII to the database char format.
*
* <B>Note:</B> This stream object can either be a standard Java
* <P><B>Note:</B> This stream object can either be a standard Java
* stream object or your own subclass that implements the standard
* interface.
*
@ -353,7 +380,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* end-of-file. The JDBC driver will do any necessary conversion from
* UNICODE to the database char format.
*
* <B>Note:</B> This stream object can either be a standard Java
* <P><B>Note:</B> This stream object can either be a standard Java
* stream object or your own subclass that implements the standard
* interface.
*
@ -372,7 +399,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* JDBC will read the data from the stream as needed, until it reaches
* end-of-file.
*
* <B>Note:</B> This stream object can either be a standard Java
* <P><B>Note:</B> This stream object can either be a standard Java
* stream object or your own subclass that implements the standard
* interface.
*
@ -406,10 +433,10 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* Set the value of a parameter using an object; use the java.lang
* equivalent objects for integral values.
*
* The given Java object will be converted to the targetSqlType before
* <P>The given Java object will be converted to the targetSqlType before
* being sent to the database.
*
* note that this method may be used to pass database-specific
* <P>note that this method may be used to pass database-specific
* abstract data types. This is done by using a Driver-specific
* Java type and using a targetSqlType of java.sql.Types.OTHER
*
@ -450,7 +477,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
case Types.TIMESTAMP:
setTimestamp(parameterIndex, (Timestamp)x);
case Types.OTHER:
setString(parameterIndex, ((PG_Object)x).value);
setString(parameterIndex, ((PGobject)x).getValue());
default:
throw new SQLException("Unknown Types value");
}
@ -485,8 +512,8 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
setTimestamp(parameterIndex, (Timestamp)x);
else if (x instanceof Boolean)
setBoolean(parameterIndex, ((Boolean)x).booleanValue());
else if (x instanceof PG_Object)
setString(parameterIndex, ((PG_Object)x).value);
else if (x instanceof PGobject)
setString(parameterIndex, ((PGobject)x).getValue());
else
throw new SQLException("Unknown object type");
}

View File

@ -6,31 +6,32 @@ import java.math.*;
import java.text.*;
import java.util.*;
import java.sql.*;
import postgresql.*;
import postgresql.largeobject.*;
import postgresql.util.*;
/**
* A ResultSet provides access to a table of data generated by executing a
* Statement. The table rows are retrieved in sequence. Within a row its
* column values can be accessed in any order.
*
* A ResultSet maintains a cursor pointing to its current row of data.
* <P>A ResultSet maintains a cursor pointing to its current row of data.
* Initially the cursor is positioned before the first row. The 'next'
* method moves the cursor to the next row.
*
* The getXXX methods retrieve column values for the current row. You can
* <P>The getXXX methods retrieve column values for the current row. You can
* retrieve values either using the index number of the column, or by using
* the name of the column. In general using the column index will be more
* efficient. Columns are numbered from 1.
*
* For maximum portability, ResultSet columns within each row should be read
* <P>For maximum portability, ResultSet columns within each row should be read
* in left-to-right order and each column should be read only once.
*
* For the getXXX methods, the JDBC driver attempts to convert the underlying
* data to the specified Java type and returns a suitable Java value. See the
* JDBC specification for allowable mappings from SQL types to Java types with
* the ResultSet getXXX methods.
*<P> For the getXXX methods, the JDBC driver attempts to convert the
* underlying data to the specified Java type and returns a suitable Java
* value. See the JDBC specification for allowable mappings from SQL types
* to Java types with the ResultSet getXXX methods.
*
* Column names used as input to getXXX methods are case insenstive. When
* <P>Column names used as input to getXXX methods are case insenstive. When
* performing a getXXX using a column name, if several columns have the same
* name, then the value of the first matching column will be returned. The
* column name option is designed to be used when column names are used in the
@ -39,11 +40,11 @@ import postgresql.*;
* the programmer to guarentee that they actually refer to the intended
* columns.
*
* A ResultSet is automatically closed by the Statement that generated it
* <P>A ResultSet is automatically closed by the Statement that generated it
* when that Statement is closed, re-executed, or is used to retrieve the
* next result from a sequence of multiple results.
*
* The number, types and properties of a ResultSet's columns are provided by
* <P>The number, types and properties of a ResultSet's columns are provided by
* the ResultSetMetaData object returned by the getMetaData method.
*
* @see ResultSetMetaData
@ -92,7 +93,7 @@ public class ResultSet implements java.sql.ResultSet
* the first call to next makes the first row the current row;
* the second call makes the second row the current row, etc.
*
* If an input stream from the previous row is open, it is
* <p>If an input stream from the previous row is open, it is
* implicitly closed. The ResultSet's warning chain is cleared
* when a new row is read
*
@ -114,7 +115,7 @@ public class ResultSet implements java.sql.ResultSet
* when it is automatically closed. The close method provides this
* immediate release.
*
* <B>Note:</B> A ResultSet is automatically closed by the Statement
* <p><B>Note:</B> A ResultSet is automatically closed by the Statement
* the Statement that generated it when that Statement is closed,
* re-executed, or is used to retrieve the next result from a sequence
* of multiple results. A ResultSet is also automatically closed
@ -150,11 +151,17 @@ public class ResultSet implements java.sql.ResultSet
*/
public String getString(int columnIndex) throws SQLException
{
byte[] bytes = getBytes(columnIndex);
if (bytes == null)
//byte[] bytes = getBytes(columnIndex);
//
//if (bytes == null)
//return null;
//return new String(bytes);
if (columnIndex < 1 || columnIndex > fields.length)
throw new SQLException("Column Index out of range");
wasNullFlag = (this_row[columnIndex - 1] == null);
if(wasNullFlag)
return null;
return new String(bytes);
return new String(this_row[columnIndex - 1]);
}
/**
@ -347,8 +354,14 @@ public class ResultSet implements java.sql.ResultSet
}
/**
* Get the value of a column in the current row as a Java byte array
* The bytes represent the raw values returned by the driver.
* Get the value of a column in the current row as a Java byte array.
*
* <p>In normal use, the bytes represent the raw values returned by the
* backend. However, if the column is an OID, then it is assumed to
* refer to a Large Object, and that object is returned as a byte array.
*
* <p><b>Be warned</b> If the large object is huge, then you may run out
* of memory.
*
* @param columnIndex the first column is 1, the second is 2, ...
* @return the column value; if the value is SQL NULL, the result
@ -360,6 +373,17 @@ public class ResultSet implements java.sql.ResultSet
if (columnIndex < 1 || columnIndex > fields.length)
throw new SQLException("Column Index out of range");
wasNullFlag = (this_row[columnIndex - 1] == null);
// Handle OID's as BLOBS
if(!wasNullFlag)
if( fields[columnIndex - 1].getOID() == 26) {
LargeObjectManager lom = connection.getLargeObjectAPI();
LargeObject lob = lom.open(getInt(columnIndex));
byte buf[] = lob.read(lob.size());
lob.close();
return buf;
}
return this_row[columnIndex - 1];
}
@ -374,7 +398,7 @@ public class ResultSet implements java.sql.ResultSet
public java.sql.Date getDate(int columnIndex) throws SQLException
{
String s = getString(columnIndex);
SimpleDateFormat df = new SimpleDateFormat(connection.europeanDates?"dd-MM-yyyy":"MM-dd-yyyy");
SimpleDateFormat df = new SimpleDateFormat(connection.getDateStyle());
try {
return new java.sql.Date(df.parse(s).getTime());
} catch (ParseException e) {
@ -449,13 +473,13 @@ public class ResultSet implements java.sql.ResultSet
* The JDBC driver will do any necessary conversion from the
* database format into ASCII.
*
* <B>Note:</B> All the data in the returned stream must be read
* <p><B>Note:</B> All the data in the returned stream must be read
* prior to getting the value of any other column. The next call
* to a get method implicitly closes the stream. Also, a stream
* may return 0 for available() whether there is data available
* or not.
*
* We implement an ASCII stream as a Binary stream - we should really
*<p> We implement an ASCII stream as a Binary stream - we should really
* do the data conversion, but I cannot be bothered to implement this
* right now.
*
@ -494,8 +518,8 @@ public class ResultSet implements java.sql.ResultSet
*
* @param columnIndex the first column is 1, the second is 2...
* @return a Java InputStream that delivers the database column value
* as a stream of two byte Unicode characters. If the value is
* SQL NULL, then the result is null
* as a stream of bytes. If the value is SQL NULL, then the result
* is null
* @exception SQLException if a database access error occurs
* @see getAsciiStream
* @see getUnicodeStream
@ -603,10 +627,10 @@ public class ResultSet implements java.sql.ResultSet
* returned. Subsequent ResultSet warnings will be chained
* to this SQLWarning.
*
* The warning chain is automatically cleared each time a new
* <p>The warning chain is automatically cleared each time a new
* row is read.
*
* <B>Note:</B> This warning chain only covers warnings caused by
* <p><B>Note:</B> This warning chain only covers warnings caused by
* ResultSet methods. Any warnings caused by statement methods
* (such as reading OUT parameters) will be chained on the
* Statement object.
@ -633,16 +657,16 @@ public class ResultSet implements java.sql.ResultSet
/**
* Get the name of the SQL cursor used by this ResultSet
*
* In SQL, a result table is retrieved though a cursor that is
* <p>In SQL, a result table is retrieved though a cursor that is
* named. The current row of a result can be updated or deleted
* using a positioned update/delete statement that references
* the cursor name.
*
* JDBC supports this SQL feature by providing the name of the
* <p>JDBC supports this SQL feature by providing the name of the
* SQL cursor used by a ResultSet. The current row of a ResulSet
* is also the current row of this SQL cursor.
*
* <B>Note:</B> If positioned update is not supported, a SQLException
* <p><B>Note:</B> If positioned update is not supported, a SQLException
* is thrown.
*
* @return the ResultSet's SQL cursor name.
@ -668,12 +692,12 @@ public class ResultSet implements java.sql.ResultSet
/**
* Get the value of a column in the current row as a Java object
*
* This method will return the value of the given column as a
* <p>This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* This method may also be used to read database specific abstract
* <p>This method may also be used to read database specific abstract
* data types.
*
* @param columnIndex the first column is 1, the second is 2...
@ -714,19 +738,19 @@ public class ResultSet implements java.sql.ResultSet
case Types.TIMESTAMP:
return getTimestamp(columnIndex);
default:
return new PG_Object(field.getTypeName(), getString(columnIndex));
return connection.getObject(field.getTypeName(), getString(columnIndex));
}
}
/**
* Get the value of a column in the current row as a Java object
*
* This method will return the value of the given column as a
*<p> This method will return the value of the given column as a
* Java object. The type of the Java object will be the default
* Java Object type corresponding to the column's SQL type, following
* the mapping specified in the JDBC specification.
*
* This method may also be used to read database specific abstract
* <p>This method may also be used to read database specific abstract
* data types.
*
* @param columnName is the SQL name of the column
@ -816,8 +840,6 @@ public class ResultSet implements java.sql.ResultSet
* particular, we need to know the number of rows and the
* number of columns. Rows are also known as Tuples
*
* getTupleCount returns the number of rows
*
* @return the number of rows
*/
public int getTupleCount()

View File

@ -6,9 +6,6 @@ import java.util.*;
import postgresql.*;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* A ResultSetMetaData object can be used to find out about the types and
* properties of the columns in a ResultSet
*

View File

@ -3,13 +3,10 @@ package postgresql;
import java.sql.*;
/**
* @version 1.0 15-APR-1997
* @author <A HREF="mailto:adrian@hottub.org">Adrian Hall</A>
*
* A Statement object is used for executing a static SQL statement and
* obtaining the results produced by it.
*
* Only one ResultSet per Statement can be open at any point in time.
* <p>Only one ResultSet per Statement can be open at any point in time.
* Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different
* Statements. All statement execute methods implicitly close a
@ -23,7 +20,6 @@ public class Statement implements java.sql.Statement
Connection connection; // The connection who created us
ResultSet result = null; // The current results
SQLWarning warnings = null; // The warnings chain.
int maxrows = 0; // maximum no. of rows; 0 = unlimited
int timeout = 0; // The timeout for a query (not used)
boolean escapeProcessing = true;// escape processing flag
@ -78,7 +74,7 @@ public class Statement implements java.sql.Statement
* for this to happen when it is automatically closed. The
* close method provides this immediate release.
*
* <B>Note:</B> A Statement is automatically closed when it is
* <p><B>Note:</B> A Statement is automatically closed when it is
* garbage collected. When a Statement is closed, its current
* ResultSet, if one exists, is also closed.
*
@ -126,7 +122,7 @@ public class Statement implements java.sql.Statement
*/
public int getMaxRows() throws SQLException
{
return maxrows;
return connection.maxrows;
}
/**
@ -138,7 +134,7 @@ public class Statement implements java.sql.Statement
*/
public void setMaxRows(int max) throws SQLException
{
maxrows = max;
connection.maxrows = max;
}
/**
@ -197,10 +193,10 @@ public class Statement implements java.sql.Statement
* chain. Subsequent Statement warnings will be chained to this
* SQLWarning.
*
* The Warning chain is automatically cleared each time a statement
* <p>The Warning chain is automatically cleared each time a statement
* is (re)executed.
*
* <B>Note:</B> If you are processing a ResultSet then any warnings
* <p><B>Note:</B> If you are processing a ResultSet then any warnings
* associated with ResultSet reads will be chained on the ResultSet
* object.
*
@ -231,12 +227,12 @@ public class Statement implements java.sql.Statement
* doesn't support positioned update/delete, this method is a
* no-op.
*
* <B>Note:</B> By definition, positioned update/delete execution
* <p><B>Note:</B> By definition, positioned update/delete execution
* must be done by a different Statement than the one which
* generated the ResultSet being used for positioning. Also, cursor
* names must be unique within a Connection.
*
* We throw an additional constriction. There can only be one
* <p>We throw an additional constriction. There can only be one
* cursor active at any one time.
*
* @param name the new cursor name