From 5af43965cf30f4a0844cca384170a44c7acc6176 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Fri, 7 Nov 1997 21:07:48 +0000 Subject: [PATCH] Update of Java driver from Peter Mount. --- src/interfaces/jdbc/JDBC_Test.java | 138 +++++++++++++----- src/interfaces/jdbc/README | 3 +- .../jdbc/postgresql/Connection.java | 27 +++- src/interfaces/jdbc/postgresql/Driver.java | 24 ++- .../jdbc/postgresql/PreparedStatement.java | 10 +- src/interfaces/jdbc/postgresql/ResultSet.java | 27 +--- .../jdbc/postgresql/ResultSetMetaData.java | 8 +- 7 files changed, 162 insertions(+), 75 deletions(-) diff --git a/src/interfaces/jdbc/JDBC_Test.java b/src/interfaces/jdbc/JDBC_Test.java index 2453e4ca94..c546469358 100644 --- a/src/interfaces/jdbc/JDBC_Test.java +++ b/src/interfaces/jdbc/JDBC_Test.java @@ -10,16 +10,21 @@ class JDBC_Test public static void main(String argv[]) { + if(argv.length<3) { + System.err.println("java JDBC_Test jdbc-url user password [debug]"); + System.exit(1); + } + String url = new String(argv[0]); String usr = new String(argv[1]); String pwd = new String(argv[2]); Connection db; Statement s; - ResultSet rs; // This line outputs debug information to stderr. To enable this, simply - // remove the // - DriverManager.setLogStream(System.err); + // add an extra parameter to the command line + if(argv.length>3) + DriverManager.setLogStream(System.err); // Load the driver try { @@ -31,12 +36,15 @@ class JDBC_Test // Lets do a few things -- it doesn't do everything, but // it tests out basic functionality try { + //---------------------------------------- + // Connect to database System.out.println("Connecting to Database URL = " + url); db = DriverManager.getConnection(url, usr, pwd); System.out.println("Connected...Now creating a statement"); s = db.createStatement(); - // test Date & Warnings + //---------------------------------------- + // test DateStyle & Warnings System.out.println("Ok... now set European date style"); s.executeUpdate("set datestyle='european'"); @@ -49,59 +57,115 @@ class JDBC_Test } db.clearWarnings(); + //---------------------------------------- + // Creating a table System.out.println("Ok...now we will create a table"); s.executeUpdate("create table test (a int2, b int2,c timestamp,d date)"); + //---------------------------------------- + // Simple inserts System.out.println("Now we will insert some columns"); s.executeUpdate("insert into test values (1, 1,'now','now')"); s.executeUpdate("insert into test values (2, 1,'now','01-11-1997')"); // As we are in european, this should mean 1 November 1997 s.executeUpdate("insert into test values (3, 1,'now','11-01-1997')"); // As we are in european, this should mean 11 January 1997 System.out.println("Inserted some data"); + //---------------------------------------- + // Now a select (see seperate method at end) System.out.println("Now lets try a select"); - rs = s.executeQuery("select a, b,c,d from test"); - System.out.println("Back from the select...the following are results"); - System.out.println("row a b c d 'd as string'"); - int i = 0; - while (rs.next()) - { - int a = rs.getInt("a"); // Example of retriving by column name - int b = rs.getInt("b"); - Timestamp c = rs.getTimestamp(3); // Example of by column number - java.sql.Date d = rs.getDate(4); // Note, java.sql.Date here - System.out.println("row " + i + " " + a + " " + b + " " + c + " " + d + " '"+rs.getString(4)+"'"); - i++; - } + select(s,""); - // This is a bug at the moment... when you use set datestyle - // it must be followed by show datestyle - System.out.println("Now switch to US date format"); - s.executeUpdate("set datestyle='US'"); - s.executeUpdate("show datestyle"); - - System.out.println("Now lets try a select"); - rs = s.executeQuery("select a, b,c,d from test"); - System.out.println("Back from the select...the following are results"); - //int i = 0; - System.out.println("row a b c d 'd as string'"); - while (rs.next()) - { - int a = rs.getInt("a"); // Example of retriving by column name - int b = rs.getInt("b"); - Timestamp c = rs.getTimestamp(3); // Example of by column number - java.sql.Date d = rs.getDate(4); // Note, java.sql.Date here - System.out.println("row " + i + " " + a + " " + b + " " + c + " " + d + " '"+rs.getString(4)+"'"); - i++; - } + //---------------------------------------- + // Now run some tests + runTests(db,s); + //---------------------------------------- + // Dropping a table System.out.println("Ok...dropping the table"); s.executeUpdate("drop table test"); + //---------------------------------------- + // Closing the connection System.out.println("Now closing the connection"); s.close(); db.close(); + + //---------------------------------------- } catch (SQLException e) { System.out.println("Exception: " + e.toString()); } } + + /** + * This performs some tests - not really part of an example, hence + * they are in a seperate method. + */ + public static void runTests(Connection db, Statement s) throws SQLException + { + //---------------------------------------- + // This is a bug at the moment... when you use set datestyle + // it must be followed by show datestyle + System.out.println("Now switch to US date format"); + s.executeUpdate("set datestyle='US'"); + s.executeUpdate("show datestyle"); + + System.out.println("Now lets try a select"); + select(s,""); + + //---------------------------------------- + // Inserting dates using PreparedStatement + System.out.println("Ok, now a test using PreparedStatement"); + Date dt = new Date(97,11,1); + PreparedStatement ps = db.prepareStatement("insert into test values (?,?,'now',?)"); + + // first insert in US style + s.executeUpdate("set datestyle='US'"); + s.executeUpdate("show datestyle"); + ps.setInt(1,8); + ps.setInt(2,8); + ps.setDate(3,dt); + ps.executeUpdate(); + + // second insert in European style + s.executeUpdate("set datestyle='european'"); + s.executeUpdate("show datestyle"); + ps.setInt(1,9); + ps.setInt(2,9); + ps.setDate(3,dt); + ps.executeUpdate(); + + System.out.println("Now run the select again - first as European"); + select(s,"where a>7"); + + s.executeUpdate("set datestyle='US'"); + s.executeUpdate("show datestyle"); + System.out.println("Then as US"); + select(s,"where a>7"); + } + + /** + * This performs a select. It's seperate because the tests use it in + * multiple places. + * @param s Statement to run under + * @throws SQLException + */ + public static void select(Statement s,String sql) throws SQLException + { + sql="select a, b,c,d from test "+sql; + System.out.println("\nQuery: "+sql); + ResultSet rs = s.executeQuery(sql); + System.out.println("row a b c d 'd as string'"); + System.out.println("-------------------------------------------------------------------------------"); + int i = 0; + while(rs.next()) { + int a = rs.getInt("a"); // Example of retriving by column name + int b = rs.getInt("b"); + Timestamp c = rs.getTimestamp(3); // Example of by column number + java.sql.Date d = rs.getDate(4); // Note, java.sql.Date here + System.out.println("row " + i + " " + a + " " + b + " " + c + " " + d + " '"+rs.getString(4)+"'"); + i++; + } + rs.close(); + } + } diff --git a/src/interfaces/jdbc/README b/src/interfaces/jdbc/README index bbc105ea8c..cd43a5af2f 100644 --- a/src/interfaces/jdbc/README +++ b/src/interfaces/jdbc/README @@ -121,7 +121,8 @@ or if passing the user & password directly via DriverManager.getConnection(): jdbc:postgresql:database?auth=y -PS: 'y' could be anything, aslong as there is something after the '=' +PS: Password authentication is enabled if the value of auth starts with 'y'. + It is case insensitive. --------------------------------------------------------------------------- diff --git a/src/interfaces/jdbc/postgresql/Connection.java b/src/interfaces/jdbc/postgresql/Connection.java index e79d1fe953..09344e1fe0 100644 --- a/src/interfaces/jdbc/postgresql/Connection.java +++ b/src/interfaces/jdbc/postgresql/Connection.java @@ -36,15 +36,20 @@ public class Connection implements java.sql.Connection private String PG_PASSWORD; private String PG_DATABASE; private boolean PG_STATUS; - private boolean PG_AUTH; // true, then password auth used public boolean CONNECTION_OK = true; public boolean CONNECTION_BAD = false; + private static final int STARTUP_LEN = 288; // Length of a startup packet + + // These are defined in src/include/libpq/pqcomm.h private int STARTUP_CODE = STARTUP_USER; private static final int STARTUP_USER = 7; // User auth + private static final int STARTUP_KRB4 = 10; // Kerberos 4 (unused) + private static final int STARTUP_KRB5 = 11; // Kerberos 5 (unused) + private static final int STARTUP_HBA = 12; // Host Based + private static final int STARTUP_NONE = 13; // Unauthenticated (unused) private static final int STARTUP_PASS = 14; // Password auth - private static final int STARTUP_LEN = 288; // Length of a startup packet private boolean autoCommit = true; private boolean readOnly = false; @@ -84,10 +89,22 @@ public class Connection implements java.sql.Connection PG_HOST = new String(host); PG_STATUS = CONNECTION_BAD; - if(info.getProperty("auth") != null) { - PG_AUTH=true; + // This handles the auth property. Any value begining with p enables + // password authentication, while anything begining with i enables + // ident (RFC 1413) authentication. Any other values default to trust. + // + // Also, the postgresql.auth system property can be used to change the + // local default, if the auth property is not present. + // + String auth = info.getProperty("auth",System.getProperty("postgresql.auth","trust")).toLowerCase(); + if(auth.startsWith("p")) { + // Password authentication STARTUP_CODE=STARTUP_PASS; + } else if(auth.startsWith("i")) { + // Ident (RFC 1413) authentication + STARTUP_CODE=STARTUP_HBA; } else { + // Anything else defaults to trust authentication STARTUP_CODE=STARTUP_USER; } @@ -107,7 +124,7 @@ public class Connection implements java.sql.Connection pg_stream.Send(PG_USER.getBytes(), len); // Send the password packet if required - if(PG_AUTH) { + if(STARTUP_CODE == STARTUP_PASS) { len=STARTUP_LEN; pg_stream.SendInteger(len, 4); len -= 4; pg_stream.SendInteger(STARTUP_PASS, 4); len -= 4; diff --git a/src/interfaces/jdbc/postgresql/Driver.java b/src/interfaces/jdbc/postgresql/Driver.java index 674c96fc66..7b711455ad 100644 --- a/src/interfaces/jdbc/postgresql/Driver.java +++ b/src/interfaces/jdbc/postgresql/Driver.java @@ -27,7 +27,7 @@ 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 = 6; - static final int MINORVERSION = 2; + static final int MINORVERSION = 3; static { @@ -125,8 +125,22 @@ public class Driver implements java.sql.Driver */ public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException { - return null; // We don't need anything except - // the username, which is a default + Properties p = parseURL(url,info); + + // naughty, but its best for speed. If anyone adds a property here, then + // this _MUST_ be increased to accomodate them. + DriverPropertyInfo d,dpi[] = new DriverPropertyInfo[1]; + int i=0; + + dpi[i++] = d = new DriverPropertyInfo("auth",p.getProperty("auth","default")); + d.description = "determines if password authentication is used"; + d.choices = new String[4]; + d.choices[0]="default"; // Get value from postgresql.auth property, defaults to trust + d.choices[1]="trust"; // No password authentication + d.choices[2]="password"; // Password authentication + d.choices[3]="ident"; // Ident (RFC 1413) protocol + + return dpi; } /** @@ -168,6 +182,10 @@ public class Driver implements java.sql.Driver /** * Constructs a new DriverURL, splitting the specified URL into its * component parts + * @param url JDBC URL to parse + * @param defaults Default properties + * @return Properties with elements added from the url + * @throws SQLException */ Properties parseURL(String url,Properties defaults) throws SQLException { diff --git a/src/interfaces/jdbc/postgresql/PreparedStatement.java b/src/interfaces/jdbc/postgresql/PreparedStatement.java index 98fdb6fb10..479f86eee9 100644 --- a/src/interfaces/jdbc/postgresql/PreparedStatement.java +++ b/src/interfaces/jdbc/postgresql/PreparedStatement.java @@ -7,8 +7,8 @@ import java.text.*; import java.util.*; /** - * @version 1.0 15-APR-1997 - * @author Adrian Hall + * @version 6.3 15-APR-1997 + * @author Adrian HallPeter Mount * * A SQL Statement is pre-compiled and stored in a PreparedStatement object. * This object can then be used to efficiently execute this statement multiple @@ -294,9 +294,9 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta */ public void setDate(int parameterIndex, java.sql.Date x) throws SQLException { - DateFormat df = DateFormat.getDateInstance(); - - set(parameterIndex, "'" + df.format(x) + "'"); + SimpleDateFormat df = new SimpleDateFormat(connection.europeanDates?"''dd-MM-yyyy''":"''MM-dd-yyyy''"); + + set(parameterIndex, df.format(x)); } /** diff --git a/src/interfaces/jdbc/postgresql/ResultSet.java b/src/interfaces/jdbc/postgresql/ResultSet.java index b6edf18974..017b0ad292 100644 --- a/src/interfaces/jdbc/postgresql/ResultSet.java +++ b/src/interfaces/jdbc/postgresql/ResultSet.java @@ -374,27 +374,12 @@ public class ResultSet implements java.sql.ResultSet public java.sql.Date getDate(int columnIndex) throws SQLException { String s = getString(columnIndex); - - if (s != null) - { - try { - if (s.length() != 10) - throw new NumberFormatException("Wrong Length!"); - int mon = Integer.parseInt(s.substring(0,2)); - int day = Integer.parseInt(s.substring(3,5)); - int yr = Integer.parseInt(s.substring(6)); - if(connection.europeanDates) { - // We europeans prefer dd mm yyyy - int t = mon; - mon = day; - day = t; - } - return new java.sql.Date(yr - 1900, mon -1, day); - } catch (NumberFormatException e) { - throw new SQLException("Bad Date Form: " + s); - } - } - return null; // SQL NULL + SimpleDateFormat df = new SimpleDateFormat(connection.europeanDates?"dd-MM-yyyy":"MM-dd-yyyy"); + try { + return new java.sql.Date(df.parse(s).getTime()); + } catch (ParseException e) { + throw new SQLException("Bad Date Format: at " + e.getErrorOffset() + " in " + s); + } } /** diff --git a/src/interfaces/jdbc/postgresql/ResultSetMetaData.java b/src/interfaces/jdbc/postgresql/ResultSetMetaData.java index f058e2e0ba..7d2c1ceaf3 100644 --- a/src/interfaces/jdbc/postgresql/ResultSetMetaData.java +++ b/src/interfaces/jdbc/postgresql/ResultSetMetaData.java @@ -190,9 +190,11 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData for (i = 0 ; i < rows.size(); ++i) { byte[][] x = (byte[][])(rows.elementAt(i)); - int xl = x[column - 1].length; - if (xl > max) - max = xl; + if(x[column-1]!=null) { + int xl = x[column - 1].length; + if (xl > max) + max = xl; + } } return max; }