From 0e583068579748ad528685fa6040636b374177c6 Mon Sep 17 00:00:00 2001 From: Bruce Momjian Date: Thu, 30 Oct 1997 18:24:44 +0000 Subject: [PATCH] Fix for java to allow password, european dates,from Peter T Mount --- src/interfaces/jdbc/JDBC_Test.java | 146 ++++++++++++------ src/interfaces/jdbc/README | 42 ++++- .../jdbc/postgresql/Connection.java | 77 ++++++++- src/interfaces/jdbc/postgresql/ResultSet.java | 48 +++--- 4 files changed, 237 insertions(+), 76 deletions(-) diff --git a/src/interfaces/jdbc/JDBC_Test.java b/src/interfaces/jdbc/JDBC_Test.java index 30cda33304..2453e4ca94 100644 --- a/src/interfaces/jdbc/JDBC_Test.java +++ b/src/interfaces/jdbc/JDBC_Test.java @@ -4,58 +4,104 @@ import java.sql.*; class JDBC_Test { - public JDBC_Test() + public JDBC_Test() + { + } + + public static void main(String argv[]) + { + 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); + + // Load the driver + try { + Class.forName("postgresql.Driver"); + } catch (ClassNotFoundException e) { + System.err.println("Exception: " + e.toString()); + } + + // Lets do a few things -- it doesn't do everything, but + // it tests out basic functionality + try { + 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 + System.out.println("Ok... now set European date style"); + s.executeUpdate("set datestyle='european'"); + + System.out.println("and see what style we are now using (handled by warnings)"); + s.executeUpdate("show datestyle"); + SQLWarning sw = db.getWarnings(); + while(sw!=null) { + System.out.println("--> "+sw.getMessage()); + sw=sw.getNextWarning(); + } + db.clearWarnings(); + + System.out.println("Ok...now we will create a table"); + s.executeUpdate("create table test (a int2, b int2,c timestamp,d date)"); + + 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"); + + 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++; } - - public static void main(String argv[]) + + // 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()) { - String url = new String(argv[0]); - Connection db; - Statement s; - ResultSet rs; - - // Load the driver - try - { - Class.forName("postgresql.Driver"); - } catch (ClassNotFoundException e) { - System.err.println("Exception: " + e.toString()); - } - - // Lets do a few things -- it doesn't do everything, but - // it tests out basic functionality - try - { - System.out.println("Connecting to Database URL = " + url); - db = DriverManager.getConnection(url, "adrian", ""); - System.out.println("Connected...Now creating a statement"); - s = db.createStatement(); - System.out.println("Ok...now we will create a table"); - s.executeUpdate("create table test (a int2, b int2)"); - System.out.println("Now we will insert some columns"); - s.executeUpdate("insert into test values (1, 1)"); - s.executeUpdate("insert into test values (2, 1)"); - s.executeUpdate("insert into test values (3, 1)"); - System.out.println("Inserted some data"); - System.out.println("Now lets try a select"); - rs = s.executeQuery("select a, b from test"); - System.out.println("Back from the select...the following are results"); - int i = 0; - while (rs.next()) - { - int a = rs.getInt("a"); - int b = rs.getInt("b"); - System.out.println("row " + i + " " + a + " " + b); - i++; - } - System.out.println("Ok...dropping the table"); - s.executeUpdate("drop table test"); - System.out.println("Now closing the connection"); - s.close(); - db.close(); - } catch (SQLException e) { - System.out.println("Exception: " + e.toString()); - } + 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++; } + + System.out.println("Ok...dropping the table"); + s.executeUpdate("drop table test"); + + System.out.println("Now closing the connection"); + s.close(); + db.close(); + } catch (SQLException e) { + System.out.println("Exception: " + e.toString()); + } + } } diff --git a/src/interfaces/jdbc/README b/src/interfaces/jdbc/README index 465331ab23..bbc105ea8c 100644 --- a/src/interfaces/jdbc/README +++ b/src/interfaces/jdbc/README @@ -112,6 +112,17 @@ them to the URL. eg: jdbc:postgresql:database?user=me jdbc:postgresql:database?user=me&password=mypass +By default, the driver doesn't use password authentication. You can enable +this by adding the argument auth. ie: + + jdbc:postgresql:database?user=me&password=mypass&auth=y + +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 '=' + --------------------------------------------------------------------------- That's the basics related to this driver. You'll need to read the JDBC Docs @@ -120,6 +131,34 @@ on how to use it. POSTGRESQL SPECIFICS -------------------- +Date datatype: + +The driver now supports US and European date styles (although it is currently +limited to postgres format). + +Basically the US like to format their dates as mm-dd-yyyy, while in Europe, +we like to use dd-mm-yyyy. Postgres supports this by the DateStyle variable. +From psql, you can issue "set datestyle='european';" to set european style, +and "set datestyle='us';" to set the US format. You can see what the current +value for this with "show datestyle;". + +The driver now issues the "show datestyle;" query when it first connects, so +any call to ResultSet.getDate() how returns the correct date. + +One caveat though: if you change the datestyle from within JDBC, you must also +issue the "show datestyle" query. Without this, the driver will not know of +the change. + +ie: + Statement s = db.createStatement(); + ... + s.executeUpdate("set datestyle='european'"); + s.executeUpdate("show datestyle"); + .. + s.close(); + + ------------------ + JDBC supports database specific data types using the getObject() call. The following types have their own Java equivalents supplied by the driver: @@ -140,9 +179,10 @@ syntax for writing these to the database. --------------------------------------------------------------------------- -Peter T Mount, August 30 1997 +Peter T Mount, October 28 1997 home email: pmount@maidast.demon.co.uk http://www.demon.co.uk/finder work email: peter@maidstone.gov.uk http://www.maidstone.gov.uk Adrian Hall email: adrian@hottub.org + diff --git a/src/interfaces/jdbc/postgresql/Connection.java b/src/interfaces/jdbc/postgresql/Connection.java index bb41dff01b..e79d1fe953 100644 --- a/src/interfaces/jdbc/postgresql/Connection.java +++ b/src/interfaces/jdbc/postgresql/Connection.java @@ -36,11 +36,15 @@ 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 int STARTUP_CODE = 7; + private int STARTUP_CODE = STARTUP_USER; + private static final int STARTUP_USER = 7; // User auth + 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; @@ -49,6 +53,12 @@ public class Connection implements java.sql.Connection private String this_url; private String cursor = null; // The positioned update cursor name + // This is false for US, true for European date formats + protected boolean europeanDates = false; + + // Now handle notices as warnings, so things like "show" now work + protected SQLWarning firstWarning = null; + /** * Connect to a PostgreSQL database back end. * @@ -63,7 +73,7 @@ public class Connection implements java.sql.Connection */ public Connection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException { - int len = 288; // Length of a startup packet + int len = STARTUP_LEN; // Length of a startup packet this_driver = d; this_url = new String(url); @@ -74,6 +84,13 @@ public class Connection implements java.sql.Connection PG_HOST = new String(host); PG_STATUS = CONNECTION_BAD; + if(info.getProperty("auth") != null) { + PG_AUTH=true; + STARTUP_CODE=STARTUP_PASS; + } else { + STARTUP_CODE=STARTUP_USER; + } + try { pg_stream = new PG_Stream(host, port); @@ -88,10 +105,34 @@ public class Connection implements java.sql.Connection pg_stream.SendInteger(STARTUP_CODE, 4); len -= 4; pg_stream.Send(database.getBytes(), 64); len -= 64; pg_stream.Send(PG_USER.getBytes(), len); + + // Send the password packet if required + if(PG_AUTH) { + len=STARTUP_LEN; + pg_stream.SendInteger(len, 4); len -= 4; + pg_stream.SendInteger(STARTUP_PASS, 4); len -= 4; + pg_stream.Send(PG_USER.getBytes(), PG_USER.length()); + len-=PG_USER.length(); + pg_stream.SendInteger(0,1); len -= 1; + pg_stream.Send(PG_PASSWORD.getBytes(), len); + } + } catch (IOException e) { throw new SQLException("Connection failed: " + e.toString()); } - ExecSQL(" "); // Test connection + + // Find out the date style by issuing the SQL: show datestyle + // This actually issues a warning, and our own warning handling + // code handles this itself. + // + // Also, this query replaced the NULL query issued to test the + // connection. + // + clearWarnings(); + ExecSQL("show datestyle"); + + // Mark the connection as ok, and cleanup + clearWarnings(); PG_STATUS = CONNECTION_OK; } @@ -391,7 +432,7 @@ public class Connection implements java.sql.Connection */ public SQLWarning getWarnings() throws SQLException { - return null; // We handle warnings as errors + return firstWarning; } /** @@ -402,13 +443,36 @@ public class Connection implements java.sql.Connection */ public void clearWarnings() throws SQLException { - // Not handles since we handle wanrings as errors + firstWarning = null; } // ********************************************************** // END OF PUBLIC INTERFACE // ********************************************************** + /** + * This adds a warning to the warning chain + */ + public void addWarning(String msg) + { + // Add the warning to the chain + if(firstWarning!=null) + firstWarning.setNextWarning(new SQLWarning(msg)); + else + firstWarning = new SQLWarning(msg); + + // Now check for some specific messages + + // This is generated by the SQL "show datestyle" + if(msg.startsWith("NOTICE:DateStyle")) { + if(msg.indexOf("with US")==-1) + europeanDates=true; + else + europeanDates=false; + System.err.println("europeanDates="+europeanDates); + } + } + /** * Send a query to the backend. Returns one of the ResultSet * objects. @@ -497,7 +561,8 @@ public class Connection implements java.sql.Connection case 'N': // Error Notification msg = pg_stream.ReceiveString(4096); PrintStream log = DriverManager.getLogStream(); - log.println(msg); + if(log!=null) log.println(msg); + addWarning(msg); break; case 'P': // Portal Name String pname = pg_stream.ReceiveString(8192); diff --git a/src/interfaces/jdbc/postgresql/ResultSet.java b/src/interfaces/jdbc/postgresql/ResultSet.java index d9222ee8ea..b6edf18974 100644 --- a/src/interfaces/jdbc/postgresql/ResultSet.java +++ b/src/interfaces/jdbc/postgresql/ResultSet.java @@ -377,17 +377,22 @@ public class ResultSet implements java.sql.ResultSet 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)); - return new java.sql.Date(yr - 1900, mon -1, day); - } catch (NumberFormatException e) { - throw new SQLException("Bad Date Form: " + s); + 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 } @@ -432,19 +437,24 @@ public class ResultSet implements java.sql.ResultSet public Timestamp getTimestamp(int columnIndex) throws SQLException { String s = getString(columnIndex); - DateFormat df = DateFormat.getDateInstance(); + SimpleDateFormat df = new SimpleDateFormat("yyyy-MM-dd HH:mm:sszzz"); if (s != null) { - try - { - java.sql.Date d = (java.sql.Date)df.parse(s); - return new Timestamp(d.getTime()); - } catch (ParseException e) { - throw new SQLException("Bad Timestamp Format: " + s); - } + int TZ = new Float(s.substring(19)).intValue(); + TZ = TZ * 60 * 60 * 1000; + TimeZone zone = TimeZone.getDefault(); + zone.setRawOffset(TZ); + String nm = zone.getID(); + s = s.substring(0,18) + nm; + try { + java.util.Date d = df.parse(s); + return new Timestamp(d.getTime()); + } catch (ParseException e) { + throw new SQLException("Bad Timestamp Format: at " + e.getErrorOffset() + " in " + s); + } } - return null; // SQL NULL + return null; // SQL NULL } /**