Thu Jan 18 12:24:00 GMT 2001 peter@retep.org.uk

- These methods in org.postgresql.jdbc2.ResultSet are now implemented:
            getBigDecimal(int) ie: without a scale (why did this get missed?)
            getBlob(int)
            getCharacterStream(int)
            getConcurrency()
            getDate(int,Calendar)
            getFetchDirection()
            getFetchSize()
            getTime(int,Calendar)
            getTimestamp(int,Calendar)
            getType()
          NB: Where int represents the column name, the associated version
              taking a String were already implemented by calling the int
              version.
        - These methods no longer throw the not implemented but the new noupdate
          error. This is in preparation for the Updateable ResultSet support
          which will overide these methods by extending the existing class to
          implement that functionality, but needed to show something other than
          notimplemented:
            cancelRowUpdates()
            deleteRow()
        - Added new error message into errors.properties "postgresql.noupdate"
          This is used by jdbc2.ResultSet when an update method is called and
          the ResultSet is not updateable. A new method notUpdateable() has been
          added to that class to throw this exception, keeping the binary size
          down.
        - Added new error message into errors.properties "postgresql.psqlnotimp"
          This is used instead of unimplemented when it's a feature in the
          backend that is preventing this method from being implemented.
        - Removed getKeysetSize() as its not part of the ResultSet API

Thu Jan 18 09:46:00 GMT 2001 peter@retep.org.uk
        - Applied modified patch from Richard Bullington-McGuire
          <rbulling@microstate.com>. I had to modify it as some of the code
          patched now exists in different classes, and some of it actually
          patched obsolete code.

Wed Jan 17 10:19:00 GMT 2001 peter@retep.org.uk
        - Updated Implementation to include both ANT & JBuilder
        - Updated README to reflect the changes since 7.0
	- Created jdbc.jpr file which allows JBuilder to be used to edit the
          source. JBuilder _CAN_NOT_ be used to compile. You must use ANT for
          that. It's only to allow JBuilders syntax checking to improve the
          drivers source. Refer to Implementation for more details
This commit is contained in:
Peter Mount 2001-01-18 14:50:15 +00:00
parent 89ac643964
commit 45b5d792af
25 changed files with 1459 additions and 550 deletions

94
build.xml Normal file
View File

@ -0,0 +1,94 @@
<!--
build file to allow ant (http://jakarta.apache.org/ant/) to be used
to build the PostgreSQL JDBC Driver and any associated java utilities under
/contrib.
This is placed here for three reasons:
1: You only need to run ANT once to get everything.
2: To let people know that there are more java sources under /contrib.
3: In the next release (after 7.1) it's intended to have configure to
detect the presence of both the JDK and ANT, and if both are found
to build the jdbc driver and utils with the rest of postgresql.
$Id: build.xml,v 1.1 2001/01/18 14:50:14 peter Exp $
-->
<project name="postgresql" default="jar" basedir=".">
<!--
This is the normal entry point. It builds first the
jdbc driver, then the extra tools.
-->
<target name="jar">
<antcall target="call">
<param name="target" value="jar" />
</antcall>
</target>
<!--
This entry point clears the source tree. Call this when you want
to build a clean install.
-->
<target name="clean">
<antcall target="call">
<param name="target" value="clean" />
</antcall>
</target>
<!--
This entry point installs the .jar files into an install directory.
To use this, call ant as follows:
ant -Dinstall.directory=mydir install
Where mydir is the _Absolute_ path of the directory to create.
If the directory mydir does not exist it will be created.
If the directory is not absolute then the install will fail by
creating subdirectories in the build path. Be careful.
This is intended for "make install" to call it.
e.g.
Windows: ant -Dc:\jars install
Unix: ant -Dinstall.directory=/usr/local/lib/jars install
Cygwin: ant -Dinstall.directory=$(cygpath -w /usr/local/lib/jars) install
-->
<target name="install" if="install.directory">
<mkdir dir="${install.directory}" />
<antcall target="call">
<param name="target" value="install" />
</antcall>
</target>
<!--
This actually calls the other two build.xml files.
To use it, use the <antcall> tag, and pass the destination target
within a <param> tag using name="target".
ie:
<antcall target="call">
<param name="target" value="mytarget" />
</antcall>
Here, the target mytarget will be called from all the sub build.xml
files.
Note: The target must be present in _ALL_ build.xml files otherwise
the build will fail.
-->
<target name="call">
<ant dir="src/interfaces/jdbc" target="${target}" />
<ant dir="contrib/retep" target="${target}" />
</target>
</project>

0
contrib/retep/CHANGELOG Normal file
View File

View File

0
contrib/retep/README Normal file
View File

60
contrib/retep/build.xml Normal file
View File

@ -0,0 +1,60 @@
<!--
build file to build the donated retep tools packages
$Id: build.xml,v 1.1 2001/01/18 14:50:14 peter Exp $
-->
<project name="retep" default="jar" basedir=".">
<!-- set global properties for this build -->
<property name="src" value="." />
<property name="dest" value="build" />
<property name="package" value="uk/org/retep" />
<property name="jars" value="jars" />
<!-- Some checks used to build dependent on the environment -->
<target name="checks">
<available property="jdk1.2+" classname="java.lang.ThreadLocal" />
<available property="jdk1.3+" classname="java.lang.StrictMath" />
<available property="jdk1.2e+" classname="javax.sql.DataSource" />
<available property="xml" classname="org.xml.sax.Parser" />
</target>
<!-- Prepares the build by creating a directory to place the class files -->
<target name="prepare">
<mkdir dir="${dest}" />
<mkdir dir="${jars}" />
</target>
<!-- This target removes any class files from the build directory -->
<target name="clean">
<delete dir="${dest}" />
<delete dir="${jars}" />
</target>
<!-- Builds the XML Tools -->
<target name="xml" depends="checks,prepare" if="xml">
<javac srcdir="${src}" destdir="${dest}">
<include name="${package}/xml/**" />
</javac>
</target>
<!-- Builds the various jar files -->
<target name="jar" depends="xml">
<jar jarfile="${jars}/retepTools.jar" basedir="${dest}">
<include name="${package}/xml/parser/**" if="xml" />
</jar>
</target>
<target name="install" depends="jar" if="install.directory">
<copy todir="${install.directory}" overwrite="true" filtering="off">
<fileset dir="${jars}">
<include name="**/*.jar" />
</fileset>
</copy>
</target>
</project>

44
contrib/retep/retep.jpx Normal file
View File

@ -0,0 +1,44 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--JBuilder XML Project-->
<project>
<property category="idl" name="ProcessIDL" value="false" />
<property category="runtime.0" name="RunnableType" value="com.borland.jbuilder.runtime.ApplicationRunner" />
<property category="runtime.0" name="jsprunner.docbase" value="." />
<property category="runtime.0" name="jsprunner.jspfile" value="E%|/docs/java/xml/example6" />
<property category="sys" name="AuthorLabel" value="@author" />
<property category="sys" name="BackupPath" value="bak" />
<property category="sys" name="BeansInstantiate" value="false" />
<property category="sys" name="BraceStyle" value="1" />
<property category="sys" name="CheckStable" value="1" />
<property category="sys" name="Company" value="" />
<property category="sys" name="CompanyLabel" value="Company:" />
<property category="sys" name="Copyright" value="Copyright (c) 2001" />
<property category="sys" name="CopyrightLabel" value="Copyright:" />
<property category="sys" name="DefaultPackage" value="org.postgresql.core" />
<property category="sys" name="Description" value="" />
<property category="sys" name="DescriptionLabel" value="Description:" />
<property category="sys" name="DocPath" value="doc" />
<property category="sys" name="EventMatch" value="false" />
<property category="sys" name="EventStyle" value="1" />
<property category="sys" name="ExcludeClassEnabled" value="0" />
<property category="sys" name="InstanceVisibility" value="0" />
<property category="sys" name="JDK" value="java 1.3.0-C" />
<property category="sys" name="LastTag" value="0" />
<property category="sys" name="Libraries" value="JAXP" />
<property category="sys" name="MakeStable" value="0" />
<property category="sys" name="OutPath" value="build" />
<property category="sys" name="SourcePath" value="." />
<property category="sys" name="Title" value="" />
<property category="sys" name="TitleLabel" value="Title:" />
<property category="sys" name="Version" value="1.0" />
<property category="sys" name="VersionLabel" value="@version" />
<property category="sys" name="WorkingDirectory" value="." />
<node type="Package" name="uk.org.retep.xml.jdbc" />
<node type="Package" name="uk.org.retep.xml.parser" />
<file path="build.xml" />
<file path="CHANGELOG" />
<file path="Implementation" />
<file path="README" />
</project>

View File

@ -0,0 +1,202 @@
package uk.org.retep.xml.parser;
import java.io.CharArrayWriter;
import java.io.IOException;
import java.util.List;
import java.util.Iterator;
import java.util.Map;
import java.util.HashSet;
import java.util.ArrayList;
import java.util.HashMap;
import org.xml.sax.AttributeList;
import org.xml.sax.HandlerBase;
import org.xml.sax.InputSource;
import org.xml.sax.Parser;
import org.xml.sax.SAXException;
import javax.xml.parsers.ParserConfigurationException;
import javax.xml.parsers.SAXParser;
import javax.xml.parsers.SAXParserFactory;
/**
* This class implements the base of the XML handler. You create an instance,
* register classes (who implement TagListener) that are interested in the tags
* and pass it to SAX.
*
* <p>Or you create an instance, register the TagListeners and use the getParser()
* method to create a Parser. Then start parsing by calling it's parse() method.
*/
public class TagHandler extends HandlerBase {
/**
* The current active level
*/
private int level;
/**
* cache used to handle nesting of tags
*/
private List contents;
/**
* cache used to handle nesting of tags
*/
private List tags;
/**
* cache used to handle nesting of tags
*/
private List args;
// Current active content writer
private CharArrayWriter content;
// List of TagListener's who want to be fed data
private HashSet tagListeners;
/**
* default constructor
*/
public TagHandler() {
level=0;
contents = new ArrayList();
tags = new ArrayList();
args = new ArrayList();
tagListeners = new HashSet();
}
/**
* Called by SAX when a tag is begun. This simply creates a new level in the
* cache and stores the parameters and tag name in there.
*/
public void startElement(String p0, AttributeList p1) throws SAXException {
// Now move up and fetch a CharArrayWriter from the cache
// creating if this is the first time at this level
if(contents.size()<=level) {
contents.add(new CharArrayWriter());
tags.add(p0);
args.add(new HashMap());
}
content=(CharArrayWriter) contents.get(level);
content.reset();
// Also cache the tag's text and argument list
tags.set(level,p0);
HashMap h = (HashMap) args.get(level);
h.clear();
for(int i=p1.getLength()-1;i>-1;i--) {
h.put(p1.getName(i),p1.getValue(i));
}
// Now notify any TagListeners
Iterator it = tagListeners.iterator();
while(it.hasNext())
( (TagListener) it.next() ).tagStart(level,p0,h);
// Now move up a level
level++;
}
/**
* This is called by SAX at the end of a tag. This calls handleTag() and then
* raises the level, so that the previous parent tag may continue.
*/
public void endElement(String p0) throws SAXException {
// move up a level retrieving that level's current content
// Now this exception should never occur as the underlying parser should
// actually trap it.
if(level<1)
throw new SAXException("Already at top level?");
level--;
// Now notify any TagListeners
Iterator it = tagListeners.iterator();
while(it.hasNext())
( (TagListener) it.next() ).tagContent(content);
// allows large content to be released early
content.reset();
// Now reset content to the previous level
content=(CharArrayWriter) contents.get(level);
}
/**
* Called by SAX so that content between the start and end tags are captured.
*/
public void characters(char[] p0, int p1, int p2) throws SAXException {
content.write(p0,p1,p2);
}
/**
* Adds a TagListener so that it is notified of tags as they are processed.
* @param handler TagListener to add
*/
public void addTagListener(TagListener h) {
tagListeners.add(h);
}
/**
* Removes the TagListener so it no longer receives notifications of tags
*/
public void removeTagListener(TagListener h) {
tagListeners.remove(h);
}
/**
* This method returns a org.xml.sax.Parser object that will parse the
* contents of a URI.
*
* <p>Normally you would call this method, then call the parse(uri) method of
* the returned object.
* @return org.xml.sax.Parser object
*/
public Parser getParser()
throws SAXException
{
try {
SAXParserFactory spf = SAXParserFactory.newInstance();
String validation = System.getProperty ("javax.xml.parsers.validation", "false");
if (validation.equalsIgnoreCase("true"))
spf.setValidating (true);
SAXParser sp = spf.newSAXParser();
Parser parser = sp.getParser ();
parser.setDocumentHandler(this);
return(parser);
} catch(ParserConfigurationException pce) {
throw new SAXException(pce.toString());
}
}
/**
* This method will parse the specified URI.
*
* <p>Internally this is the same as getParser().parse(uri);
* @param uri The URI to parse
*/
public void parse(String uri)
throws IOException, SAXException
{
getParser().parse(uri);
}
/**
* This method will parse the specified InputSource.
*
* <p>Internally this is the same as getParser().parse(is);
* @param is The InputSource to parse
*/
public void parse(InputSource is)
throws IOException, SAXException
{
getParser().parse(is);
}
}

View File

@ -0,0 +1,30 @@
package uk.org.retep.xml.parser;
import java.util.HashMap;
import java.io.CharArrayWriter;
/**
* This interface defines the methods a class needs to implement if it wants the
* xml parser to notify it of any xml tags.
*/
public interface TagListener {
/**
* This is called when a tag has just been started.
* <p><b>NB:</b> args is volatile, so if you use it beyond the lifetime of
* this call, then you must make a copy of the HashMap (and not use simply
* store this HashMap).
* @param level The number of tags above this
* @param tag The tag name
* @param args A HashMap of any arguments
*/
public void tagStart(int level,String tag,HashMap args);
/**
* This method is called by ContHandler to process a tag once it has been
* fully processed.
* <p><b>NB:</b> content is volatile, so you must copy its contents if you use
* it beyond the lifetime of this call.
* @param content CharArrayWriter containing the content of the tag.
*/
public void tagContent(CharArrayWriter content);
}

View File

@ -1,3 +1,49 @@
Thu Jan 18 12:24:00 GMT 2001 peter@retep.org.uk
- These methods in org.postgresql.jdbc2.ResultSet are now implemented:
getBigDecimal(int) ie: without a scale (why did this get missed?)
getBlob(int)
getCharacterStream(int)
getConcurrency()
getDate(int,Calendar)
getFetchDirection()
getFetchSize()
getTime(int,Calendar)
getTimestamp(int,Calendar)
getType()
NB: Where int represents the column name, the associated version
taking a String were already implemented by calling the int
version.
- These methods no longer throw the not implemented but the new noupdate
error. This is in preparation for the Updateable ResultSet support
which will overide these methods by extending the existing class to
implement that functionality, but needed to show something other than
notimplemented:
cancelRowUpdates()
deleteRow()
- Added new error message into errors.properties "postgresql.noupdate"
This is used by jdbc2.ResultSet when an update method is called and
the ResultSet is not updateable. A new method notUpdateable() has been
added to that class to throw this exception, keeping the binary size
down.
- Added new error message into errors.properties "postgresql.psqlnotimp"
This is used instead of unimplemented when it's a feature in the
backend that is preventing this method from being implemented.
- Removed getKeysetSize() as its not part of the ResultSet API
Thu Jan 18 09:46:00 GMT 2001 peter@retep.org.uk
- Applied modified patch from Richard Bullington-McGuire
<rbulling@microstate.com>. I had to modify it as some of the code
patched now exists in different classes, and some of it actually
patched obsolete code.
Wed Jan 17 10:19:00 GMT 2001 peter@retep.org.uk
- Updated Implementation to include both ANT & JBuilder
- Updated README to reflect the changes since 7.0
- Created jdbc.jpr file which allows JBuilder to be used to edit the
source. JBuilder _CAN_NOT_ be used to compile. You must use ANT for
that. It's only to allow JBuilders syntax checking to improve the
drivers source. Refer to Implementation for more details
Wed Dec 20 16:19:00 GMT 2000 peter@retep.org.uk Wed Dec 20 16:19:00 GMT 2000 peter@retep.org.uk
- Finished build.xml and updated Driver.java.in and buildDriver to - Finished build.xml and updated Driver.java.in and buildDriver to
match how Makefile and ANT operate. match how Makefile and ANT operate.
@ -12,23 +58,23 @@ Tue Oct 17 15:35:00 BST 2000 petermount@maidstone.gov.uk
- Changed getTimestamp() again. This time Michael Stephenson's - Changed getTimestamp() again. This time Michael Stephenson's
<mstephenson@tirin.openworld.co.uk> solution looked far better <mstephenson@tirin.openworld.co.uk> solution looked far better
than the original solution put in June. than the original solution put in June.
Tue Oct 10 13:12:00 BST 2000 peter@retep.org.uk Tue Oct 10 13:12:00 BST 2000 peter@retep.org.uk
- DatabaseMetaData.supportsAlterTableWithDropColumn() as psql doesn't - DatabaseMetaData.supportsAlterTableWithDropColumn() as psql doesn't
support dropping of individual columns support dropping of individual columns
- Merged in some last patches. Only 1 left, which may not be compatible - Merged in some last patches. Only 1 left, which may not be compatible
with jdbc1 with jdbc1
- Merged in my old retepsql project. Makefile now includes it. - Merged in my old retepsql project. Makefile now includes it.
Mon Oct 02 12:30:00 BST 2000 peter@retep.org.uk Mon Oct 02 12:30:00 BST 2000 peter@retep.org.uk
- Merged in byte[] array allocation changes submitted by Gunnar R|nning - Merged in byte[] array allocation changes submitted by Gunnar R|nning
<gunnar@candleweb.no> <gunnar@candleweb.no>
Mon Sep 25 14:22:00 BST 2000 peter@retep.org.uk Mon Sep 25 14:22:00 BST 2000 peter@retep.org.uk
- Removed the DriverClass kludge. Now the org.postgresql.Driver class - Removed the DriverClass kludge. Now the org.postgresql.Driver class
is compiled from a template file, and now has both the connection is compiled from a template file, and now has both the connection
class (ie jdbc1/jdbc2) and the current version's from Makefile.global class (ie jdbc1/jdbc2) and the current version's from Makefile.global
Thu Jul 20 16:30:00 BST 2000 petermount@it.maidstone.gov.uk Thu Jul 20 16:30:00 BST 2000 petermount@it.maidstone.gov.uk
- Fixed DatabaseMetaData.getTableTypes() - Fixed DatabaseMetaData.getTableTypes()
@ -56,24 +102,24 @@ Mon May 15 22:30:00 BST 2000 peter@retep.org.uk
Thu May 04 11:38:00 BST 2000 petermount@it.maidstone.gov.uk Thu May 04 11:38:00 BST 2000 petermount@it.maidstone.gov.uk
- Corrected incorrect date in CHANGELOG - Corrected incorrect date in CHANGELOG
- Fixed the ImageViewer example - Fixed the ImageViewer example
Wed May 03 16:47:00 BST 2000 petermount@it.maidstone.gov.uk Wed May 03 16:47:00 BST 2000 petermount@it.maidstone.gov.uk
- Fixed the Makefile so that postgresql.jar is built everytime - Fixed the Makefile so that postgresql.jar is built everytime
the jdbc1 or jdbc2 rules are called. the jdbc1 or jdbc2 rules are called.
- Fixed the threadsafe example. It had problems with autocommit - Fixed the threadsafe example. It had problems with autocommit
Wed May 03 14:32:00 BST 2000 petermount@it.maidstone.gov.uk Wed May 03 14:32:00 BST 2000 petermount@it.maidstone.gov.uk
- Rewrote the README file (the old one was 18 months old!) - Rewrote the README file (the old one was 18 months old!)
- Added @deprecated tags to org.postgresql.jdbc2.ResultSet - Added @deprecated tags to org.postgresql.jdbc2.ResultSet
to clear some warnings issued during compilation. to clear some warnings issued during compilation.
Wed Apr 12 22:14:00 BST 2000 peter@retep.org.uk Wed Apr 12 22:14:00 BST 2000 peter@retep.org.uk
- Implemented the JDBC2 Blob interface, and ResultSet.getBlob(). - Implemented the JDBC2 Blob interface, and ResultSet.getBlob().
Wed Apr 12 20:20:00 BST 2000 peter@retep.org.uk Wed Apr 12 20:20:00 BST 2000 peter@retep.org.uk
- Fixed bug in ResultSet.absolute(). Negative rows are now supported. - Fixed bug in ResultSet.absolute(). Negative rows are now supported.
- Implemented ResultSet.relative(), afterLast(). - Implemented ResultSet.relative(), afterLast().
Tue Feb 1 21:40:00 GMT 2000 peter@retep.org.uk Tue Feb 1 21:40:00 GMT 2000 peter@retep.org.uk
- Finally imported the contributed javax extensions by Assaf Arkin - Finally imported the contributed javax extensions by Assaf Arkin
arkin@exoffice.com arkin@exoffice.com
@ -109,7 +155,7 @@ Wed Aug 4 00:25:18 CEST 1999 jens@jens.de
Mon Aug 2 03:29:35 CEST 1999 jens@jens.de Mon Aug 2 03:29:35 CEST 1999 jens@jens.de
- fixed bug in DatabaseMetaData.getPrimaryKeys() - fixed bug in DatabaseMetaData.getPrimaryKeys()
Sun Aug 1 18:05:42 CEST 1999 jens@jens.de Sun Aug 1 18:05:42 CEST 1999 jens@jens.de
- added support for getTransactionIsolation and setTransactionIsolation - added support for getTransactionIsolation and setTransactionIsolation
@ -212,7 +258,7 @@ Web Oct 7 22:00:00 BST 1998
FastPath.fastpath() methods. They now lock against the PG_Steam FastPath.fastpath() methods. They now lock against the PG_Steam
object for the connection, which now provides full Thread Safety. object for the connection, which now provides full Thread Safety.
- Reposted ChangeLog as it's missing from CVS. - Reposted ChangeLog as it's missing from CVS.
Modifications done since 6.3.2 was released and Sun Aug 30 11:33:06 BST 1998 Modifications done since 6.3.2 was released and Sun Aug 30 11:33:06 BST 1998
- Fixed PreparedStatement.setObject as it didn't handle shorts - Fixed PreparedStatement.setObject as it didn't handle shorts
@ -228,7 +274,7 @@ Modifications done since 6.3.2 was released and Sun Aug 30 11:33:06 BST 1998
properties are missing, as they are required for JDBC to work. properties are missing, as they are required for JDBC to work.
This occasionally occurs when the client uses the properties version This occasionally occurs when the client uses the properties version
of getConnection(), and is a common question on the email lists. of getConnection(), and is a common question on the email lists.
Sun Aug 30 11:33:06 BST 1998 Sun Aug 30 11:33:06 BST 1998
- Created ChangeLog file, and entered stuff done since 6.3.2 and today - Created ChangeLog file, and entered stuff done since 6.3.2 and today
@ -290,4 +336,4 @@ Sun Aug 30 11:33:06 BST 1998
and getSchemaName(). and getSchemaName().
- Created new class postgresql.util.PGmoney to map the money type - Created new class postgresql.util.PGmoney to map the money type
- Created new class postgresql.geometric.PGline to map the line type - Created new class postgresql.geometric.PGline to map the line type

View File

@ -1,28 +1,87 @@
This short document is provided to help programmers through the internals of This short document is provided to help programmers through the internals of
the PostgreSQL JDBC driver. the PostgreSQL JDBC driver.
Last update: January 17 2001 peter@retep.org.uk
build.xml
---------
As of 7.1, we now use the ANT build tool to build the driver. ANT is part of
the Apache/Jakarta project, and provides far superior build capabilities. You
can find ANT from http://jakarta.apache.org/ant/index.html and being pure java
it will run on any java platform.
So far I've tested it under JDK1.2.x & JDK1.3 (both Linux & NT) but not yet with
JDK1.1.8. Because of the latter the Makefile still works for now, but should be
gone for 7.2.
Anyhow, to build, simply type ant and the .jar file will be created and put into
the jars directory.
Tip: If you run ant from the sources root directory (ie: where the configure
script is located) you will find another build.xml file. It is advised to run
ant from that directory as it will then compile some auxilary Java/JDBC
utilities that are located under the /contrib/retep directory.
Makefile Makefile
-------- --------
All compilation must be done by using Make. This is because there are two Prior to 7.1, all compilation must be done by using Make. This is because there
versions of the driver, one for JDBC1 (for JDK 1.1.x) and the other for JDBC2 are three versions of the driver, one for JDBC1 (for JDK 1.1.x) and the others
(for JDK 1.2 or later). The makefile determines which version to compile by for JDBC2 (for JDK 1.2 or later, one standard and one enterprise).
using a helper class makeVersion. This class is only used by make, and is not
stored in the Jar file.
Note: It is not sufficient to simply call javac on postgresql/Driver.java as As of 7.1, ANT is the build tool of choice. Just compare Makefile and build.xml
some classes are dynamically loaded, so javac will not compile them. to see why! Make just isn't suited to Java.
Building with just the JDK
--------------------------
This is not advised, simply because you have to make sure you include the
correct classes, and the fact that org.postgresql.Driver is built on the fly.
Also, javac won't pick up all the classes because some (org.postgresql.geometric
for example) are loaded dynamically.
org/postgresql/Driver.java.in
-----------------------------
Because there are three versions of the driver, the org.postgresql.Driver class
is built dynamically. To build correctly ANT copies the Driver.java.in file to
Driver.java replacing certain values according to the required driver.
The replaced values are of the format %VALUE%, ie: %MAJORVERSION% is replaced
with 7 in the 7.1 version of the driver.
postgresql.jar postgresql.jar
-------------- --------------
This jar file is produced by make, and contains the driver for your JDK This jar file is produced by ANT, and contains the driver for your JDK platform.
platform.
Note: It is possible to compile the driver under say JDK1.1.7, then under If you downloaded a precompiled binary from the web, you may find that the
JDK 1.2. Because make doesn't remove the old classes before compiling, jar file will be named differently. These are identical to this file but are
jar will simply package both sets together. When the driver is loaded, named according to the backend and jdk versions.
the postgresql.Driver class will sort out which set of classes to use.
The naming convention is of the form: jdbc-#.#-#.##.jar
ie: for 7.1
jdbc-7.1-1.1.jar JDBC Driver for JDK1.1.8
jdbc-7.1-1.2.jar JDBC Driver for JDK1.2 & JDK1.3
jdbc-7.1-1.2ent.jar JDBC Driver for JDK1.2 & JDK1.3 Enterprise Editions
If in the future there are any 1.3 specific classes then there will be two new
jar files.
Note: All the precompiled binaries are built under Linux.
jdbc.jpx
--------
This is a JBuilder4 project file. It's here to allow JBuilder to be used to
develop the driver. Mainly for it's Editor's features like syntax checking and
auto-completion etc.
IMPORTANT: You CAN NOT build the driver from within JBuilder. You must use ANT.
This is because of the three versions of the JDK. If you try to use
JBuilder, it will try to build everything, and it will just not work.
Importing packages Importing packages
------------------ ------------------
@ -50,16 +109,17 @@ Package Layout
The driver is split into several packages: The driver is split into several packages:
postgresql core classes, common to both JDBC 1 & 2 org.postgresql core classes that can be accessed by user code
postgresql.jdbc1 classes used only in implementing JDBC 1 org.postgresql.core core classes not normally used externally
postgresql.jdbc2 classes used only in implementing JDBC 2 org.postgresql.jdbc1 classes used only in implementing JDBC 1
postgresql.fastpath FastPath to backend functions org.postgresql.jdbc2 classes used only in implementing JDBC 2
postgresql.geometric 2D Geometric types mapped to Java Objects org.postgresql.fastpath FastPath to backend functions
postgresql.largeobject Low level Large Object access org.postgresql.geometric 2D Geometric types mapped to Java Objects
postgresql.util Utility classes org.postgresql.largeobject Low level Large Object access
org.postgresql.util Utility classes
Package postgresql Package org.postgresql
------------------ ------------------
This package holds the core classes. This package holds the core classes.
@ -70,6 +130,9 @@ Driver registers the driver when it's loaded, and determines which
Field Used internally to represent a Field Field Used internally to represent a Field
PG_Stream Used internally to manage the network stream. PG_Stream Used internally to manage the network stream.
PostgresqlDataSource
Exists in the Java2 Enterprise edition driver only and is the
enterprise equivalent to Driver
These classes contains common code that is not dependent to the These classes contains common code that is not dependent to the
two JDBC specifications. two JDBC specifications.
@ -77,13 +140,25 @@ PG_Stream Used internally to manage the network stream.
Connection Common code used in Connections, mainly Network Protocol stuff. Connection Common code used in Connections, mainly Network Protocol stuff.
ResultSet Common code used in ResultSet's ResultSet Common code used in ResultSet's
Package postgresql.fastpath Package org.postgresql.core
-----------------------
New in 7.1, this is where core classes (common to all versions) will exist. Any
new class that would have gone into org.postgresql must go in here instead.
BytePoolDim1 Handles a pool of byte[] arrays.
BytePoolDim2 Handles a pool of byte[][] arrays
MemoryPool Interface for managing MemoryPools. Not used (yet).
ObjectPool Interface for an Object Pool
SimpleObjectPool Class that implements ObjectPool and used by BytePoolDim#
Package org.postgresql.fastpath
--------------------------- ---------------------------
Fastpath Handles executing a function on the PostgreSQL Backend Fastpath Handles executing a function on the PostgreSQL Backend
FastpathArg Defines an argument for a function call FastpathArg Defines an argument for a function call
Package postgresql.geometric Package org.postgresql.geometric
---------------------------- ----------------------------
PGbox Maps to postgresql type box PGbox Maps to postgresql type box
@ -94,25 +169,25 @@ PGpath Maps to postgresql type path
PGpoint Maps to postgresql type point PGpoint Maps to postgresql type point
PGpolygon Maps to postgresql type polygon PGpolygon Maps to postgresql type polygon
Package postgresql.jdbc1 Package org.postgresql.jdbc1
------------------------ ------------------------
The classes in this package handle the JDBC 1 Specification, for JDK 1.1.x The classes in this package handle the JDBC 1 Specification, for JDK 1.1.x
All interfaces in the java.sql package are present here. All interfaces in the java.sql package are present here.
Package postgresql.jdbc2 Package org.postgresql.jdbc2
------------------------ ------------------------
The classes in this package handle the JDBC 2 Specification, for JDK 1.2 The classes in this package handle the JDBC 2 Specification, for JDK 1.2
All interfaces in the java.sql, and javax.sql packages are present here. All interfaces in the java.sql, and javax.sql packages are present here.
Package postgresql.largeobject Package org.postgresql.largeobject
------------------------------ ------------------------------
LargeObject Represents an open LargeObject LargeObject Represents an open LargeObject
LargeObjectManager Handles the opening and deleting of LargeObjects LargeObjectManager Handles the opening and deleting of LargeObjects
Package postgresql.util Package org.postgresql.util
----------------------- -----------------------
PGmoney Maps to postgresql type money PGmoney Maps to postgresql type money

View File

@ -4,7 +4,7 @@
# Makefile for Java JDBC interface # Makefile for Java JDBC interface
# #
# IDENTIFICATION # IDENTIFICATION
# $Id: Makefile,v 1.25 2000/10/12 08:55:23 peter Exp $ # $Id: Makefile,v 1.26 2001/01/18 14:50:14 peter Exp $
# #
#------------------------------------------------------------------------- #-------------------------------------------------------------------------
@ -39,10 +39,30 @@ PGBASE = org/postgresql
# New for 7.1: The jar filename # New for 7.1: The jar filename
JARFILE = postgresql.jar JARFILE = postgresql.jar
all:
@echo ------------------------------------------------------------
@echo The use of Make to build the driver is now depreciated in
@echo version 7.1 and later. To build the driver you now need to
@echo use ANT. This is the build tool of the Jakarta project, and
@echo you can obtain this from http://jakarta.apache.org/ant/
@echo
@echo Once you have this installed, change directory to the root
@echo directory of the postgresql source and type ant.
@echo
@echo ie: if you are currently in the pgsql/src/interfaces/jdbc
@echo directory then cd into the pgsql one \(cd ../../.. should
@echo do\).
@echo
@echo The file Implementation contains more info on this, as does
@echo the homepage http://jdbc.postgresql.org/
@echo ------------------------------------------------------------
# Yet another attempt to check the version. In theory, any JVM that fails # Yet another attempt to check the version. In theory, any JVM that fails
# this is breaking the versioning specifications released by Javasoft. # this is breaking the versioning specifications released by Javasoft.
# #
all: utils/CheckVersion.class # In 7.1 this is renamed oldall so that the depreciated message is shown.
#
oldall: utils/CheckVersion.class
@$(MAKE) `$(JAVA) utils.CheckVersion` @$(MAKE) `$(JAVA) utils.CheckVersion`
# For 6.5.3 and 7.0+, we need to select the correct JDBC API, so prompt # For 6.5.3 and 7.0+, we need to select the correct JDBC API, so prompt
@ -72,7 +92,10 @@ huho:
@echo @echo
@echo ------------------------------------------------------------ @echo ------------------------------------------------------------
msg: # In 7.1 replaced msg so that the depreciated message is shown.
msg: all
oldmsg:
@echo ------------------------------------------------------------ @echo ------------------------------------------------------------
@echo The JDBC driver has now been built. To make it available to @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 other applications, copy the postgresql.jar file to a public

View File

@ -1,34 +1,49 @@
This is a simple readme describing how to compile and use the jdbc driver. This is a simple readme describing how to compile and use the jdbc driver.
This file was amended on May 2 2000 to document the changes made in the 7.0 This file was amended on January 17 2001 to reflect the changes made in the 7.1
release. release.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
This isn't a guide on how to use JDBC - for that refer to Javasoft's web site: This isn't a guide on how to use JDBC - for that refer to Javasoft's web site:
http://www.javasoft.com http://www.javasoft.com/
For problems with this driver, then refer to the postgres-interfaces email For problems with this driver, then refer to the postgres-interfaces email
list: list:
http://www.postgresql.org http://www.postgresql.org/
The Driver's home page is:
http://jdbc.postgresql.org/
or http://www.retep.org.uk/postgresql/
NB: They are both the same physical directory so both will always be in sync
(unless the laws of physics break down ;-) )
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
COMPILING COMPILING
There are actually two versions of the driver. One for the JDBC1.2 specification, and one for the JDBC2 specification. To compile the driver, you need to select the correct one. To compile you will need to have ANT installed. To obtain ant go to
http://jakarta.apache.org/ant/index.html and download the binary. Being pure
java it will run on virtually all java platforms. If you have any problems
please email the INTERFACES list.
If you have JDK1.1.x you need to type: make jdbc1 Once you have ANT, cd to the src directory and type "ant". This will compile
the correct driver for your JVM, and build a .jar file (Java ARchive) called
If you have JDK1.2 or JDK1.3, you need to type: make jdbc2
This will compile the driver, and build a .jar file (Java ARchive) called
postgresql.jar postgresql.jar
That jar file will contain the driver for _your_ version of the JDK. That jar file will contain the driver for _your_ version of the JDK.
Note: As of 7.1, you build from pgsql/src and not pgsql/src/interfaces/jdbc.
Well you can, but building from the top will also build some extra utilities
located under /contrib at the same time. Also later on (either 7.1.1 or 7.2)
it's intended to have the main configure script to build the driver
automatically if it finds both a JDK & ANT installed, so this is the first step
towards that.
REMEMBER: Once you have compiled the driver, it will work on ALL platforms REMEMBER: Once you have compiled the driver, it will work on ALL platforms
that support that version of the API. You don't need to build it for each that support that version of the API. You don't need to build it for each
platform. platform.
@ -37,11 +52,8 @@ That means you don't have to compile it on every platform. Believe me, I
still hear from people who ask me "I've compiled it ok under Solaris, but it still hear from people who ask me "I've compiled it ok under Solaris, but it
won't compile under Linux" - there's no difference. won't compile under Linux" - there's no difference.
PS: When you run make, don't worry if you see more than one or two calls to I advise you don't try running javac outside of ANT as it builds some classes
javac. This is normal, because the driver dynamically loads classes, and on the fly.
the Makefile ensures everything gets compiled.
I advise you don't try running javac outside of make. You may miss something.
Possible problems Possible problems
@ -51,10 +63,13 @@ postgresql/Driver.java:87: interface java.sql.Connection is an interface. It can
return new Connection (host(), port(), props, database(), url, this); return new Connection (host(), port(), props, database(), url, this);
This is caused by not having the current directory in your CLASSPATH. Under This is caused by not having the current directory in your CLASSPATH. Under
Linux/Solaris, unset the CLASSPATH environment variable, and rerun make. Linux/Solaris, unset the CLASSPATH environment variable, and rerun ant.
If you are still having problems, I keep a copy of the driver (for different If you are still having problems, I keep a copy of the driver (for different
versions of the backend) on my web site http://www.retep.org.uk/postgres/ versions of the backend) on my web site http://www.retep.org.uk/postgres/
or http://jdbc.postgresql.org/
More details are in the Implementation file src/interfaces/jdbc/Implementation
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
@ -67,6 +82,9 @@ ie: under LINUX/SOLARIS (the example here is my linux box):
export CLASSPATH=.:/usr/local/lib/postgresql.jar export CLASSPATH=.:/usr/local/lib/postgresql.jar
Please don't be tempted to extract the files from the .jar file. There are a
lot of files in there, and you may break the Exception handling.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
USING THE DRIVER USING THE DRIVER
@ -122,6 +140,14 @@ them to the URL. eg:
jdbc:postgresql:database?user=me jdbc:postgresql:database?user=me
jdbc:postgresql:database?user=me&password=mypass jdbc:postgresql:database?user=me&password=mypass
Notes:
1) If you are connecting to localhost or 127.0.0.1 you can leave it out of the
URL. ie: jdbc:postgresql://localhost/mydb can be replaced with
jdbc:postgresql:mydb
2) The port defaults to 5432 if it's left out.
--------------------------------------------------------------------------- ---------------------------------------------------------------------------
That's the basics related to this driver. You'll need to read the JDBC Docs That's the basics related to this driver. You'll need to read the JDBC Docs

View File

@ -3,25 +3,26 @@
build file to allow ant (http://jakarta.apache.org/ant/) to be used build file to allow ant (http://jakarta.apache.org/ant/) to be used
to build the PostgreSQL JDBC Driver. to build the PostgreSQL JDBC Driver.
$Id: build.xml,v 1.2 2000/12/20 16:22:48 peter Exp $ $Id: build.xml,v 1.3 2001/01/18 14:50:14 peter Exp $
--> -->
<project name="postgresqlJDBC" default="jar" basedir="."> <project name="postgresqlJDBC" default="jar" basedir=".">
<!-- set global properties for this build --> <!-- set global properties for this build -->
<property name="src" value="." /> <property name="src" value="." />
<property name="jars" value="jars" />
<property name="dest" value="build" /> <property name="dest" value="build" />
<property name="package" value="org/postgresql" /> <property name="package" value="org/postgresql" />
<property name="major" value="7" /> <property name="major" value="7" />
<property name="minor" value="1" /> <property name="minor" value="1" />
<!-- <!--
This is a simpler method than utils.CheckVersion This is a simpler method than utils.CheckVersion
It defaults to jdbc1, but builds jdbc2 if the java.lang.Byte class is It defaults to jdbc1, but builds jdbc2 if the java.lang.Byte class is
in the CLASSPATH (ie JDK1.2 or later), and then enterprise if the in the CLASSPATH (ie JDK1.2 or later), and then enterprise if the
javax.sql.DataSource class is present. javax.sql.DataSource class is present.
Important: This must have the following order: jdbc1, jdbc2, enterprise Important: This must have the following order: jdbc1, jdbc2, enterprise
--> -->
<target name="check_versions"> <target name="check_versions">
@ -29,51 +30,53 @@
<available property="jdk1.3+" classname="java.lang.StrictMath" /> <available property="jdk1.3+" classname="java.lang.StrictMath" />
<available property="jdk1.2e+" classname="javax.sql.DataSource" /> <available property="jdk1.2e+" classname="javax.sql.DataSource" />
</target> </target>
<!-- <!--
This generates Driver.java from Driver.java.in This generates Driver.java from Driver.java.in
It's required for importing the driver version properties It's required for importing the driver version properties
--> -->
<target name="driver" depends="prepare,check_versions"> <target name="driver" depends="prepare,check_versions">
<!-- determine the edition text --> <!-- determine the edition text -->
<property name="edition" value="JDBC1" /> <property name="edition" value="JDBC1" />
<available property="edition" value="JDBC2" classname="java.lang.ThreadLocal" /> <available property="edition" value="JDBC2" classname="java.lang.ThreadLocal" />
<available property="edition" value="JDBC2" classname="java.lang.StrictMath" /> <available property="edition" value="JDBC2" classname="java.lang.StrictMath" />
<available property="edition" value="JDBC2 Enterprise" classname="javax.sql.DataSource" /> <available property="edition" value="JDBC2 Enterprise" classname="javax.sql.DataSource" />
<!-- determine the connection class --> <!-- determine the connection class -->
<property name="connectclass" value="org.postgresql.jdbc1.Connection" /> <property name="connectclass" value="org.postgresql.jdbc1.Connection" />
<available property="connectclass" value="org.postgresql.jdbc2.Connection" classname="java.lang.ThreadLocal" /> <available property="connectclass" value="org.postgresql.jdbc2.Connection" classname="java.lang.ThreadLocal" />
<!-- Some defaults --> <!-- Some defaults -->
<filter token="MAJORVERSION" value="${major}" /> <filter token="MAJORVERSION" value="${major}" />
<filter token="MINORVERSION" value="${minor}" /> <filter token="MINORVERSION" value="${minor}" />
<filter token="VERSION" value="PostgreSQL ${major}.${minor} ${edition}" /> <filter token="VERSION" value="PostgreSQL ${major}.${minor} ${edition}" />
<filter token="JDBCCONNECTCLASS" value="${connectclass}" /> <filter token="JDBCCONNECTCLASS" value="${connectclass}" />
<!-- Put a check for the current version here --> <!-- Put a check for the current version here -->
<!-- now copy and filter the file --> <!-- now copy and filter the file -->
<copy file="${package}/Driver.java.in" <copy file="${package}/Driver.java.in"
tofile="${package}/Driver.java" tofile="${package}/Driver.java"
filtering="yes" /> filtering="yes" />
<echo message="Configured build for the ${edition} edition driver." /> <echo message="Configured build for the ${edition} edition driver." />
</target> </target>
<!-- This target removes any class files from the build directory --> <!-- This target removes any class files from the build directory -->
<target name="clean"> <target name="clean">
<delete dir="${dest}" /> <delete dir="${dest}" />
<delete dir="${jars}" />
<delete file="${package}/Driver.java" /> <delete file="${package}/Driver.java" />
</target> </target>
<!-- Prepares the build directory --> <!-- Prepares the build directory -->
<target name="prepare"> <target name="prepare">
<mkdir dir="${dest}" /> <mkdir dir="${dest}" />
<mkdir dir="${jars}" />
</target> </target>
<!-- This is the core of the driver. It is common for all three versions --> <!-- This is the core of the driver. It is common for all three versions -->
<target name="compile" depends="prepare,check_versions,driver"> <target name="compile" depends="prepare,check_versions,driver">
<javac srcdir="${src}" destdir="${dest}"> <javac srcdir="${src}" destdir="${dest}">
@ -87,12 +90,27 @@
<copy todir="${dest}" overwrite="true" filtering="on"> <copy todir="${dest}" overwrite="true" filtering="on">
<fileset dir="${src}"> <fileset dir="${src}">
<include name="**/*.properties" /> <include name="**/*.properties" />
<exclude name="${dest}/**" />
</fileset> </fileset>
</copy> </copy>
</target> </target>
<!-- This builds the jar file containing the driver -->
<target name="jar" depends="compile"> <target name="jar" depends="compile">
<jar jarfile="postgresql.jar" basedir="${dest}" includes="org/**" /> <jar jarfile="${jars}/postgresql.jar" basedir="${dest}" includes="org/**" />
</target> </target>
<!--
This installs the jar file. It's called by the build.xml file in the
root directory of the source (where configure is). Refer to that file
on how to use it.
-->
<target name="install" depends="jar" if="install.directory">
<copy todir="${install.directory}" overwrite="true" filtering="off">
<fileset dir="${jars}">
<include name="**/*.jar" />
</fileset>
</copy>
</target>
</project> </project>

View File

@ -0,0 +1,31 @@
<?xml version="1.0" encoding="UTF-8"?>
<!--JBuilder XML Project-->
<project>
<property category="runtime.0" name="RunnableType" value="com.borland.jbuilder.runtime.ApplicationRunner" />
<property category="runtime.0" name="jsprunner.docbase" value="." />
<property category="runtime.0" name="jsprunner.jspfile" value="E%|/docs/java/xml/example6" />
<property category="sys" name="BackupPath" value="bak" />
<property category="sys" name="CheckStable" value="1" />
<property category="sys" name="Company" value="" />
<property category="sys" name="Copyright" value="Copyright (c) 2001" />
<property category="sys" name="DefaultPackage" value="org.postgresql.core" />
<property category="sys" name="Description" value="" />
<property category="sys" name="DocPath" value="doc" />
<property category="sys" name="ExcludeClassEnabled" value="0" />
<property category="sys" name="JDK" value="java 1.3.0-C" />
<property category="sys" name="LastTag" value="0" />
<property category="sys" name="Libraries" value="" />
<property category="sys" name="MakeStable" value="0" />
<property category="sys" name="OutPath" value="build" />
<property category="sys" name="SourcePath" value="." />
<property category="sys" name="Title" value="" />
<property category="sys" name="Version" value="1.0" />
<property category="sys" name="WorkingDirectory" value="." />
<node type="Package" name="org.postgresql.core" />
<file path="build.xml" />
<file path="CHANGELOG" />
<file path="Implementation" />
<file path="README" />
</project>

View File

@ -10,7 +10,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*; import org.postgresql.util.*;
/** /**
* $Id: Connection.java,v 1.11 2000/12/22 03:08:52 momjian Exp $ * $Id: Connection.java,v 1.12 2001/01/18 14:50:14 peter Exp $
* *
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
* JDBC2 versions of the Connection class. * JDBC2 versions of the Connection class.
@ -20,10 +20,10 @@ public abstract class Connection
{ {
// This is the network stream associated with this connection // This is the network stream associated with this connection
public PG_Stream pg_stream; public PG_Stream pg_stream;
// This is set by org.postgresql.Statement.setMaxRows() // This is set by org.postgresql.Statement.setMaxRows()
public int maxrows = 0; // maximum no. of rows; 0 = unlimited public int maxrows = 0; // maximum no. of rows; 0 = unlimited
private String PG_HOST; private String PG_HOST;
private int PG_PORT; private int PG_PORT;
private String PG_USER; private String PG_USER;
@ -38,17 +38,17 @@ public abstract class Connection
* used. * used.
*/ */
private String encoding; private String encoding;
public boolean CONNECTION_OK = true; public boolean CONNECTION_OK = true;
public boolean CONNECTION_BAD = false; public boolean CONNECTION_BAD = false;
public boolean autoCommit = true; public boolean autoCommit = true;
public boolean readOnly = false; public boolean readOnly = false;
public Driver this_driver; public Driver this_driver;
private String this_url; private String this_url;
private String cursor = null; // The positioned update cursor name private String cursor = null; // The positioned update cursor name
// These are new for v6.3, they determine the current protocol versions // These are new for v6.3, they determine the current protocol versions
// supported by this version of the driver. They are defined in // supported by this version of the driver. They are defined in
// src/include/libpq/pqcomm.h // src/include/libpq/pqcomm.h
@ -59,41 +59,41 @@ public abstract class Connection
private static final int SM_OPTIONS = 64; private static final int SM_OPTIONS = 64;
private static final int SM_UNUSED = 64; private static final int SM_UNUSED = 64;
private static final int SM_TTY = 64; private static final int SM_TTY = 64;
private static final int AUTH_REQ_OK = 0; private static final int AUTH_REQ_OK = 0;
private static final int AUTH_REQ_KRB4 = 1; private static final int AUTH_REQ_KRB4 = 1;
private static final int AUTH_REQ_KRB5 = 2; private static final int AUTH_REQ_KRB5 = 2;
private static final int AUTH_REQ_PASSWORD = 3; private static final int AUTH_REQ_PASSWORD = 3;
private static final int AUTH_REQ_CRYPT = 4; private static final int AUTH_REQ_CRYPT = 4;
// New for 6.3, salt value for crypt authorisation // New for 6.3, salt value for crypt authorisation
private String salt; private String salt;
// This is used by Field to cache oid -> names. // This is used by Field to cache oid -> names.
// It's here, because it's shared across this connection only. // It's here, because it's shared across this connection only.
// Hence it cannot be static within the Field class, because it would then // Hence it cannot be static within the Field class, because it would then
// be across all connections, which could be to different backends. // be across all connections, which could be to different backends.
public Hashtable fieldCache = new Hashtable(); public Hashtable fieldCache = new Hashtable();
// Now handle notices as warnings, so things like "show" now work // Now handle notices as warnings, so things like "show" now work
public SQLWarning firstWarning = null; public SQLWarning firstWarning = null;
// The PID an cancellation key we get from the backend process // The PID an cancellation key we get from the backend process
public int pid; public int pid;
public int ckey; public int ckey;
// This receive_sbuf should be used by the different methods // This receive_sbuf should be used by the different methods
// that call pg_stream.ReceiveString() in this Connection, so // that call pg_stream.ReceiveString() in this Connection, so
// so we avoid uneccesary new allocations. // so we avoid uneccesary new allocations.
byte receive_sbuf[] = new byte[8192]; byte receive_sbuf[] = new byte[8192];
/** /**
* This is called by Class.forName() from within org.postgresql.Driver * This is called by Class.forName() from within org.postgresql.Driver
*/ */
public Connection() public Connection()
{ {
} }
/** /**
* This method actually opens the connection. It is called by Driver. * This method actually opens the connection. It is called by Driver.
* *
@ -115,7 +115,7 @@ public abstract class Connection
throw new PSQLException("postgresql.con.user"); throw new PSQLException("postgresql.con.user");
if(info.getProperty("password")==null) if(info.getProperty("password")==null)
throw new PSQLException("postgresql.con.pass"); throw new PSQLException("postgresql.con.pass");
this_driver = d; this_driver = d;
this_url = url; this_url = url;
PG_DATABASE = database; PG_DATABASE = database;
@ -137,7 +137,7 @@ public abstract class Connection
} catch (IOException e) { } catch (IOException e) {
throw new PSQLException ("postgresql.con.failed",e); throw new PSQLException ("postgresql.con.failed",e);
} }
// Now we need to construct and send a startup packet // Now we need to construct and send a startup packet
try try
{ {
@ -146,13 +146,13 @@ public abstract class Connection
pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2); pg_stream.SendInteger(PG_PROTOCOL_LATEST_MAJOR,2);
pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2); pg_stream.SendInteger(PG_PROTOCOL_LATEST_MINOR,2);
pg_stream.Send(database.getBytes(),SM_DATABASE); pg_stream.Send(database.getBytes(),SM_DATABASE);
// This last send includes the unused fields // This last send includes the unused fields
pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY); pg_stream.Send(PG_USER.getBytes(),SM_USER+SM_OPTIONS+SM_UNUSED+SM_TTY);
// now flush the startup packets to the backend // now flush the startup packets to the backend
pg_stream.flush(); pg_stream.flush();
// Now get the response from the backend, either an error message // Now get the response from the backend, either an error message
// or an authentication request // or an authentication request
int areq = -1; // must have a value here int areq = -1; // must have a value here
@ -169,11 +169,11 @@ public abstract class Connection
// //
throw new SQLException(pg_stream.ReceiveString throw new SQLException(pg_stream.ReceiveString
(receive_sbuf, 4096, getEncoding())); (receive_sbuf, 4096, getEncoding()));
case 'R': case 'R':
// Get the type of request // Get the type of request
areq = pg_stream.ReceiveIntegerR(4); areq = pg_stream.ReceiveIntegerR(4);
// Get the password salt if there is one // Get the password salt if there is one
if(areq == AUTH_REQ_CRYPT) { if(areq == AUTH_REQ_CRYPT) {
byte[] rst = new byte[2]; byte[] rst = new byte[2];
@ -182,21 +182,21 @@ public abstract class Connection
salt = new String(rst,0,2); salt = new String(rst,0,2);
DriverManager.println("Salt="+salt); DriverManager.println("Salt="+salt);
} }
// now send the auth packet // now send the auth packet
switch(areq) switch(areq)
{ {
case AUTH_REQ_OK: case AUTH_REQ_OK:
break; break;
case AUTH_REQ_KRB4: case AUTH_REQ_KRB4:
DriverManager.println("postgresql: KRB4"); DriverManager.println("postgresql: KRB4");
throw new PSQLException("postgresql.con.kerb4"); throw new PSQLException("postgresql.con.kerb4");
case AUTH_REQ_KRB5: case AUTH_REQ_KRB5:
DriverManager.println("postgresql: KRB5"); DriverManager.println("postgresql: KRB5");
throw new PSQLException("postgresql.con.kerb5"); throw new PSQLException("postgresql.con.kerb5");
case AUTH_REQ_PASSWORD: case AUTH_REQ_PASSWORD:
DriverManager.println("postgresql: PASSWORD"); DriverManager.println("postgresql: PASSWORD");
pg_stream.SendInteger(5+PG_PASSWORD.length(),4); pg_stream.SendInteger(5+PG_PASSWORD.length(),4);
@ -204,7 +204,7 @@ public abstract class Connection
pg_stream.SendInteger(0,1); pg_stream.SendInteger(0,1);
pg_stream.flush(); pg_stream.flush();
break; break;
case AUTH_REQ_CRYPT: case AUTH_REQ_CRYPT:
DriverManager.println("postgresql: CRYPT"); DriverManager.println("postgresql: CRYPT");
String crypted = UnixCrypt.crypt(salt,PG_PASSWORD); String crypted = UnixCrypt.crypt(salt,PG_PASSWORD);
@ -213,21 +213,21 @@ public abstract class Connection
pg_stream.SendInteger(0,1); pg_stream.SendInteger(0,1);
pg_stream.flush(); pg_stream.flush();
break; break;
default: default:
throw new PSQLException("postgresql.con.auth",new Integer(areq)); throw new PSQLException("postgresql.con.auth",new Integer(areq));
} }
break; break;
default: default:
throw new PSQLException("postgresql.con.authfail"); throw new PSQLException("postgresql.con.authfail");
} }
} while(areq != AUTH_REQ_OK); } while(areq != AUTH_REQ_OK);
} catch (IOException e) { } catch (IOException e) {
throw new PSQLException("postgresql.con.failed",e); throw new PSQLException("postgresql.con.failed",e);
} }
// As of protocol version 2.0, we should now receive the cancellation key and the pid // As of protocol version 2.0, we should now receive the cancellation key and the pid
int beresp = pg_stream.ReceiveChar(); int beresp = pg_stream.ReceiveChar();
@ -266,7 +266,7 @@ public abstract class Connection
// We also ask the DB for certain properties (i.e. DatabaseEncoding at this time) // We also ask the DB for certain properties (i.e. DatabaseEncoding at this time)
// //
firstWarning = null; firstWarning = null;
java.sql.ResultSet initrset = ExecSQL("set datestyle to 'ISO'; select getdatabaseencoding()"); java.sql.ResultSet initrset = ExecSQL("set datestyle to 'ISO'; select getdatabaseencoding()");
String dbEncoding = null; String dbEncoding = null;
@ -341,19 +341,19 @@ public abstract class Connection
encoding = null; encoding = null;
} }
} }
// Initialise object handling // Initialise object handling
initObjectTypes(); initObjectTypes();
// Mark the connection as ok, and cleanup // Mark the connection as ok, and cleanup
firstWarning = null; firstWarning = null;
PG_STATUS = CONNECTION_OK; PG_STATUS = CONNECTION_OK;
} }
// These methods used to be in the main Connection implementation. As they // These methods used to be in the main Connection implementation. As they
// are common to all implementations (JDBC1 or 2), they are placed here. // are common to all implementations (JDBC1 or 2), they are placed here.
// This should make it easy to maintain the two specifications. // This should make it easy to maintain the two specifications.
/** /**
* This adds a warning to the warning chain. * This adds a warning to the warning chain.
* @param msg message to add * @param msg message to add
@ -361,15 +361,15 @@ public abstract class Connection
public void addWarning(String msg) public void addWarning(String msg)
{ {
DriverManager.println(msg); DriverManager.println(msg);
// Add the warning to the chain // Add the warning to the chain
if(firstWarning!=null) if(firstWarning!=null)
firstWarning.setNextWarning(new SQLWarning(msg)); firstWarning.setNextWarning(new SQLWarning(msg));
else else
firstWarning = new SQLWarning(msg); firstWarning = new SQLWarning(msg);
// Now check for some specific messages // Now check for some specific messages
// This is obsolete in 6.5, but I've left it in here so if we need to use this // This is obsolete in 6.5, but I've left it in here so if we need to use this
// technique again, we'll know where to place it. // technique again, we'll know where to place it.
// //
@ -377,13 +377,13 @@ public abstract class Connection
//if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) { //if(msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) {
//// 13 is the length off "DateStyle is " //// 13 is the length off "DateStyle is "
//msg = msg.substring(msg.indexOf("DateStyle is ")+13); //msg = msg.substring(msg.indexOf("DateStyle is ")+13);
// //
//for(int i=0;i<dateStyles.length;i+=2) //for(int i=0;i<dateStyles.length;i+=2)
//if(msg.startsWith(dateStyles[i])) //if(msg.startsWith(dateStyles[i]))
//currentDateStyle=i+1; // this is the index of the format //currentDateStyle=i+1; // this is the index of the format
//} //}
} }
/** /**
* Send a query to the backend. Returns one of the ResultSet * Send a query to the backend. Returns one of the ResultSet
* objects. * objects.
@ -404,8 +404,10 @@ public abstract class Connection
// This will let the driver reuse byte arrays that has already // This will let the driver reuse byte arrays that has already
// been allocated instead of allocating new ones in order // been allocated instead of allocating new ones in order
// to gain performance improvements. // to gain performance improvements.
pg_stream.deallocate(); // PM 17/01/01: Commented out due to race bug. See comments in
// PG_Stream
//pg_stream.deallocate();
Field[] fields = null; Field[] fields = null;
Vector tuples = new Vector(); Vector tuples = new Vector();
byte[] buf = null; byte[] buf = null;
@ -415,7 +417,7 @@ public abstract class Connection
int update_count = 1; int update_count = 1;
int insert_oid = 0; int insert_oid = 0;
SQLException final_error = null; SQLException final_error = null;
// Commented out as the backend can now handle queries // Commented out as the backend can now handle queries
// larger than 8K. Peter June 6 2000 // larger than 8K. Peter June 6 2000
//if (sql.length() > 8192) //if (sql.length() > 8192)
@ -441,13 +443,13 @@ public abstract class Connection
} catch (IOException e) { } catch (IOException e) {
throw new PSQLException("postgresql.con.ioerror",e); throw new PSQLException("postgresql.con.ioerror",e);
} }
while (!hfr || fqp > 0) while (!hfr || fqp > 0)
{ {
Object tup=null; // holds rows as they are recieved Object tup=null; // holds rows as they are recieved
int c = pg_stream.ReceiveChar(); int c = pg_stream.ReceiveChar();
switch (c) switch (c)
{ {
case 'A': // Asynchronous Notify case 'A': // Asynchronous Notify
@ -464,7 +466,7 @@ public abstract class Connection
break; break;
case 'C': // Command Status case 'C': // Command Status
recv_status = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); recv_status = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding());
// Now handle the update count correctly. // Now handle the update count correctly.
if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE")) { if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE")) {
try { try {
@ -511,7 +513,7 @@ public abstract class Connection
break; break;
case 'I': // Empty Query case 'I': // Empty Query
int t = pg_stream.ReceiveChar(); int t = pg_stream.ReceiveChar();
if (t != 0) if (t != 0)
throw new PSQLException("postgresql.con.garbled"); throw new PSQLException("postgresql.con.garbled");
if (fqp > 0) if (fqp > 0)
@ -538,7 +540,7 @@ public abstract class Connection
} }
if (final_error != null) if (final_error != null)
throw final_error; throw final_error;
return getResultSet(this, fields, tuples, recv_status, update_count, insert_oid); return getResultSet(this, fields, tuples, recv_status, update_count, insert_oid);
} }
} }
@ -553,7 +555,7 @@ public abstract class Connection
{ {
int nf = pg_stream.ReceiveIntegerR(2), i; int nf = pg_stream.ReceiveIntegerR(2), i;
Field[] fields = new Field[nf]; Field[] fields = new Field[nf];
for (i = 0 ; i < nf ; ++i) for (i = 0 ; i < nf ; ++i)
{ {
String typname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); String typname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding());
@ -564,7 +566,7 @@ public abstract class Connection
} }
return fields; return fields;
} }
/** /**
* In SQL, a result table can be retrieved through a cursor that * In SQL, a result table can be retrieved through a cursor that
* is named. The current row of a result can be updated or deleted * is named. The current row of a result can be updated or deleted
@ -582,7 +584,7 @@ public abstract class Connection
{ {
this.cursor = cursor; this.cursor = cursor;
} }
/** /**
* getCursorName gets the cursor name. * getCursorName gets the cursor name.
* *
@ -593,7 +595,7 @@ public abstract class Connection
{ {
return cursor; return cursor;
} }
/** /**
* We are required to bring back certain information by * We are required to bring back certain information by
* the DatabaseMetaData class. These functions do that. * the DatabaseMetaData class. These functions do that.
@ -607,7 +609,7 @@ public abstract class Connection
{ {
return this_url; return this_url;
} }
/** /**
* Method getUserName() brings back the User Name (again, we * Method getUserName() brings back the User Name (again, we
* saved it) * saved it)
@ -622,13 +624,13 @@ public abstract class Connection
/** /**
* Get the character encoding to use for this connection. * Get the character encoding to use for this connection.
* @return the encoding to use, or <b>null</b> for the * @return the encoding to use, or <b>null</b> for the
* default encoding. * default encoding.
*/ */
public String getEncoding() throws SQLException { public String getEncoding() throws SQLException {
return encoding; return encoding;
} }
/** /**
* This returns the Fastpath API for the current connection. * This returns the Fastpath API for the current connection.
* *
@ -657,10 +659,10 @@ public abstract class Connection
fastpath = new Fastpath(this,pg_stream); fastpath = new Fastpath(this,pg_stream);
return fastpath; return fastpath;
} }
// This holds a reference to the Fastpath API if already open // This holds a reference to the Fastpath API if already open
private Fastpath fastpath = null; private Fastpath fastpath = null;
/** /**
* This returns the LargeObject API for the current connection. * This returns the LargeObject API for the current connection.
* *
@ -686,10 +688,10 @@ public abstract class Connection
largeobject = new LargeObjectManager(this); largeobject = new LargeObjectManager(this);
return largeobject; return largeobject;
} }
// This holds a reference to the LargeObject API if already open // This holds a reference to the LargeObject API if already open
private LargeObjectManager largeobject = null; private LargeObjectManager largeobject = null;
/** /**
* This method is used internally to return an object based around * This method is used internally to return an object based around
* org.postgresql's more unique data types. * org.postgresql's more unique data types.
@ -713,7 +715,7 @@ public abstract class Connection
{ {
try { try {
Object o = objectTypes.get(type); Object o = objectTypes.get(type);
// If o is null, then the type is unknown, so check to see if type // If o is null, then the type is unknown, so check to see if type
// is an actual table name. If it does, see if a Class is known that // is an actual table name. If it does, see if a Class is known that
// can handle it // can handle it
@ -722,7 +724,7 @@ public abstract class Connection
objectTypes.put(type,ser); objectTypes.put(type,ser);
return ser.fetch(Integer.parseInt(value)); return ser.fetch(Integer.parseInt(value));
} }
// If o is not null, and it is a String, then its a class name that // If o is not null, and it is a String, then its a class name that
// extends PGobject. // extends PGobject.
// //
@ -748,11 +750,11 @@ public abstract class Connection
} catch(Exception ex) { } catch(Exception ex) {
throw new PSQLException("postgresql.con.creobj",type,ex); throw new PSQLException("postgresql.con.creobj",type,ex);
} }
// should never be reached // should never be reached
return null; return null;
} }
/** /**
* This stores an object into the database. * This stores an object into the database.
* @param o Object to store * @param o Object to store
@ -765,7 +767,7 @@ public abstract class Connection
try { try {
String type = o.getClass().getName(); String type = o.getClass().getName();
Object x = objectTypes.get(type); Object x = objectTypes.get(type);
// If x is null, then the type is unknown, so check to see if type // If x is null, then the type is unknown, so check to see if type
// is an actual table name. If it does, see if a Class is known that // is an actual table name. If it does, see if a Class is known that
// can handle it // can handle it
@ -774,15 +776,15 @@ public abstract class Connection
objectTypes.put(type,ser); objectTypes.put(type,ser);
return ser.store(o); return ser.store(o);
} }
// If it's an object, it should be an instance of our Serialize class // If it's an object, it should be an instance of our Serialize class
// If so, then call it's fetch method. // If so, then call it's fetch method.
if(x instanceof Serialize) if(x instanceof Serialize)
return ((Serialize)x).store(o); return ((Serialize)x).store(o);
// Thow an exception because the type is unknown // Thow an exception because the type is unknown
throw new PSQLException("postgresql.con.strobj"); throw new PSQLException("postgresql.con.strobj");
} catch(SQLException sx) { } catch(SQLException sx) {
// rethrow the exception. Done because we capture any others next // rethrow the exception. Done because we capture any others next
sx.fillInStackTrace(); sx.fillInStackTrace();
@ -791,7 +793,7 @@ public abstract class Connection
throw new PSQLException("postgresql.con.strobjex",ex); throw new PSQLException("postgresql.con.strobjex",ex);
} }
} }
/** /**
* This allows client code to add a handler for one of org.postgresql's * This allows client code to add a handler for one of org.postgresql's
* more unique data types. * more unique data types.
@ -816,10 +818,10 @@ public abstract class Connection
{ {
objectTypes.put(type,name); objectTypes.put(type,name);
} }
// This holds the available types // This holds the available types
private Hashtable objectTypes = new Hashtable(); private Hashtable objectTypes = new Hashtable();
// This array contains the types that are supported as standard. // This array contains the types that are supported as standard.
// //
// The first entry is the types name on the database, the second // The first entry is the types name on the database, the second
@ -835,25 +837,25 @@ public abstract class Connection
{"polygon", "org.postgresql.geometric.PGpolygon"}, {"polygon", "org.postgresql.geometric.PGpolygon"},
{"money", "org.postgresql.util.PGmoney"} {"money", "org.postgresql.util.PGmoney"}
}; };
// This initialises the objectTypes hashtable // This initialises the objectTypes hashtable
private void initObjectTypes() private void initObjectTypes()
{ {
for(int i=0;i<defaultObjectTypes.length;i++) for(int i=0;i<defaultObjectTypes.length;i++)
objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]); objectTypes.put(defaultObjectTypes[i][0],defaultObjectTypes[i][1]);
} }
// These are required by other common classes // These are required by other common classes
public abstract java.sql.Statement createStatement() throws SQLException; public abstract java.sql.Statement createStatement() throws SQLException;
/** /**
* This returns a resultset. It must be overridden, so that the correct * This returns a resultset. It must be overridden, so that the correct
* version (from jdbc1 or jdbc2) are returned. * version (from jdbc1 or jdbc2) are returned.
*/ */
protected abstract java.sql.ResultSet getResultSet(org.postgresql.Connection conn, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException; protected abstract java.sql.ResultSet getResultSet(org.postgresql.Connection conn, Field[] fields, Vector tuples, String status, int updateCount,int insertOID) throws SQLException;
public abstract void close() throws SQLException; public abstract void close() throws SQLException;
/** /**
* Overides finalize(). If called, it closes the connection. * Overides finalize(). If called, it closes the connection.
* *
@ -866,12 +868,33 @@ public abstract class Connection
{ {
close(); close();
} }
/** /**
* This is an attempt to implement SQL Escape clauses * This is an attempt to implement SQL Escape clauses
*/ */
public String EscapeSQL(String sql) { public String EscapeSQL(String sql) {
return sql; //if (DEBUG) { System.out.println ("parseSQLEscapes called"); }
// If we find a "{d", assume we have a date escape.
//
// Since the date escape syntax is very close to the
// native Postgres date format, we just remove the escape
// delimiters.
//
// This implementation could use some optimization, but it has
// worked in practice for two years of solid use.
int index = sql.indexOf("{d");
while (index != -1) {
//System.out.println ("escape found at index: " + index);
StringBuffer buf = new StringBuffer(sql);
buf.setCharAt(index, ' ');
buf.setCharAt(index + 1, ' ');
buf.setCharAt(sql.indexOf('}', index), ' ');
sql = new String(buf);
index = sql.indexOf("{d");
}
//System.out.println ("modified SQL: " + sql);
return sql;
} }
} }

View File

@ -6,6 +6,7 @@ import java.net.*;
import java.util.*; import java.util.*;
import java.sql.*; import java.sql.*;
import org.postgresql.*; import org.postgresql.*;
import org.postgresql.core.*;
import org.postgresql.util.*; import org.postgresql.util.*;
/** /**
@ -22,10 +23,10 @@ public class PG_Stream
private Socket connection; private Socket connection;
private InputStream pg_input; private InputStream pg_input;
private BufferedOutputStream pg_output; private BufferedOutputStream pg_output;
BytePoolDim1 bytePoolDim1 = new BytePoolDim1(); BytePoolDim1 bytePoolDim1 = new BytePoolDim1();
BytePoolDim2 bytePoolDim2 = new BytePoolDim2(); BytePoolDim2 bytePoolDim2 = new BytePoolDim2();
/** /**
* Constructor: Connect to the PostgreSQL back end and return * Constructor: Connect to the PostgreSQL back end and return
* a stream connection. * a stream connection.
@ -37,16 +38,16 @@ public class PG_Stream
public PG_Stream(String host, int port) throws IOException public PG_Stream(String host, int port) throws IOException
{ {
connection = new Socket(host, port); connection = new Socket(host, port);
// Submitted by Jason Venner <jason@idiom.com> adds a 10x speed // Submitted by Jason Venner <jason@idiom.com> adds a 10x speed
// improvement on FreeBSD machines (caused by a bug in their TCP Stack) // improvement on FreeBSD machines (caused by a bug in their TCP Stack)
connection.setTcpNoDelay(true); connection.setTcpNoDelay(true);
// Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no> // Buffer sizes submitted by Sverre H Huseby <sverrehu@online.no>
pg_input = new BufferedInputStream(connection.getInputStream(), 8192); pg_input = new BufferedInputStream(connection.getInputStream(), 8192);
pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192); pg_output = new BufferedOutputStream(connection.getOutputStream(), 8192);
} }
/** /**
* Sends a single character to the back end * Sends a single character to the back end
* *
@ -59,11 +60,11 @@ public class PG_Stream
//byte b[] = new byte[1]; //byte b[] = new byte[1];
//b[0] = (byte)val; //b[0] = (byte)val;
//pg_output.write(b); //pg_output.write(b);
// Optimised version by Sverre H. Huseby Aug 22 1999 Applied Sep 13 1999 // Optimised version by Sverre H. Huseby Aug 22 1999 Applied Sep 13 1999
pg_output.write((byte)val); pg_output.write((byte)val);
} }
/** /**
* Sends an integer to the back end * Sends an integer to the back end
* *
@ -74,7 +75,7 @@ public class PG_Stream
public void SendInteger(int val, int siz) throws IOException public void SendInteger(int val, int siz) throws IOException
{ {
byte[] buf = bytePoolDim1.allocByte(siz); byte[] buf = bytePoolDim1.allocByte(siz);
while (siz-- > 0) while (siz-- > 0)
{ {
buf[siz] = (byte)(val & 0xff); buf[siz] = (byte)(val & 0xff);
@ -82,7 +83,7 @@ public class PG_Stream
} }
Send(buf); Send(buf);
} }
/** /**
* Sends an integer to the back end in reverse order. * Sends an integer to the back end in reverse order.
* *
@ -106,7 +107,7 @@ public class PG_Stream
} }
Send(buf); Send(buf);
} }
/** /**
* Send an array of bytes to the backend * Send an array of bytes to the backend
* *
@ -117,7 +118,7 @@ public class PG_Stream
{ {
pg_output.write(buf); pg_output.write(buf);
} }
/** /**
* Send an exact array of bytes to the backend - if the length * Send an exact array of bytes to the backend - if the length
* has not been reached, send nulls until it has. * has not been reached, send nulls until it has.
@ -130,7 +131,7 @@ public class PG_Stream
{ {
Send(buf,0,siz); Send(buf,0,siz);
} }
/** /**
* Send an exact array of bytes to the backend - if the length * Send an exact array of bytes to the backend - if the length
* has not been reached, send nulls until it has. * has not been reached, send nulls until it has.
@ -143,7 +144,7 @@ public class PG_Stream
public void Send(byte buf[], int off, int siz) throws IOException public void Send(byte buf[], int off, int siz) throws IOException
{ {
int i; int i;
pg_output.write(buf, off, ((buf.length-off) < siz ? (buf.length-off) : siz)); pg_output.write(buf, off, ((buf.length-off) < siz ? (buf.length-off) : siz));
if((buf.length-off) < siz) if((buf.length-off) < siz)
{ {
@ -153,7 +154,7 @@ public class PG_Stream
} }
} }
} }
/** /**
* Sends a packet, prefixed with the packet's length * Sends a packet, prefixed with the packet's length
* @param buf buffer to send * @param buf buffer to send
@ -164,7 +165,7 @@ public class PG_Stream
SendInteger(buf.length+4,4); SendInteger(buf.length+4,4);
Send(buf); Send(buf);
} }
/** /**
* Receives a single character from the backend * Receives a single character from the backend
* *
@ -174,7 +175,7 @@ public class PG_Stream
public int ReceiveChar() throws SQLException public int ReceiveChar() throws SQLException
{ {
int c = 0; int c = 0;
try try
{ {
c = pg_input.read(); c = pg_input.read();
@ -184,7 +185,7 @@ public class PG_Stream
} }
return c; return c;
} }
/** /**
* Receives an integer from the backend * Receives an integer from the backend
* *
@ -195,13 +196,13 @@ public class PG_Stream
public int ReceiveInteger(int siz) throws SQLException public int ReceiveInteger(int siz) throws SQLException
{ {
int n = 0; int n = 0;
try try
{ {
for (int i = 0 ; i < siz ; i++) for (int i = 0 ; i < siz ; i++)
{ {
int b = pg_input.read(); int b = pg_input.read();
if (b < 0) if (b < 0)
throw new PSQLException("postgresql.stream.eof"); throw new PSQLException("postgresql.stream.eof");
n = n | (b << (8 * i)) ; n = n | (b << (8 * i)) ;
@ -211,7 +212,7 @@ public class PG_Stream
} }
return n; return n;
} }
/** /**
* Receives an integer from the backend * Receives an integer from the backend
* *
@ -222,13 +223,13 @@ public class PG_Stream
public int ReceiveIntegerR(int siz) throws SQLException public int ReceiveIntegerR(int siz) throws SQLException
{ {
int n = 0; int n = 0;
try try
{ {
for (int i = 0 ; i < siz ; i++) for (int i = 0 ; i < siz ; i++)
{ {
int b = pg_input.read(); int b = pg_input.read();
if (b < 0) if (b < 0)
throw new PSQLException("postgresql.stream.eof"); throw new PSQLException("postgresql.stream.eof");
n = b | (n << 8); n = b | (n << 8);
@ -270,24 +271,24 @@ public class PG_Stream
byte[] rst = bytePoolDim1.allocByte(maxsiz); byte[] rst = bytePoolDim1.allocByte(maxsiz);
return ReceiveString(rst, maxsiz, encoding); return ReceiveString(rst, maxsiz, encoding);
} }
/** /**
* Receives a null-terminated string from the backend. Maximum of * Receives a null-terminated string from the backend. Maximum of
* maxsiz bytes - if we don't see a null, then we assume something * maxsiz bytes - if we don't see a null, then we assume something
* has gone wrong. * has gone wrong.
* *
* @param rst byte array to read the String into. rst.length must * @param rst byte array to read the String into. rst.length must
* equal to or greater than maxsize. * equal to or greater than maxsize.
* @param maxsiz maximum length of string in bytes * @param maxsiz maximum length of string in bytes
* @param encoding the charset encoding to use. * @param encoding the charset encoding to use.
* @return string from back end * @return string from back end
* @exception SQLException if an I/O error occurs * @exception SQLException if an I/O error occurs
*/ */
public String ReceiveString(byte rst[], int maxsiz, String encoding) public String ReceiveString(byte rst[], int maxsiz, String encoding)
throws SQLException throws SQLException
{ {
int s = 0; int s = 0;
try try
{ {
while (s < maxsiz) while (s < maxsiz)
@ -318,7 +319,7 @@ public class PG_Stream
} }
return v; return v;
} }
/** /**
* Read a tuple from the back end. A tuple is a two dimensional * Read a tuple from the back end. A tuple is a two dimensional
* array of bytes * array of bytes
@ -334,10 +335,10 @@ public class PG_Stream
int i, bim = (nf + 7)/8; int i, bim = (nf + 7)/8;
byte[] bitmask = Receive(bim); byte[] bitmask = Receive(bim);
byte[][] answer = bytePoolDim2.allocByte(nf); byte[][] answer = bytePoolDim2.allocByte(nf);
int whichbit = 0x80; int whichbit = 0x80;
int whichbyte = 0; int whichbyte = 0;
for (i = 0 ; i < nf ; ++i) for (i = 0 ; i < nf ; ++i)
{ {
boolean isNull = ((bitmask[whichbyte] & whichbit) == 0); boolean isNull = ((bitmask[whichbyte] & whichbit) == 0);
@ -347,21 +348,21 @@ public class PG_Stream
++whichbyte; ++whichbyte;
whichbit = 0x80; whichbit = 0x80;
} }
if (isNull) if (isNull)
answer[i] = null; answer[i] = null;
else else
{ {
int len = ReceiveIntegerR(4); int len = ReceiveIntegerR(4);
if (!bin) if (!bin)
len -= 4; len -= 4;
if (len < 0) if (len < 0)
len = 0; len = 0;
answer[i] = Receive(len); answer[i] = Receive(len);
} }
} }
return answer; return answer;
} }
/** /**
* Reads in a given number of bytes from the backend * Reads in a given number of bytes from the backend
* *
@ -375,7 +376,7 @@ public class PG_Stream
Receive(answer,0,siz); Receive(answer,0,siz);
return answer; return answer;
} }
/** /**
* Reads in a given number of bytes from the backend * Reads in a given number of bytes from the backend
* *
@ -387,8 +388,8 @@ public class PG_Stream
public void Receive(byte[] b,int off,int siz) throws SQLException public void Receive(byte[] b,int off,int siz) throws SQLException
{ {
int s = 0; int s = 0;
try try
{ {
while (s < siz) while (s < siz)
{ {
@ -401,7 +402,7 @@ public class PG_Stream
throw new PSQLException("postgresql.stream.ioerror",e); throw new PSQLException("postgresql.stream.ioerror",e);
} }
} }
/** /**
* This flushes any pending output to the backend. It is used primarily * This flushes any pending output to the backend. It is used primarily
* by the Fastpath code. * by the Fastpath code.
@ -415,7 +416,7 @@ public class PG_Stream
throw new PSQLException("postgresql.stream.flush",e); throw new PSQLException("postgresql.stream.flush",e);
} }
} }
/** /**
* Closes the connection * Closes the connection
* *
@ -430,151 +431,5 @@ public class PG_Stream
connection.close(); connection.close();
} }
/**
* Deallocate all resources that has been associated with any previous
* query.
*/
public void deallocate(){
bytePoolDim1.deallocate();
bytePoolDim2.deallocate();
}
}
/**
* A simple and fast object pool implementation that can pool objects
* of any type. This implementation is not thread safe, it is up to the users
* of this class to assure thread safety.
*/
class ObjectPool {
int cursize = 0;
int maxsize = 16;
Object arr[] = new Object[maxsize];
public void add(Object o){
if(cursize >= maxsize){
Object newarr[] = new Object[maxsize*2];
System.arraycopy(arr, 0, newarr, 0, maxsize);
maxsize = maxsize * 2;
arr = newarr;
}
arr[cursize++] = o;
}
public Object remove(){
return arr[--cursize];
}
public boolean isEmpty(){
return cursize == 0;
}
public int size(){
return cursize;
}
public void addAll(ObjectPool pool){
int srcsize = pool.size();
if(srcsize == 0)
return;
int totalsize = srcsize + cursize;
if(totalsize > maxsize){
Object newarr[] = new Object[totalsize*2];
System.arraycopy(arr, 0, newarr, 0, cursize);
maxsize = maxsize = totalsize * 2;
arr = newarr;
}
System.arraycopy(pool.arr, 0, arr, cursize, srcsize);
cursize = totalsize;
}
public void clear(){
cursize = 0;
}
}
/**
* A simple and efficient class to pool one dimensional byte arrays
* of different sizes.
*/
class BytePoolDim1 {
int maxsize = 256;
ObjectPool notusemap[] = new ObjectPool[maxsize];
ObjectPool inusemap[] = new ObjectPool[maxsize];
byte binit[][] = new byte[maxsize][0];
public BytePoolDim1(){
for(int i = 0; i < maxsize; i++){
binit[i] = new byte[i];
inusemap[i] = new ObjectPool();
notusemap[i] = new ObjectPool();
}
}
public byte[] allocByte(int size){
if(size > maxsize){
return new byte[size];
}
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[] = null;
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[]) o;
} else
b = new byte[size];
in_usel.add(b);
return b;
}
public void deallocate(){
for(int i = 0; i < maxsize; i++){
notusemap[i].addAll(inusemap[i]);
inusemap[i].clear();
}
}
}
/**
* A simple and efficient class to pool two dimensional byte arrays
* of different sizes.
*/
class BytePoolDim2 {
int maxsize = 32;
ObjectPool notusemap[] = new ObjectPool[maxsize];
ObjectPool inusemap[] = new ObjectPool[maxsize];
public BytePoolDim2(){
for(int i = 0; i < maxsize; i++){
inusemap[i] = new ObjectPool();
notusemap[i] = new ObjectPool();
}
}
public byte[][] allocByte(int size){
if(size > maxsize){
return new byte[size][0];
}
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[][] = null;
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[][]) o;
} else
b = new byte[size][0];
in_usel.add(b);
return b;
}
public void deallocate(){
for(int i = 0; i < maxsize; i++){
notusemap[i].addAll(inusemap[i]);
inusemap[i].clear();
}
}
} }

View File

@ -0,0 +1,95 @@
package org.postgresql.core;
/**
* A simple and efficient class to pool one dimensional byte arrays
* of different sizes.
*/
public class BytePoolDim1 {
/**
* The maximum size of the array we manage.
*/
int maxsize = 256;
/**
* The pools not currently in use
*/
ObjectPool notusemap[] = new ObjectPool[maxsize+1];
/**
* The pools currently in use
*/
ObjectPool inusemap[] = new ObjectPool[maxsize+1];
/**
*
*/
byte binit[][] = new byte[maxsize][0];
/**
* Construct a new pool
*/
public BytePoolDim1(){
for(int i = 0; i <= maxsize; i++){
binit[i] = new byte[i];
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
}
}
/**
* Allocate a byte[] of a specified size and put it in the pool. If it's
* larger than maxsize then it is not pooled.
* @return the byte[] allocated
*/
public byte[] allocByte(int size) {
// for now until the bug can be removed
return new byte[size];
/*
// Don't pool if >maxsize
if(size > maxsize){
return new byte[size];
}
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[] = null;
// Fetch from the unused pool if available otherwise allocate a new
// now array
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[]) o;
} else
b = new byte[size];
in_usel.add(b);
return b;
*/
}
/**
* Release an array
* @param b byte[] to release
*/
public void release(byte[] b) {
// If it's larger than maxsize then we don't touch it
if(b.length>maxsize)
return;
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
in_usel.remove(b);
not_usel.add(b);
}
/**
* Deallocate all
* @deprecated Real bad things happen if this is called!
*/
public void deallocate() {
//for(int i = 0; i <= maxsize; i++){
// notusemap[i].addAll(inusemap[i]);
// inusemap[i].clear();
//}
}
}

View File

@ -0,0 +1,62 @@
package org.postgresql.core;
public class BytePoolDim2 {
int maxsize = 32;
ObjectPool notusemap[] = new ObjectPool[maxsize+1];
ObjectPool inusemap[] = new ObjectPool[maxsize+1];
public BytePoolDim2(){
for(int i = 0; i <= maxsize; i++){
inusemap[i] = new SimpleObjectPool();
notusemap[i] = new SimpleObjectPool();
}
}
public byte[][] allocByte(int size){
// For now until the bug can be removed
return new byte[size][0];
/*
if(size > maxsize){
return new byte[size][0];
}
ObjectPool not_usel = notusemap[size];
ObjectPool in_usel = inusemap[size];
byte b[][] = null;
if(!not_usel.isEmpty()) {
Object o = not_usel.remove();
b = (byte[][]) o;
} else
b = new byte[size][0];
in_usel.add(b);
return b;
*/
}
public void release(byte[][] b){
if(b.length > maxsize){
return;
}
ObjectPool not_usel = notusemap[b.length];
ObjectPool in_usel = inusemap[b.length];
in_usel.remove(b);
not_usel.add(b);
}
/**
* Deallocate the object cache.
* PM 17/01/01: Commented out this code as it blows away any hope of
* multiple queries on the same connection. I'll redesign the allocation
* code to use some form of Statement context, so the buffers are per
* Statement and not per Connection/PG_Stream as it is now.
*/
public void deallocate(){
//for(int i = 0; i <= maxsize; i++){
// notusemap[i].addAll(inusemap[i]);
// inusemap[i].clear();
//}
}
}

View File

@ -0,0 +1,18 @@
package org.postgresql.core;
/**
* This interface defines the methods to access the memory pool classes.
*/
public interface MemoryPool {
/**
* Allocate an array from the pool
* @return byte[] allocated
*/
public byte[] allocByte(int size);
/**
* Frees an object back to the pool
* @param o Object to release
*/
public void release(Object o);
}

View File

@ -0,0 +1,48 @@
package org.postgresql.core;
/**
* This interface defines methods needed to implement a simple object pool.
* There are two known classes that implement this, one for jdk1.1 and the
* other for jdk1.2+
*/
public interface ObjectPool {
/**
* Adds an object to the pool
* @param o Object to add
*/
public void add(Object o);
/**
* Removes an object from the pool
* @param o Object to remove
*/
public void remove(Object o);
/**
* Removes the top object from the pool
* @return Object from the top.
*/
public Object remove();
/**
* @return true if the pool is empty
*/
public boolean isEmpty();
/**
* @return the number of objects in the pool
*/
public int size();
/**
* Adds all objects in one pool to this one
* @param pool The pool to take the objects from
*/
public void addAll(ObjectPool pool);
/**
* Clears the pool of all objects
*/
public void clear();
}

View File

@ -0,0 +1,97 @@
package org.postgresql.core;
/**
* A simple and fast object pool implementation that can pool objects
* of any type. This implementation is not thread safe, it is up to the users
* of this class to assure thread safety.
*/
public class SimpleObjectPool implements ObjectPool
{
// This was originally in PG_Stream but moved out to fix the major problem
// where more than one query (usually all the time) overwrote the results
// of another query.
int cursize = 0;
int maxsize = 16;
Object arr[] = new Object[maxsize];
/**
* Adds an object to the pool
* @param o Object to add
*/
public void add(Object o)
{
if(cursize >= maxsize){
Object newarr[] = new Object[maxsize*2];
System.arraycopy(arr, 0, newarr, 0, maxsize);
maxsize = maxsize * 2;
arr = newarr;
}
arr[cursize++] = o;
}
/**
* Removes the top object from the pool
* @return Object from the top.
*/
public Object remove(){
return arr[--cursize];
}
/**
* Removes the given object from the pool
* @param o Object to remove
*/
public void remove(Object o) {
int p=0;
while(p<cursize && !arr[p].equals(o))
p++;
if(arr[p].equals(o)) {
// This should be ok as there should be no overlap conflict
System.arraycopy(arr,p+1,arr,p,cursize-p);
cursize--;
}
}
/**
* @return true if the pool is empty
*/
public boolean isEmpty(){
return cursize == 0;
}
/**
* @return the number of objects in the pool
*/
public int size(){
return cursize;
}
/**
* Adds all objects in one pool to this one
* @param pool The pool to take the objects from
*/
public void addAll(ObjectPool p){
SimpleObjectPool pool = (SimpleObjectPool)p;
int srcsize = pool.size();
if(srcsize == 0)
return;
int totalsize = srcsize + cursize;
if(totalsize > maxsize){
Object newarr[] = new Object[totalsize*2];
System.arraycopy(arr, 0, newarr, 0, cursize);
maxsize = maxsize = totalsize * 2;
arr = newarr;
}
System.arraycopy(pool.arr, 0, arr, cursize, srcsize);
cursize = totalsize;
}
/**
* Clears the pool of all objects
*/
public void clear(){
cursize = 0;
}
}

View File

@ -35,6 +35,8 @@ postgresql.geo.point:Conversion of point failed - {0}
postgresql.jvm.version:The postgresql.jar file does not contain the correct JDBC classes for this JVM. Try rebuilding. If that fails, try forcing the version supplying it to the command line using the argument -Djava.version=1.1 or -Djava.version=1.2\nException thrown was {0} postgresql.jvm.version:The postgresql.jar file does not contain the correct JDBC classes for this JVM. Try rebuilding. If that fails, try forcing the version supplying it to the command line using the argument -Djava.version=1.1 or -Djava.version=1.2\nException thrown was {0}
postgresql.lo.init:failed to initialise LargeObject API postgresql.lo.init:failed to initialise LargeObject API
postgresql.money:conversion of money failed - {0}. postgresql.money:conversion of money failed - {0}.
postgresql.noupdate:This ResultSet is not updateable
postgresql.psqlnotimp:The backend currently does not support this feature.
postgresql.prep.is:InputStream as parameter not supported postgresql.prep.is:InputStream as parameter not supported
postgresql.prep.param:No value specified for parameter {0}. postgresql.prep.param:No value specified for parameter {0}.
postgresql.prep.range:Parameter index out of range. postgresql.prep.range:Parameter index out of range.

View File

@ -13,7 +13,7 @@ import org.postgresql.util.PSQLException;
* A Statement object is used for executing a static SQL statement and * A Statement object is used for executing a static SQL statement and
* obtaining the results produced by it. * obtaining the results produced by it.
* *
* <p>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 * Therefore, if the reading of one ResultSet is interleaved with the
* reading of another, each must have been generated by different * reading of another, each must have been generated by different
* Statements. All statement execute methods implicitly close a * Statements. All statement execute methods implicitly close a
@ -29,7 +29,7 @@ public class Statement implements java.sql.Statement
SQLWarning warnings = null; // The warnings chain. SQLWarning warnings = null; // The warnings chain.
int timeout = 0; // The timeout for a query (not used) int timeout = 0; // The timeout for a query (not used)
boolean escapeProcessing = true;// escape processing flag boolean escapeProcessing = true;// escape processing flag
/** /**
* Constructor for a Statement. It simply sets the connection * Constructor for a Statement. It simply sets the connection
* that created us. * that created us.
@ -81,8 +81,8 @@ public class Statement implements java.sql.Statement
* for this to happen when it is automatically closed. The * for this to happen when it is automatically closed. The
* close method provides this immediate release. * close method provides this immediate release.
* *
* <p><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 * garbage collected. When a Statement is closed, its current
* ResultSet, if one exists, is also closed. * ResultSet, if one exists, is also closed.
* *
* @exception SQLException if a database access error occurs (why?) * @exception SQLException if a database access error occurs (why?)
@ -146,7 +146,7 @@ public class Statement implements java.sql.Statement
/** /**
* If escape scanning is on (the default), the driver will do escape * If escape scanning is on (the default), the driver will do escape
* substitution before sending the SQL to the database. * substitution before sending the SQL to the database.
* *
* @param enable true to enable; false to disable * @param enable true to enable; false to disable
* @exception SQLException if a database access error occurs * @exception SQLException if a database access error occurs
@ -183,7 +183,7 @@ public class Statement implements java.sql.Statement
/** /**
* Cancel can be used by one thread to cancel a statement that * Cancel can be used by one thread to cancel a statement that
* is being executed by another thread. However, PostgreSQL is * is being executed by another thread. However, PostgreSQL is
* a sync. sort of thing, so this really has no meaning - we * a sync. sort of thing, so this really has no meaning - we
* define it as a no-op (i.e. you can't cancel, but there is no * define it as a no-op (i.e. you can't cancel, but there is no
* error if you try.) * error if you try.)
* *
@ -256,7 +256,7 @@ public class Statement implements java.sql.Statement
/** /**
* Execute a SQL statement that may return multiple results. We * Execute a SQL statement that may return multiple results. We
* don't have to worry about this since we do not support multiple * don't have to worry about this since we do not support multiple
* ResultSets. You can use getResultSet or getUpdateCount to * ResultSets. You can use getResultSet or getUpdateCount to
* retrieve the result. * retrieve the result.
* *
* @param sql any SQL statement * @param sql any SQL statement
@ -266,8 +266,10 @@ public class Statement implements java.sql.Statement
*/ */
public boolean execute(String sql) throws SQLException public boolean execute(String sql) throws SQLException
{ {
result = connection.ExecSQL(sql); if(escapeProcessing)
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet()); sql=connection.EscapeSQL(sql);
result = connection.ExecSQL(sql);
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
} }
/** /**
@ -309,7 +311,7 @@ public class Statement implements java.sql.Statement
result = ((org.postgresql.ResultSet)result).getNext(); result = ((org.postgresql.ResultSet)result).getNext();
return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet()); return (result != null && ((org.postgresql.ResultSet)result).reallyResultSet());
} }
/** /**
* Returns the status message from the current Result.<p> * Returns the status message from the current Result.<p>
* This is used internally by the driver. * This is used internally by the driver.

File diff suppressed because it is too large Load Diff

View File

@ -10,10 +10,10 @@ import java.util.*;
public class PSQLException extends SQLException public class PSQLException extends SQLException
{ {
private String message; private String message;
// Cache for future errors // Cache for future errors
static ResourceBundle bundle; static ResourceBundle bundle;
/** /**
* This provides the same functionality to SQLException * This provides the same functionality to SQLException
* @param error Error string * @param error Error string
@ -22,7 +22,7 @@ public class PSQLException extends SQLException
super(); super();
translate(error,null); translate(error,null);
} }
/** /**
* A more generic entry point. * A more generic entry point.
* @param error Error string or standard message id * @param error Error string or standard message id
@ -33,7 +33,7 @@ public class PSQLException extends SQLException
//super(); //super();
translate(error,args); translate(error,args);
} }
/** /**
* Helper version for 1 arg * Helper version for 1 arg
*/ */
@ -44,7 +44,7 @@ public class PSQLException extends SQLException
argv[0] = arg; argv[0] = arg;
translate(error,argv); translate(error,argv);
} }
/** /**
* Helper version for 2 args * Helper version for 2 args
*/ */
@ -56,7 +56,7 @@ public class PSQLException extends SQLException
argv[1] = arg2; argv[1] = arg2;
translate(error,argv); translate(error,argv);
} }
/** /**
* This does the actual translation * This does the actual translation
*/ */
@ -70,7 +70,7 @@ public class PSQLException extends SQLException
message = id; message = id;
} }
} }
if (bundle != null) { if (bundle != null) {
// Now look up a localized message. If one is not found, then use // Now look up a localized message. If one is not found, then use
// the supplied message instead. // the supplied message instead.
@ -81,13 +81,13 @@ public class PSQLException extends SQLException
message = id; message = id;
} }
} }
// Expand any arguments // Expand any arguments
if(args!=null) if(args!=null && message != null)
message = MessageFormat.format(message,args); message = MessageFormat.format(message,args);
} }
/** /**
* Overides Throwable * Overides Throwable
*/ */
@ -95,7 +95,7 @@ public class PSQLException extends SQLException
{ {
return message; return message;
} }
/** /**
* Overides Throwable * Overides Throwable
*/ */
@ -103,7 +103,7 @@ public class PSQLException extends SQLException
{ {
return message; return message;
} }
/** /**
* Overides Object * Overides Object
*/ */
@ -111,5 +111,5 @@ public class PSQLException extends SQLException
{ {
return message; return message;
} }
} }