From f41dcbe4d810f0906f43d1b345cf506d72c792ac Mon Sep 17 00:00:00 2001 From: Peter Mount Date: Thu, 12 Oct 2000 08:55:28 +0000 Subject: [PATCH] Major update part I involving delayed patches, reworked Makefile, and how the versioning works. There's also a new utils directory used by Makefile --- src/interfaces/jdbc/CHANGELOG | 17 + src/interfaces/jdbc/Makefile | 160 ++++- src/interfaces/jdbc/example/psql.java | 423 ++++++------- src/interfaces/jdbc/example/threadsafe.java | 4 +- .../jdbc/org/postgresql/Connection.java | 33 +- .../{Driver.java => Driver.java.in} | 20 +- .../jdbc/org/postgresql/PG_Stream.java | 206 +++++- .../org/postgresql/PostgresqlDataSource.java | 585 ++++++++++++++++++ .../jdbc/org/postgresql/errors.properties | 1 + .../jdbc/org/postgresql/errors_it.properties | 74 +++ .../postgresql/jdbc1/DatabaseMetaData.java | 8 +- .../postgresql/jdbc2/DatabaseMetaData.java | 10 +- .../jdbc/org/postgresql/jdbc2/ResultSet.java | 5 + src/interfaces/jdbc/utils/CheckVersion.java | 68 ++ src/interfaces/jdbc/utils/buildDriver | 47 ++ src/interfaces/jdbc/utils/changelog.pl | 23 + 16 files changed, 1405 insertions(+), 279 deletions(-) rename src/interfaces/jdbc/org/postgresql/{Driver.java => Driver.java.in} (97%) create mode 100644 src/interfaces/jdbc/org/postgresql/PostgresqlDataSource.java create mode 100644 src/interfaces/jdbc/org/postgresql/errors_it.properties create mode 100644 src/interfaces/jdbc/utils/CheckVersion.java create mode 100755 src/interfaces/jdbc/utils/buildDriver create mode 100644 src/interfaces/jdbc/utils/changelog.pl diff --git a/src/interfaces/jdbc/CHANGELOG b/src/interfaces/jdbc/CHANGELOG index 4a5d3cd659..84eebc6577 100644 --- a/src/interfaces/jdbc/CHANGELOG +++ b/src/interfaces/jdbc/CHANGELOG @@ -1,3 +1,20 @@ +Tue Oct 10 13:12:00 BST 2000 peter@retep.org.uk + - DatabaseMetaData.supportsAlterTableWithDropColumn() as psql doesn't + support dropping of individual columns + - Merged in some last patches. Only 1 left, which may not be compatible + with jdbc1 + - Merged in my old retepsql project. Makefile now includes it. + +Mon Oct 02 12:30:00 BST 2000 peter@retep.org.uk + - Merged in byte[] array allocation changes submitted by Gunnar R|nning + + +Mon Sep 25 14:22:00 BST 2000 peter@retep.org.uk + - Removed the DriverClass kludge. Now the org.postgresql.Driver class + is compiled from a template file, and now has both the connection + 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 - Fixed DatabaseMetaData.getTableTypes() diff --git a/src/interfaces/jdbc/Makefile b/src/interfaces/jdbc/Makefile index 445d606ef8..651a995f56 100644 --- a/src/interfaces/jdbc/Makefile +++ b/src/interfaces/jdbc/Makefile @@ -4,10 +4,15 @@ # Makefile for Java JDBC interface # # IDENTIFICATION -# $Id: Makefile,v 1.24 2000/09/12 04:58:46 momjian Exp $ +# $Id: Makefile,v 1.25 2000/10/12 08:55:23 peter Exp $ # #------------------------------------------------------------------------- +subdir = src/interfaces +top_builddir = ../../.. +include $(top_builddir)/src/Makefile.global + +CP = cp FIND = find IDL2JAVA = idltojava -fno-cpp -fno-tie JAR = jar @@ -17,6 +22,9 @@ JAVADOC = javadoc RM = rm -f TOUCH = touch +BUILDDRIVER = sh utils/buildDriver +CHANGELOG = perl utils/changelog.pl + # This defines how to compile a java class .java.class: $(JAVAC) $< @@ -28,9 +36,18 @@ TOUCH = touch # postgresql to org/postgresql PGBASE = org/postgresql +# New for 7.1: The jar filename +JARFILE = postgresql.jar + +# Yet another attempt to check the version. In theory, any JVM that fails +# this is breaking the versioning specifications released by Javasoft. +# +all: utils/CheckVersion.class + @$(MAKE) `$(JAVA) utils.CheckVersion` + # For 6.5.3 and 7.0+, we need to select the correct JDBC API, so prompt # for the version. -all: +huho: @echo ------------------------------------------------------------ @echo Due to problems with some JVMs that dont return a meaningful @echo version number, we have had to make the choice of what jdbc @@ -38,15 +55,20 @@ all: @echo @echo If you are using JDK1.1.x, you will need the JDBC1.2 driver. @echo To compile, type: - @echo " make jdbc1 jar" + @echo " make jdbc1" @echo @echo "If you are using JDK1.2 (aka Java2) you need the JDBC2." @echo To compile, type: - @echo " make jdbc2 jar" + @echo " make jdbc2" + @echo + @echo "If you are using the Java2 Enterprise Edition, you can use" + @echo "either the standard driver above, or compile the standard" + @echo "extensions version of the driver. Type:" + @echo " make enterprise" @echo @echo Once you have done this, a postgresql.jar file will be @echo produced. This file will only work with that particular - @echo JVM. + @echo version of virtual machine. @echo @echo ------------------------------------------------------------ @@ -76,6 +98,10 @@ msg: @echo @echo "To make the tests, type:" @echo " make tests" + @echo + @echo "To build the GUI Shell, type:" + @echo " make retepsql" + @echo @echo ------------------------------------------------------------ @echo @@ -93,7 +119,6 @@ doc: # the jar file. OBJ_COMMON= $(PGBASE)/Connection.class \ $(PGBASE)/Driver.class \ - $(PGBASE)/DriverClass.class \ $(PGBASE)/Field.class \ $(PGBASE)/PG_Stream.class \ $(PGBASE)/ResultSet.class \ @@ -136,53 +161,79 @@ OBJ_JDBC2= $(PGBASE)/jdbc2/ResultSet.class \ $(PGBASE)/jdbc2/Statement.class \ $(PGBASE)/largeobject/PGblob.class +# These files are unique to the JDBC2 Enterprise driver +OBJ_ENTER= $(OBJ_JDBC2) \ + $(PGBASE)/PostgresqlDataSource.class \ + $(PGBASE)/xa/ClientConnection.class \ + $(PGBASE)/xa/TwoPhaseConnection.class \ + $(PGBASE)/xa/TxConnection.class \ + $(PGBASE)/xa/XAConnectionImpl.class \ + $(PGBASE)/xa/XADataSourceImpl.class + # This rule builds the JDBC1 compliant driver jdbc1: - (echo "package org.postgresql;" ;\ - echo "public class DriverClass {" ;\ - echo "public static String connectClass=\"org.postgresql.jdbc1.Connection\";" ;\ - echo "}" \ - ) >$(PGBASE)/DriverClass.java + $(BUILDDRIVER) $(VERSION) org.postgresql.jdbc1.Connection JDBC1.1 $(PGBASE)/Driver.java -$(RM) postgresql.jar @$(MAKE) jdbc1real # This rule does the real work for JDBC1.2, however do not call it directly. # This is because the JDBC driver relies on the org.postgresql.DriverClass # class to determine the driver version. -jdbc1real: $(PGBASE)/DriverClass.class \ - $(OBJ_COMMON) $(OBJ_JDBC1) postgresql.jar msg +jdbc1real: $(OBJ_COMMON) $(OBJ_JDBC1) $(JARFILE) msg # This rule builds the JDBC2 compliant driver -jdbc2: - (echo "package org.postgresql;" ;\ - echo "public class DriverClass {" ;\ - echo "public static String connectClass=\"org.postgresql.jdbc2.Connection\";" ;\ - echo "}" \ - ) >$(PGBASE)/DriverClass.java +jdbc2: + @$(MAKE) jdbc2internal msg + +# This allows us to build the jdbc2 driver without displaying the msg +# refer to the retepsql rule to see why. +jdbc2internal: + $(BUILDDRIVER) $(VERSION) org.postgresql.jdbc2.Connection Java2 $(PGBASE)/Driver.java -$(RM) postgresql.jar @$(MAKE) jdbc2real # This rule does the real work for JDBC2, however do not call it directly. # This is because the JDBC driver relies on the org.postgresql.DriverClass # class to determine the driver version. -jdbc2real: $(PGBASE)/DriverClass.class \ - $(OBJ_COMMON) $(OBJ_JDBC2) postgresql.jar msg +jdbc2real: $(OBJ_COMMON) $(OBJ_JDBC2) $(JARFILE) + +# This rule builds the enterprise edition of the driver +enterprise: + $(BUILDDRIVER) $(VERSION) org.postgresql.jdbc2.Connection Enterprise $(PGBASE)/Driver.java + -$(RM) postgresql.jar + @$(MAKE) enterprisereal -# If you have problems with this rule, replace the $( ) with ` ` as some -# shells (mainly sh under Solaris) doesn't recognise $( ) +# This rule does the real work for JDBC2 Enterprise Edition, however do not +# call it directly. This is because the JDBC driver relies on the +# org.postgresql.DriverClass class to determine the driver version. +enterprisereal: $(OBJ_COMMON) $(OBJ_ENTER) $(JARFILE) + +# We use the old `cmd` notation here as some older shells (mainly sh under +# Solaris) don't recognise the newer $(cmd) syntax. # -postgresql.jar: $(OBJ) $(OBJ_COMMON) +$(JARFILE): $(OBJ) $(OBJ_COMMON) $(JAR) -c0f $@ `$(FIND) $(PGBASE) -name "*.class" -print` \ $(wildcard $(PGBASE)/*.properties) # This rule removes any temporary and compiled files from the source tree. +# clean: $(FIND) . -name "*~" -exec $(RM) {} \; $(FIND) . -name "*.class" -exec $(RM) {} \; - $(FIND) . -name "*.html" -exec $(RM) {} \; -$(RM) -rf stock example/corba/stock.built - -$(RM) postgresql.jar org/postgresql/DriverClass.java + -$(RM) postgresql.jar org/postgresql/Driver.java -$(RM) -rf Package-postgresql *output + -$(RM) retepsql.jar manifest + +# New for 7.1 +install: $(JARFILE) + $(CP) $(JARFILE) $(libdir) + +# This converts CHANGELOG into an html format - used by peter@retep.org.uk +# to produce an online version +changelog: changelog.html +changelog.html: CHANGELOG + $(CHANGELOG) $< >$@ ####################################################################### # This helps make workout what classes are from what source files @@ -311,3 +362,60 @@ example/corba/stock.built: example/corba/stock.idl # tip: we cant use $(wildcard stock/*.java) in the above rule as a race # condition occurs, where javac is passed no arguments ####################################################################### +# +# JPGSql This isn't really an example, but an entire frontend +# for PostgreSQL via Java & JDBC. +# +# Requirements: Java2 platform (JDK1.2.x or 1.3) +# +retepsql: jdbc2internal postgresql.jar + -$(RM) retepsql.jar + @$(MAKE) retepsql.jar + @echo + @echo "The retepsql application has now been built. To run, simply" + @echo "type:" + @echo + @echo " java -jar retepsql.jar" + @echo + @echo "Note: Some operating systems recognise .jar as an executable," + @echo " so on those (and Windows is one of them), you can simply" + @echo " double click the jar file to start it." + +# All my classes have this prefix +RETEP= uk/org/retep + +# These classes form part of my personal swing library. I have placed these +# into the public domain, so there are no license issues... enjoy... +RETEPUTILS= $(RETEP)/swing/SwingApplication.class \ + $(RETEP)/swing/SwingApplication.class \ + +# This is my postgresql frontend. As it's never been released before, I've +# decided not only to publish it under the same licence as the JDBC driver, +# but also to put it along side the driver. To me it makes sense as it's the +# best example I have on showing how to use the driver ;-) +RETEPSQL= $(RETEP)/sql/DBConnection.class \ + $(RETEP)/sql/RetepSQL.class \ + +# Some ancilary files which are included in the jar file +RETEPSQLAUX= $(RETEP)/icons/ \ + +# The big rule, this builds the jpgsql.jar file which contains the entire +# application. DONT call this rule directly, but use the retepsql one, as +# it ensures that jdbc is also compiled first. +# +# Note: We include the postgresql.jar contents in this as well. Also the +# manifest entry MUST be immediately after $@ (note the -m option to jar). +# +retepsql.jar: $(RETEPUTILS) \ + $(RETEPSQL) + (echo "Manifest-Version: 1.0"; \ + echo "Created-By: 1.2 (Sun Microsystems Inc.)"; \ + echo "Main-Class: uk.org.retep.sql.RetepSQL"; \ + ) >manifest + $(JAR) -c0fm $@ manifest \ + `$(FIND) $(PGBASE) -name "*.class" -print` \ + $(wildcard $(PGBASE)/*.properties) \ + `$(FIND) $(RETEP) -name "*.class" -print` \ + $(RETEPSQLAUX) + +####################################################################### diff --git a/src/interfaces/jdbc/example/psql.java b/src/interfaces/jdbc/example/psql.java index 1493a3b822..9e63ad8129 100644 --- a/src/interfaces/jdbc/example/psql.java +++ b/src/interfaces/jdbc/example/psql.java @@ -1,210 +1,213 @@ -package example; - -import java.io.*; -import java.sql.*; -import java.text.*; - -/** - * This example application demonstrates some of the drivers other features - * by implementing a simple psql replacement in Java. - * - */ - -public class psql -{ - Connection db; // The connection to the database - Statement st; // Our statement to run queries with - DatabaseMetaData dbmd; // This defines the structure of the database - - public psql(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException - { - String url = args[0]; - String usr = args[1]; - String pwd = args[2]; - - // Load the driver - Class.forName("org.postgresql.Driver"); - - // Connect to database - System.out.println("Connecting to Database URL = " + url); - db = DriverManager.getConnection(url, usr, pwd); - - dbmd = db.getMetaData(); - st = db.createStatement(); - - // This prints the backend's version - System.out.println("Connected to "+dbmd.getDatabaseProductName()+" "+dbmd.getDatabaseProductVersion()); - - System.out.println(); - - // This provides us the means of reading from stdin - StreamTokenizer input = new StreamTokenizer(new InputStreamReader(System.in)); - input.resetSyntax(); - input.slashSlashComments(true); // allow // as a comment delimiter - input.eolIsSignificant(false); // treat eol's as spaces - input.wordChars(32,126); - input.whitespaceChars(59,59); - input.quoteChar(39); - - // Now the main loop. - int tt=0,lineno=1; - while(tt!=StreamTokenizer.TT_EOF) { - System.out.print("["+lineno+"] "); - System.out.flush(); - - // Here, we trap SQLException so they don't terminate the application - try { - if((tt=input.nextToken())==StreamTokenizer.TT_WORD) { - processLine(input.sval); - lineno++; - } - } catch(SQLException ex) { - System.out.println(ex.getMessage()); - } - } - - System.out.println("Now closing the connection"); - st.close(); - db.close(); - - } - - /** - * This processes a statement - */ - public void processLine(String line) throws SQLException - { - if(line.startsWith("\\")) { - processSlashCommand(line); - return; - } - - boolean type = st.execute(line); - boolean loop=true; - while(loop) { - if(type) { - // A ResultSet was returned - ResultSet rs=st.getResultSet(); - displayResult(rs); - } else { - int count = st.getUpdateCount(); - - if(count==-1) { - // This indicates nothing left - loop=false; - } else { - // An update count was returned - System.out.println("Updated "+st.getUpdateCount()+" rows"); - } - } - - if(loop) - type = st.getMoreResults(); - } - } - - /** - * This displays a result set. - * Note: it closes the result once complete. - */ - public void displayResult(ResultSet rs) throws SQLException - { - ResultSetMetaData rsmd = rs.getMetaData(); - - // Print the result column names - int cols = rsmd.getColumnCount(); - for(int i=1;i<=cols;i++) - System.out.print(rsmd.getColumnLabel(i)+(i3) - DriverManager.setLogStream(System.err); - - // Now run the tests - try { - psql test = new psql(args); - } catch(Exception ex) { - System.err.println("Exception caught.\n"+ex); - ex.printStackTrace(); - } - } -} +package example; + +import java.io.*; +import java.sql.*; +import java.text.*; + +/** + * This example application demonstrates some of the drivers other features + * by implementing a simple psql replacement in Java. + * + */ + +public class psql +{ + Connection db; // The connection to the database + Statement st; // Our statement to run queries with + DatabaseMetaData dbmd; // This defines the structure of the database + boolean done = false; // Added by CWJ to permit \q command + + public psql(String args[]) throws ClassNotFoundException, FileNotFoundException, IOException, SQLException + { + String url = args[0]; + String usr = args[1]; + String pwd = args[2]; + + // Load the driver + Class.forName("org.postgresql.Driver"); + + // Connect to database + System.out.println("Connecting to Database URL = " + url); + db = DriverManager.getConnection(url, usr, pwd); + + dbmd = db.getMetaData(); + st = db.createStatement(); + + // This prints the backend's version + System.out.println("Connected to "+dbmd.getDatabaseProductName()+" "+dbmd.getDatabaseProductVersion()); + + System.out.println(); + + // This provides us the means of reading from stdin + StreamTokenizer input = new StreamTokenizer(new InputStreamReader(System.in)); + input.resetSyntax(); + input.slashSlashComments(true); // allow // as a comment delimiter + input.eolIsSignificant(false); // treat eol's as spaces + input.wordChars(32,126); + input.whitespaceChars(59,59); + // input.quoteChar(39); *** CWJ: messes up literals in query string *** + + // Now the main loop. + int tt=0,lineno=1; + while(tt!=StreamTokenizer.TT_EOF && ! done) { // done added by CWJ to permit \q command + System.out.print("["+lineno+"] "); + System.out.flush(); + + // Here, we trap SQLException so they don't terminate the application + try { + if((tt=input.nextToken())==StreamTokenizer.TT_WORD) { + processLine(input.sval); + lineno++; + } + } catch(SQLException ex) { + System.out.println(ex.getMessage()); + } + } + + System.out.println("Now closing the connection"); + st.close(); + db.close(); + + } + + /** + * This processes a statement + */ + public void processLine(String line) throws SQLException + { + if(line.startsWith("\\")) { + processSlashCommand(line); + return; + } + + boolean type = st.execute(line); + boolean loop=true; + while(loop) { + if(type) { + // A ResultSet was returned + ResultSet rs=st.getResultSet(); + displayResult(rs); + } else { + int count = st.getUpdateCount(); + + if(count==-1) { + // This indicates nothing left + loop=false; + } else { + // An update count was returned + System.out.println("Updated "+st.getUpdateCount()+" rows"); + } + } + + if(loop) + type = st.getMoreResults(); + } + } + + /** + * This displays a result set. + * Note: it closes the result once complete. + */ + public void displayResult(ResultSet rs) throws SQLException + { + ResultSetMetaData rsmd = rs.getMetaData(); + + // Print the result column names + int cols = rsmd.getColumnCount(); + for(int i=1;i<=cols;i++) + System.out.print(rsmd.getColumnLabel(i)+(i3) + DriverManager.setLogStream(System.err); + + // Now run the tests + try { + psql test = new psql(args); + } catch(Exception ex) { + System.err.println("Exception caught.\n"+ex); + ex.printStackTrace(); + } + } +} diff --git a/src/interfaces/jdbc/example/threadsafe.java b/src/interfaces/jdbc/example/threadsafe.java index 7cb48c1961..ea69143d8d 100644 --- a/src/interfaces/jdbc/example/threadsafe.java +++ b/src/interfaces/jdbc/example/threadsafe.java @@ -145,7 +145,7 @@ public class threadsafe // manner. (DateStyles are PostgreSQL's way of handling different methods // of representing dates in the Date data type.) PreparedStatement ps = db.prepareStatement("insert into basic1 values (?,?)"); - for(int i=2;i<200;i++) { + for(int i=2;i<2000;i++) { ps.setInt(1,4); // "column a" = 5 ps.setInt(2,i); // "column b" = i ps.executeUpdate(); // executeUpdate because insert returns no data @@ -212,7 +212,7 @@ public class threadsafe // manner. (DateStyles are PostgreSQL's way of handling different methods // of representing dates in the Date data type.) PreparedStatement ps = db.prepareStatement("insert into basic2 values (?,?)"); - for(int i=2;i<200;i++) { + for(int i=2;i<2000;i++) { ps.setInt(1,4); // "column a" = 5 ps.setInt(2,i); // "column b" = i ps.executeUpdate(); // executeUpdate because insert returns no data diff --git a/src/interfaces/jdbc/org/postgresql/Connection.java b/src/interfaces/jdbc/org/postgresql/Connection.java index f04f7fffe6..e4c3537df7 100644 --- a/src/interfaces/jdbc/org/postgresql/Connection.java +++ b/src/interfaces/jdbc/org/postgresql/Connection.java @@ -10,7 +10,7 @@ import org.postgresql.largeobject.*; import org.postgresql.util.*; /** - * $Id: Connection.java,v 1.8 2000/10/09 16:48:16 momjian Exp $ + * $Id: Connection.java,v 1.9 2000/10/12 08:55:24 peter Exp $ * * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or * JDBC2 versions of the Connection class. @@ -81,6 +81,11 @@ public abstract class Connection // The PID an cancellation key we get from the backend process public int pid; public int ckey; + + // This receive_sbuf should be used by the different methods + // that call pg_stream.ReceiveString() in this Connection, so + // so we avoid uneccesary new allocations. + byte receive_sbuf[] = new byte[8192]; /** * This is called by Class.forName() from within org.postgresql.Driver @@ -165,7 +170,7 @@ public abstract class Connection // "User authentication failed" // throw new SQLException(pg_stream.ReceiveString - (4096, getEncoding())); + (receive_sbuf, 4096, getEncoding())); case 'R': // Get the type of request @@ -236,7 +241,7 @@ public abstract class Connection case 'E': case 'N': throw new SQLException(pg_stream.ReceiveString - (4096, getEncoding())); + (receive_sbuf, 4096, getEncoding())); default: throw new PSQLException("postgresql.con.setup"); } @@ -248,7 +253,7 @@ public abstract class Connection break; case 'E': case 'N': - throw new SQLException(pg_stream.ReceiveString(4096)); + throw new SQLException(pg_stream.ReceiveString(receive_sbuf, 4096, getEncoding())); default: throw new PSQLException("postgresql.con.setup"); } @@ -322,6 +327,12 @@ public abstract class Connection { // added Oct 7 1998 to give us thread safety. synchronized(pg_stream) { + // Deallocate all resources in the stream associated + // with a previous request. + // This will let the driver reuse byte arrays that has already + // been allocated instead of allocating new ones in order + // to gain performance improvements. + pg_stream.deallocate(); Field[] fields = null; Vector tuples = new Vector(); @@ -353,7 +364,7 @@ public abstract class Connection { pg_stream.SendChar('Q'); buf = sql.getBytes(); - pg_stream.Send(buf); + pg_stream.Send(sql.getBytes()); pg_stream.SendChar(0); pg_stream.flush(); } catch (IOException e) { @@ -370,7 +381,7 @@ public abstract class Connection { case 'A': // Asynchronous Notify pid = pg_stream.ReceiveInteger(4); - msg = pg_stream.ReceiveString(8192); + msg = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); break; case 'B': // Binary Data Transfer if (fields == null) @@ -381,7 +392,7 @@ public abstract class Connection tuples.addElement(tup); break; case 'C': // Command Status - recv_status = pg_stream.ReceiveString(8192); + recv_status = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); // Now handle the update count correctly. if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE")) { @@ -423,7 +434,7 @@ public abstract class Connection tuples.addElement(tup); break; case 'E': // Error Message - msg = pg_stream.ReceiveString(4096); + msg = pg_stream.ReceiveString(receive_sbuf,4096,getEncoding()); final_error = new SQLException(msg); hfr = true; break; @@ -438,10 +449,10 @@ public abstract class Connection hfr = true; break; case 'N': // Error Notification - addWarning(pg_stream.ReceiveString(4096)); + addWarning(pg_stream.ReceiveString(receive_sbuf,4096,getEncoding())); break; case 'P': // Portal Name - String pname = pg_stream.ReceiveString(8192); + String pname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); break; case 'T': // MetaData Field Description if (fields != null) @@ -474,7 +485,7 @@ public abstract class Connection for (i = 0 ; i < nf ; ++i) { - String typname = pg_stream.ReceiveString(8192); + String typname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding()); int typid = pg_stream.ReceiveIntegerR(4); int typlen = pg_stream.ReceiveIntegerR(2); int typmod = pg_stream.ReceiveIntegerR(4); diff --git a/src/interfaces/jdbc/org/postgresql/Driver.java b/src/interfaces/jdbc/org/postgresql/Driver.java.in similarity index 97% rename from src/interfaces/jdbc/org/postgresql/Driver.java rename to src/interfaces/jdbc/org/postgresql/Driver.java.in index 849bb71d54..40e2a94956 100644 --- a/src/interfaces/jdbc/org/postgresql/Driver.java +++ b/src/interfaces/jdbc/org/postgresql/Driver.java.in @@ -26,10 +26,6 @@ import org.postgresql.util.PSQLException; */ public class Driver implements java.sql.Driver { - // These should be in sync with the backend that the driver was - // distributed with - static final int MAJORVERSION = 7; - static final int MINORVERSION = 0; static { @@ -117,10 +113,8 @@ public class Driver implements java.sql.Driver if((props = parseURL(url,info))==null) return null; - DriverManager.println("Using "+DriverClass.connectClass); - try { - org.postgresql.Connection con = (org.postgresql.Connection)(Class.forName(DriverClass.connectClass).newInstance()); + org.postgresql.Connection con = (org.postgresql.Connection)(Class.forName("%JDBCCONNECTCLASS%").newInstance()); con.openConnection (host(), port(), props, database(), url, this); return (java.sql.Connection)con; } catch(ClassNotFoundException ex) { @@ -198,7 +192,7 @@ public class Driver implements java.sql.Driver */ public int getMajorVersion() { - return MAJORVERSION; + return %MAJORVERSION%; } /** @@ -208,9 +202,17 @@ public class Driver implements java.sql.Driver */ public int getMinorVersion() { - return MINORVERSION; + return %MINORVERSION%; } + /** + * Returns the VERSION variable from Makefile.global + */ + public static String getVersion() + { + return "%VERSION%"; + } + /** * Report whether the driver is a genuine JDBC compliant driver. A * driver may only report "true" here if it passes the JDBC compliance diff --git a/src/interfaces/jdbc/org/postgresql/PG_Stream.java b/src/interfaces/jdbc/org/postgresql/PG_Stream.java index 22c41bdb3a..9a2b712dda 100644 --- a/src/interfaces/jdbc/org/postgresql/PG_Stream.java +++ b/src/interfaces/jdbc/org/postgresql/PG_Stream.java @@ -23,6 +23,9 @@ public class PG_Stream private InputStream pg_input; private BufferedOutputStream pg_output; + BytePoolDim1 bytePoolDim1 = new BytePoolDim1(); + BytePoolDim2 bytePoolDim2 = new BytePoolDim2(); + /** * Constructor: Connect to the PostgreSQL back end and return * a stream connection. @@ -70,7 +73,7 @@ public class PG_Stream */ public void SendInteger(int val, int siz) throws IOException { - byte[] buf = new byte[siz]; + byte[] buf = bytePoolDim1.allocByte(siz); while (siz-- > 0) { @@ -94,7 +97,7 @@ public class PG_Stream */ public void SendIntegerReverse(int val, int siz) throws IOException { - byte[] buf = new byte[siz]; + byte[] buf = bytePoolDim1.allocByte(siz); int p=0; while (siz-- > 0) { @@ -236,15 +239,27 @@ public class PG_Stream return n; } - public String ReceiveString(int maxsize) throws SQLException { - return ReceiveString(maxsize, null); - } - /** * Receives a null-terminated string from the backend. Maximum of * maxsiz bytes - if we don't see a null, then we assume something * has gone wrong. * + * @param maxsiz maximum length of string + * @return string from back end + * @exception SQLException if an I/O error occurs + */ + public String ReceiveString(int maxsiz) throws SQLException + { + byte[] rst = bytePoolDim1.allocByte(maxsiz); + return ReceiveString(rst, maxsiz, null); + } + + /** + * Receives a null-terminated string from the backend. Maximum of + * maxsiz bytes - if we don't see a null, then we assume something + * has gone wrong. + * + * @param maxsiz maximum length of string * @param encoding the charset encoding to use. * @param maxsiz maximum length of string in bytes * @return string from back end @@ -252,7 +267,25 @@ public class PG_Stream */ public String ReceiveString(int maxsiz, String encoding) throws SQLException { - byte[] rst = new byte[maxsiz]; + byte[] rst = bytePoolDim1.allocByte(maxsiz); + return ReceiveString(rst, maxsiz, encoding); + } + + /** + * Receives a null-terminated string from the backend. Maximum of + * maxsiz bytes - if we don't see a null, then we assume something + * has gone wrong. + * + * @param rst byte array to read the String into. rst.length must + * equal to or greater than maxsize. + * @param maxsiz maximum length of string in bytes + * @param encoding the charset encoding to use. + * @return string from back end + * @exception SQLException if an I/O error occurs + */ + public String ReceiveString(byte rst[], int maxsiz, String encoding) + throws SQLException + { int s = 0; try @@ -262,9 +295,10 @@ public class PG_Stream int c = pg_input.read(); if (c < 0) throw new PSQLException("postgresql.stream.eof"); - else if (c == 0) - break; - else + else if (c == 0) { + rst[s] = 0; + break; + } else rst[s++] = (byte)c; } if (s >= maxsiz) @@ -299,7 +333,7 @@ public class PG_Stream { int i, bim = (nf + 7)/8; byte[] bitmask = Receive(bim); - byte[][] answer = new byte[nf][0]; + byte[][] answer = bytePoolDim2.allocByte(nf); int whichbit = 0x80; int whichbyte = 0; @@ -337,7 +371,7 @@ public class PG_Stream */ private byte[] Receive(int siz) throws SQLException { - byte[] answer = new byte[siz]; + byte[] answer = bytePoolDim1.allocByte(siz); Receive(answer,0,siz); return answer; } @@ -395,4 +429,152 @@ public class PG_Stream pg_input.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(); + } + } +} + diff --git a/src/interfaces/jdbc/org/postgresql/PostgresqlDataSource.java b/src/interfaces/jdbc/org/postgresql/PostgresqlDataSource.java new file mode 100644 index 0000000000..e02d8126cc --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/PostgresqlDataSource.java @@ -0,0 +1,585 @@ +/** + * Redistribution and use of this software and associated documentation + * ("Software"), with or without modification, are permitted provided + * that the following conditions are met: + * + * 1. Redistributions of source code must retain copyright + * statements and notices. Redistributions must also contain a + * copy of this document. + * + * 2. Redistributions in binary form must reproduce the + * above copyright notice, this list of conditions and the + * following disclaimer in the documentation and/or other + * materials provided with the distribution. + * + * 3. The name "Exolab" must not be used to endorse or promote + * products derived from this Software without prior written + * permission of Exoffice Technologies. For written permission, + * please contact info@exolab.org. + * + * 4. Products derived from this Software may not be called "Exolab" + * nor may "Exolab" appear in their names without prior written + * permission of Exoffice Technologies. Exolab is a registered + * trademark of Exoffice Technologies. + * + * 5. Due credit should be given to the Exolab Project + * (http://www.exolab.org/). + * + * THIS SOFTWARE IS PROVIDED BY EXOFFICE TECHNOLOGIES AND CONTRIBUTORS + * ``AS IS'' AND ANY EXPRESSED OR IMPLIED WARRANTIES, INCLUDING, BUT + * NOT LIMITED TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND + * FITNESS FOR A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL + * EXOFFICE TECHNOLOGIES OR ITS CONTRIBUTORS BE LIABLE FOR ANY DIRECT, + * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL DAMAGES + * (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF SUBSTITUTE GOODS OR + * SERVICES; LOSS OF USE, DATA, OR PROFITS; OR BUSINESS INTERRUPTION) + * HOWEVER CAUSED AND ON ANY THEORY OF LIABILITY, WHETHER IN CONTRACT, + * STRICT LIABILITY, OR TORT (INCLUDING NEGLIGENCE OR OTHERWISE) + * ARISING IN ANY WAY OUT OF THE USE OF THIS SOFTWARE, EVEN IF ADVISED + * OF THE POSSIBILITY OF SUCH DAMAGE. + * + * Copyright 1999 (C) Exoffice Technologies Inc. All Rights Reserved. + * + * $Id: PostgresqlDataSource.java,v 1.1 2000/10/12 08:55:24 peter Exp $ + */ + + +package org.postgresql; + + +import java.io.PrintWriter; +import java.io.Serializable; +import java.util.Properties; +import java.util.Hashtable; +import java.sql.Connection; +import java.sql.SQLException; +import java.sql.DriverManager; +import java.rmi.Remote; +import javax.sql.DataSource; +import javax.naming.Referenceable; +import javax.naming.Reference; +import javax.naming.StringRefAddr; +import javax.naming.RefAddr; +import javax.naming.Context; +import javax.naming.Name; +import javax.naming.NamingException; +import javax.naming.spi.ObjectFactory; +import postgresql.util.PSQLException; +import postgresql.xa.XADataSourceImpl; + + +/** + * Implements a JDBC 2.0 {@link javax.sql.DataSource} for the + * PostgreSQL driver with JNDI persistance support. XA and pooled + * connection support is also available, but the application must + * used the designated DataSource interface to obtain them. + *

+ * The supported data source properties are: + *

+ * description         (optional)
+ * databaseName        (required)
+ * loginTimeout        (optional)
+ * user                (optional)
+ * password            (optional)
+ * serverName          (optional)
+ * portNumber          (optional)
+ * transactionTimeout  (optional for XA connections)
+ * 
+ * This data source may be serialized and stored in a JNDI + * directory. Example of how to create a new data source and + * register it with JNDI: + *
+ * PostgresqlDataSource ds;
+ * InitialContext       ctx;
+ *
+ * ds = new PostgresqlDataSource();
+ * ds.setDatabaseName( "test" );
+ * ds.setUser( "me" );
+ * ds.setPassword( "secret" );
+ * ctx = new InitialContext();
+ * ctx.rebind( "/comp/jdbc/test", ds );
+ * 
+ * Example for obtaining the data source from JNDI and + * opening a new connections: + *
+ * InitialContext       ctx;
+ * DataSource           ds;
+ * 
+ * ctx = new InitialContext();
+ * ds = (DataSource) ctx.lookup( "/comp/jdbc/test" );
+ * ds.getConnection();
+ * 
+ * + * + * @author Assaf Arkin + * @version 1.0 + * @see XADataSourceImpl + * @see DataSource + * @see Connection + */ +public class PostgresqlDataSource + extends XADataSourceImpl + implements DataSource, Referenceable, + ObjectFactory, Serializable +{ + + + /** + * Holds the timeout for opening a new connection, specified + * in seconds. The default is obtained from the JDBC driver. + */ + private int _loginTimeout; + + + /** + * Holds the user's account name. + */ + private String _user; + + + /** + * Holds the database password. + */ + private String _password; + + + /** + * Holds the name of the particular database on the server. + */ + private String _databaseName; + + + /** + * Description of this datasource. + */ + private String _description = "PostgreSQL DataSource"; + + + /** + * Holds the database server name. If null, this is + * assumed to be the localhost. + */ + private String _serverName; + + + /** + * Holds the port number where a server is listening. + * The default value will open a connection with an + * unspecified port. + */ + private int _portNumber = DEFAULT_PORT; + + + /** + * The default port number. Since we open the connection + * without specifying the port if it's the default one, + * this value can be meaningless. + */ + private static final int DEFAULT_PORT = 0; + + + /** + * Holds the log writer to which all messages should be + * printed. The default writer is obtained from the driver + * manager, but it can be specified at the datasource level + * and will be passed to the driver. May be null. + */ + private transient PrintWriter _logWriter; + + + /** + * Each datasource maintains it's own driver, in case of + * driver-specific setup (e.g. pools, log writer). + */ + private transient postgresql.Driver _driver; + + + + + public PostgresqlDataSource() + { + _logWriter = DriverManager.getLogWriter(); + _loginTimeout = DriverManager.getLoginTimeout(); + } + + + public Connection getConnection() + throws SQLException + { + // Uses the username and password specified for the datasource. + return getConnection( _user, _password ); + } + + + public synchronized Connection getConnection( String user, String password ) + throws SQLException + { + Connection conn; + Properties info; + String url; + + if ( _driver == null ) { + try { + // Constructs a driver for use just by this data source + // which will produce TwoPhaseConnection-s. This driver + // is not registered with the driver manager. + _driver = new postgresql.Driver(); + _driver.setLogWriter( _logWriter ); + } catch ( SQLException except ) { + if ( _logWriter != null ) + _logWriter.println( "DataSource: Failed to initialize JDBC driver: " + except ); + throw except; + } + } + + // Use info to supply properties that are not in the URL. + info = new Properties(); + info.put( "loginTimeout", Integer.toString( _loginTimeout ) ); + + // DriverManager will do that and not rely on the URL alone. + if ( user == null ) { + user = _user; + password = _password; + } + if ( user == null || password == null ) + throw new PSQLException( "postgresql.ds.userpswd" ); + info.put( "user", user ); + info.put( "password", password ); + + if ( _serverName != null ) + info.put( "PGHOST", _serverName ); + if ( _portNumber != DEFAULT_PORT ) + info.put( "PGPORT", Integer.toString( _portNumber ) ); + if ( _databaseName != null ) + info.put( "PGDBNAME", _databaseName ); + + // Construct the URL suitable for this driver. + url = "jdbc:postgresql:"; + + // Attempt to establish a connection. Report a successful + // attempt or a failure. + try { + conn = _driver.connect( url, info ); + if ( ! ( conn instanceof postgresql.jdbc2.Connection ) ) { + if ( _logWriter != null ) + _logWriter.println( "DataSource: JDBC 1 connections not supported" ); + throw new PSQLException( "postgresql.ds.onlyjdbc2" ); + } + } catch ( SQLException except ) { + if ( _logWriter != null ) + _logWriter.println( "DataSource: getConnection failed " + except ); + throw except; + } + if ( conn != null && _logWriter != null ) + _logWriter.println( "DataSource: getConnection returning " + conn ); + return conn; + } + + + public PrintWriter getLogWriter() + { + return _logWriter; + } + + + public synchronized void setLogWriter( PrintWriter writer ) + { + // Once a log writer has been set, we cannot set it since some + // thread might be conditionally accessing it right now without + // synchronizing. + if ( writer != null ) { + if ( _driver != null ) + _driver.setLogWriter( writer ); + _logWriter = writer; + } + } + + + public void setLoginTimeout( int seconds ) + { + _loginTimeout = seconds; + } + + + public synchronized int getLoginTimeout() + { + return _loginTimeout; + } + + + /** + * Sets the name of the particular database on the server. + * The standard name for this property is databaseName. + * + * @param databaseName The name of the particular database on the server + */ + public synchronized void setDatabaseName( String databaseName ) + { + if ( databaseName == null ) + throw new NullPointerException( "DataSource: Argument 'databaseName' is null" ); + _databaseName = databaseName; + } + + + /** + * Returns the name of the particular database on the server. + * The standard name for this property is databaseName. + * + * @return The name of the particular database on the server + */ + public String getDatabaseName() + { + return _databaseName; + } + + + /** + * Sets the description of this datasource. + * The standard name for this property is description. + * + * @param description The description of this datasource + */ + public synchronized void setDescription( String description ) + { + if ( description == null ) + throw new NullPointerException( "DataSource: Argument 'description' is null" ); + _description = description; + } + + + /** + * Returns the description of this datasource. + * The standard name for this property is description. + * + * @return The description of this datasource + */ + public String getDescription() + { + return _description; + } + + + /** + * Sets the database password. + * The standard name for this property is password. + * + * @param password The database password + */ + public synchronized void setPassword( String password ) + { + _password = password; + } + + + /** + * Returns the database password. + * The standard name for this property is password. + * + * @return The database password + */ + public String getPassword() + { + return _password; + } + + + /** + * Sets the port number where a server is listening. + * The standard name for this property is portNumber. + * + * @param portNumber The port number where a server is listening + */ + public synchronized void setPortNumber( int portNumber ) + { + _portNumber = portNumber; + } + + + /** + * Returns the port number where a server is listening. + * The standard name for this property is portNumber. + * + * @return The port number where a server is listening + */ + public int getPortNumber() + { + return _portNumber; + } + + + /** + * Sets the database server name. + + * The standard name for this property is serverName. + * + * @param serverName The database server name + */ + public synchronized void setServerName( String serverName ) + { + _serverName = serverName; + } + + + /** + * Returns the database server name. + * The standard name for this property is serverName. + * + * @return The database server name + */ + public String getServerName() + { + return _serverName; + } + + + /** + * Sets the user's account name. + * The standard name for this property is user. + * + * @param user The user's account name + */ + public synchronized void setUser( String user ) + { + _user = user; + } + + + /** + * Returns the user's account name. + * The standard name for this property is user. + * + * @return The user's account name + */ + public String getUser() + { + return _user; + } + + + /** + * Returns true if this datasource and the other are equal. + * The two datasources are equal if and only if they will produce + * the exact same connections. Connection properties like database + * name, user name, etc are comapred. Setup properties like + * description, log writer, etc are not compared. + */ + public synchronized boolean equals( Object other ) + { + if ( other == this ) + return true; + if ( other == null || ! ( other instanceof PostgresqlDataSource ) ) + return false; + + PostgresqlDataSource with; + + with = (PostgresqlDataSource) other; + if ( _databaseName != null && _databaseName.equals( with._databaseName ) ) + if ( _portNumber == with._portNumber && + ( ( _serverName == null && with._serverName == null ) || + ( _serverName != null && _serverName.equals( with._serverName ) ) ) ) + if ( ( _user == null && with._user == null ) || + ( _user != null && _password != null && _user.equals( with._user ) && + _password.equals( with._password ) ) ) + return true; + return false; + } + + + public String toString() + { + if ( _description != null ) + return _description; + else { + String url; + + url = "jdbc:postgresql:"; + if ( _serverName != null ) { + if ( _portNumber == DEFAULT_PORT ) + url = url + "//" + _serverName + "/"; + else + url = url + "//" + _serverName + ":" + _portNumber + "/"; + } else if ( _portNumber != DEFAULT_PORT ) + url = url + "//localhost:" + _portNumber + "/"; + if ( _databaseName != null ) + url = url + _databaseName; + return "DataSource " + url; + } + } + + + public synchronized Reference getReference() + { + Reference ref; + + // We use same object as factory. + ref = new Reference( getClass().getName(), getClass().getName(), null ); + // Mandatory properties + ref.add( new StringRefAddr( "description", _description ) ); + ref.add( new StringRefAddr( "databaseName", _databaseName ) ); + ref.add( new StringRefAddr( "loginTimeout", Integer.toString( _loginTimeout ) ) ); + // Optional properties + if ( _user != null ) + ref.add( new StringRefAddr( "user", _user ) ); + if ( _password != null ) + ref.add( new StringRefAddr( "password", _password ) ); + if ( _serverName != null ) + ref.add( new StringRefAddr( "serverName", _serverName ) ); + if ( _portNumber != DEFAULT_PORT ) + ref.add( new StringRefAddr( "portNumber", Integer.toString( _portNumber ) ) ); + ref.add( new StringRefAddr( "transactionTimeout", Integer.toString( getTransactionTimeout() ) ) ); + return ref; + } + + + public Object getObjectInstance( Object refObj, Name name, Context nameCtx, Hashtable env ) + throws NamingException + { + Reference ref; + + // Can only reconstruct from a reference. + if ( refObj instanceof Reference ) { + ref = (Reference) refObj; + // Make sure reference is of datasource class. + if ( ref.getClassName().equals( getClass().getName() ) ) { + + PostgresqlDataSource ds; + RefAddr addr; + + try { + ds = (PostgresqlDataSource) Class.forName( ref.getClassName() ).newInstance(); + } catch ( Exception except ) { + throw new NamingException( except.toString() ); + } + // Mandatory properties + ds._description = (String) ref.get( "description" ).getContent(); + ds._databaseName = (String) ref.get( "databaseName" ).getContent(); + ds._loginTimeout = Integer.parseInt( (String) ref.get( "loginTimeout" ).getContent() ); + // Optional properties + addr = ref.get( "user" ); + if ( addr != null ) + ds._user = (String) addr.getContent(); + addr = ref.get( "password" ); + if ( addr != null ) + ds._password = (String) addr.getContent(); + addr = ref.get( "serverName" ); + if ( addr != null ) + ds._serverName = (String) addr.getContent(); + addr = ref.get( "portNumber" ); + if ( addr != null ) + ds._portNumber = Integer.parseInt( (String) addr.getContent() ); + addr = ref.get( "transactionTimeout" ); + if ( addr != null ) + setTransactionTimeout( Integer.parseInt( (String) addr.getContent() ) ); + return ds; + + } else + throw new NamingException( "DataSource: Reference not constructed from class " + getClass().getName() ); + } else if ( refObj instanceof Remote ) + return refObj; + else + return null; + } + + +} + diff --git a/src/interfaces/jdbc/org/postgresql/errors.properties b/src/interfaces/jdbc/org/postgresql/errors.properties index 2de5802d5b..c33a34aa7b 100644 --- a/src/interfaces/jdbc/org/postgresql/errors.properties +++ b/src/interfaces/jdbc/org/postgresql/errors.properties @@ -1,4 +1,5 @@ # This is the default errors +postgresql.drv.version:An internal error has occured. Please recompile the driver. postgresql.con.auth:The authentication type {0} is not supported. Check that you have configured the pg_hba.conf file to include the client's IP address or Subnet, and that it is using an authentication scheme supported by the driver. postgresql.con.authfail:An error occured while getting the authentication request. postgresql.con.call:Callable Statements are not supported at this time. diff --git a/src/interfaces/jdbc/org/postgresql/errors_it.properties b/src/interfaces/jdbc/org/postgresql/errors_it.properties new file mode 100644 index 0000000000..9b7f7cdd69 --- /dev/null +++ b/src/interfaces/jdbc/org/postgresql/errors_it.properties @@ -0,0 +1,74 @@ +# This is the italian version of some errors. Errors not in this file +# are handled by the parent errors.properties file. +# +# Daniele Arduini +# Wed Aug 9 12:18:31 CEST 2000 +# +postgresql.con.auth:L'autenticazione di tipo {0} non è supportata. Verificare che nel file di configurazione pg_hba.conf sia presente l'indirizzo IP o la sotto-rete del client, e che lo schema di autenticazione utilizzato sia supportato dal driver. +postgresql.con.authfail:Si è verificato un errore durante la richiesta di autenticazione. +postgresql.con.call:I ``Callable Statements'' non sono supportati al momento. +postgresql.con.creobj:Fallita la creazione dell'oggetto per {0} {1} +postgresql.con.failed:Il tentativo di connessione è fallito perché {0} +#postgresql.con.fathom:Unable to fathom update count {0} +postgresql.con.garbled:Ricevuti dati incomprensibili. +postgresql.con.ioerror:Si è verificato un errore di I/O nella spedizione di dati al backend - {0} +postgresql.con.kerb4:L'autenticazione di tipo ``Kerberos 4'' non è supportata da questo driver. +postgresql.con.kerb5:L'autenticazione di tipo ``Kerberos 5'' non è supportata da questo driver. +postgresql.con.multres:Impossibile gestire gruppi multipli di risultati. +postgresql.con.pass:La proprietà ``password'' è mancante. E` obbligatoria. +postgresql.con.refused:Connessione rifiutata. Controllare che il nome dell'host e la porta siano corretti, e che il server (postmaster) è in esecuzione con l'opzione -i, che abilita le connessioni attraverso la rete TCP/IP. +postgresql.con.setup:Errore di protocollo. Fallita l'impostazione della sessione. +postgresql.con.strobj:L'oggetto potrebbe non essere stato memorizzato. Controllare che ogni tabella richiesta è stata creata nel database. +postgresql.con.strobjex:Fallita la memorizzazione dell'oggetto - {0} +postgresql.con.toolong:L'istruzione SQL è troppo lunga - {0} +postgresql.con.isolevel:Il livello d'isolamento delle transazioni {0} non è supportato. +postgresql.con.tuple:Tupla ricevuta prima del MetaData. +postgresql.con.type:Tipo di risposta sconosciuta {0} +postgresql.con.user:La proprietà ``user'' è mancante. E` obbligatoria. +postgresql.fp.error:La chiamata a FastPath ha restituito {0} +postgresql.fp.expint:Chiamata Fastpath {0} - Nessun risultato restituito mentre ci si aspettava un intero. +postgresql.fp.protocol:Errore nel protocollo FastPath: {0} +postgresql.fp.send:Fallita la spedizione della chiamata fastpath {0} {1} +postgresql.fp.unknown:La funzione fastpath {0} è sconosciuta. +postgresql.geo.box:Fallita la conversione di un ``box'' - {0} +postgresql.geo.circle:Fallita la conversione di un ``circle'' - {0} +postgresql.geo.line:Fallita la conversione di una ``line'' - {0} +postgresql.geo.lseg:Fallita la conversione di un ``lseg'' - {0} +postgresql.geo.path:Impossibile stabilire se il ``path'' è aperto o chiuso. +postgresql.geo.point:Fallita la conversione di un ``point'' - {0} +postgresql.jvm.version:Il file ``postgresql.jar'' non contiene le classi JDBC corrette per questa JVM. Provare a ricompilarle. Se il problema persiste, tentare di forzare la versione fornendola nella linea di comando con l'opzione -Djava.version=1.1 or -Djava.version=1.2\nL'eccezione ricevuta è stata {0} +postgresql.lo.init:Inizializzazione di LargeObject API fallita. +postgresql.money:Fallita la conversione di un ``money'' - {0}. +postgresql.prep.is:InputStream come parametro non è supportato +postgresql.prep.param:Nessun valore specificato come parametro {0}. +postgresql.prep.range:Indice di parametro fuori dall'intervallo. +postgresql.prep.type:Valore di tipo sconosciuto. +postgresql.res.badbigdec:Cattivo BigDecimal {0} +postgresql.res.badbyte:Cattivo Byte {0} +postgresql.res.baddate:Cattivo Date Format a {0} in {1} +postgresql.res.baddouble:Cattivo Double {0} +postgresql.res.badfloat:Cattivo Float {0} +postgresql.res.badint:Cattivo Integer {0} +postgresql.res.badlong:Cattivo Long {0} +postgresql.res.badshort:Cattivo Short {0} +postgresql.res.badtime:Cattivo Time {0} +postgresql.res.badtimestamp:Cattivo Timestamp Format a {0} in {1} +postgresql.res.colname:Colonna denominata {0} non trovata. +postgresql.res.colrange:Indice di colonna fuori dall'intervallo. +postgresql.serial.interface:Impossibile serializzare una interfaccia. +postgresql.serial.namelength:La lunghezza dei nomi per Class & Package non può essere superiore a 32 caratteri. {0} è di {1} caratteri. +postgresql.serial.noclass:Nessuna classe trovata per {0}. +postgresql.serial.table:La tabella per {0} non è nel database. Contattare il DBA, visto che il database è in uno stato incosistente. +postgresql.serial.underscore:Il nome di una classe non può contenere il carattere ``_''. E` stato fornito {0}. +postgresql.stat.batch.empty:La sequenza di operazioni è vuota. Non c'è niente da eseguire. +postgresql.stat.batch.error:L'operazione {0} {1} della sequenza è stata annullata. +postgresql.stat.maxfieldsize:Fallito un tentativo a setMaxFieldSize() - verrà utilizzato il valore predefinito a tempo di compilazione. +postgresql.stat.noresult:Nessun risultato è stato restituito dalla query. +postgresql.stat.result:Un risultato è stato restituito dallo statement, quando ci si aspettava nulla. +postgresql.stream.eof:Il backend ha interrotto la connessione. Probabilmente la tua azione ha causato la sua uscita. +postgresql.stream.flush:Si è verificato un errore di I/O mentre si svuotava il buffer d'uscita - {0} +postgresql.stream.ioerror:Si è verificato un errore di I/O mentre si leggevano dati dal backend - {0} +postgresql.stream.toomuch:Troppi dati ricevuti. +postgresql.unusual:Qualcosa di insolito si è verificato causando il fallimento del driver. Per favore riferire allo sviluppatore questa eccezione: {0} +postgresql.unimplemented:Questo metodo non è stato ancora implementato. +postgresql.unexpected:Un risultato inaspettato è stato ricevuto dalla query. diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java b/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java index 674c0d16e1..b1f7e581bc 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/DatabaseMetaData.java @@ -179,7 +179,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public String getDatabaseProductVersion() throws SQLException { - return ("7.0.2"); + return connection.this_driver.getVersion(); } /** @@ -203,7 +203,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public String getDriverVersion() throws SQLException { - return Integer.toString(connection.this_driver.getMajorVersion())+"."+Integer.toString(connection.this_driver.getMinorVersion()); + return connection.this_driver.getVersion(); } /** @@ -453,14 +453,14 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData /** * Is "ALTER TABLE" with a drop column supported? - * Yes for PostgreSQL 6.1 + * Peter 10/10/2000 This was set to true, but 7.1devel doesn't support it! * * @return true if so * @exception SQLException if a database access error occurs */ public boolean supportsAlterTableWithDropColumn() throws SQLException { - return true; + return false; } /** diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java b/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java index 4b8451d1fc..051a99c630 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/DatabaseMetaData.java @@ -179,7 +179,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public String getDatabaseProductVersion() throws SQLException { - return ("7.0.2"); + return connection.this_driver.getVersion(); } /** @@ -203,7 +203,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData */ public String getDriverVersion() throws SQLException { - return Integer.toString(connection.this_driver.getMajorVersion())+"."+Integer.toString(connection.this_driver.getMinorVersion()); + return connection.this_driver.getVersion(); } /** @@ -453,14 +453,14 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData /** * Is "ALTER TABLE" with a drop column supported? - * Yes for PostgreSQL 6.1 + * Peter 10/10/2000 This was set to true, but 7.1devel doesn't support it! * * @return true if so * @exception SQLException if a database access error occurs */ public boolean supportsAlterTableWithDropColumn() throws SQLException { - return true; + return false; } /** @@ -523,7 +523,7 @@ public class DatabaseMetaData implements java.sql.DatabaseMetaData } /** - * Are expressions in "ORCER BY" lists supported? + * Are expressions in "ORDER BY" lists supported? * *
e.g. select * from t order by a + b; * diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java index e9f6c79f41..5c73b6ed4f 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/ResultSet.java @@ -730,6 +730,11 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu if (columnIndex < 1 || columnIndex > fields.length) throw new PSQLException("postgresql.res.colrange"); + + wasNullFlag = (this_row[columnIndex - 1] == null); + if(wasNullFlag) + return null; + field = fields[columnIndex - 1]; // some fields can be null, mainly from those returned by MetaData methods diff --git a/src/interfaces/jdbc/utils/CheckVersion.java b/src/interfaces/jdbc/utils/CheckVersion.java new file mode 100644 index 0000000000..b82ba335fd --- /dev/null +++ b/src/interfaces/jdbc/utils/CheckVersion.java @@ -0,0 +1,68 @@ +package utils; + +/** + * This little app checks to see what version of JVM is being used. + * It does this by checking first the java.vm.version property, and + * if that fails, it looks for certain classes that should be present. + */ +public class CheckVersion +{ + /** + * Check for the existence of a class by attempting to load it + */ + public static boolean checkClass(String c) { + try { + Class.forName(c); + } catch(Exception e) { + return false; + } + return true; + } + + /** + * This first checks java.vm.version for 1.1, 1.2 or 1.3. + * + * It writes jdbc1 to stdout for the 1.1.x VM. + * + * For 1.2 or 1.3, it checks for the existence of the javax.sql.DataSource + * interface, and if found writes enterprise to stdout. If the interface + * is not found, it writes jdbc2 to stdout. + * + * PS: It also looks for the existence of java.lang.Byte which appeared in + * JDK1.1.0 incase java.vm.version is not heeded by some JVM's. + * + * If it can't work it out, it writes huho to stdout. + * + * The make file uses the written results to determine which rule to run. + * + * Bugs: This needs thorough testing. + */ + public static void main(String args[]) + { + String vmversion = System.getProperty("java.vm.version"); + + // We are running a 1.1 JVM + if(vmversion.startsWith("1.1")) { + System.out.println("jdbc1"); + System.exit(0); + } + + // We are running a 1.2 or 1.3 JVM + if(vmversion.startsWith("1.2") || + vmversion.startsWith("1.3") || + checkClass("java.lang.Byte") + ) { + + // Check to see if we have the standard extensions. If so, then + // we want the enterprise edition, otherwise the jdbc2 driver. + if(checkClass("javax.sql.DataSource")) + System.out.println("enterprise"); + else + System.out.println("jdbc2"); + System.exit(0); + } + + System.out.println("huho"); + System.exit(0); + } +} diff --git a/src/interfaces/jdbc/utils/buildDriver b/src/interfaces/jdbc/utils/buildDriver new file mode 100755 index 0000000000..097ce6e04a --- /dev/null +++ b/src/interfaces/jdbc/utils/buildDriver @@ -0,0 +1,47 @@ +#!/bin/sh +# +# $Id: buildDriver,v 1.1 2000/10/12 08:55:28 peter Exp $ +# +# This script generates the org/postgresql/Driver.java file from the template +# org/postgresql/Driver.java.in +# +# We do this because we need to include the version number from Makefile.global +# and some other goodies. +# +# This used to be in Makefile, but as it's now done three times, it's better +# to have it as a separate script. +# +# If you have any problems, please let us know ;-) +# +# Syntax: buildDriver version class +# +# Where: +# version The version string from Makefile.global +# class The class implementing java.sql.Connection +# edition The driver edition being built +# source The file to build. We assume that ${source}.in exists +# + +VERSION=$1 +CLASS=$2 +EDITION=$3 +SOURCE=$4 + +#--------------------------------------------------------------------------- +# Extract the version. This will work until version x.9 (and assuming we don't +# have 7.10 etc). We only handle 1 digit for MINORVERSION to handle things like +# 7.1devel etc +# +MAJORVERSION=`echo $VERSION | cut -f1 -d'.'` +MINORVERSION=`echo $VERSION | cut -f2 -d'.' | cut -c1` + +#--------------------------------------------------------------------------- +# Now finally build the driver +sed \ + -e "s/%JDBCCONNECTCLASS%/$CLASS/g" \ + -e "s/%VERSION%/$VERSION $EDITION/g" \ + -e "s/%MAJORVERSION%/$MAJORVERSION/g" \ + -e "s/%MINORVERSION%/$MINORVERSION/g" \ + <${SOURCE}.in \ + >$SOURCE +#--------------------------------------------------------------------------- diff --git a/src/interfaces/jdbc/utils/changelog.pl b/src/interfaces/jdbc/utils/changelog.pl new file mode 100644 index 0000000000..3cba15aa91 --- /dev/null +++ b/src/interfaces/jdbc/utils/changelog.pl @@ -0,0 +1,23 @@ +#!/bin/perl + +while(<>) { + chomp(); + s/\t+/ /g; + if(substr($_,0,3) eq ' - ') { + print "
    " if !$inlist; + $inlist=1; + print "
  • ".substr($_,3)."\n"; + } else { + if($_ eq "" || $_ eq " ") { + print "
" if $inlist; + $inlist=0; + print "
\n"; + } elsif(substr($_,0,1) eq " ") { + print $_; + } else { + print "" if $inlist; + $inlist=0; + print "

".$_."

\n"; + } + } +} -- 2.40.0