From 05a966fca4a828413da9d3a9d9492d111e176780 Mon Sep 17 00:00:00 2001 From: Barry Lind Date: Sat, 8 Mar 2003 06:06:55 +0000 Subject: [PATCH] Applied patch from Paul Sorenson to correctly handle schema names in updateable result sets. Applied patch from Rich Cullingford to fix a NPE in the absolute() method of result set. Applied patch from Tarjei Skorgenes to fix a NPE when logging is enabled. Modified Files: jdbc/org/postgresql/core/BaseResultSet.java jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java jdbc/org/postgresql/jdbc2/Array.java jdbc/org/postgresql/util/PSQLException.java --- .../org/postgresql/core/BaseResultSet.java | 7 +- .../jdbc1/AbstractJdbc1ResultSet.java | 60 +++++++++++---- .../jdbc2/AbstractJdbc2ResultSet.java | 73 +++++++++++++++---- .../org/postgresql/util/PSQLException.java | 4 +- 4 files changed, 111 insertions(+), 33 deletions(-) diff --git a/src/interfaces/jdbc/org/postgresql/core/BaseResultSet.java b/src/interfaces/jdbc/org/postgresql/core/BaseResultSet.java index af9830dcca..c89ad29ec8 100644 --- a/src/interfaces/jdbc/org/postgresql/core/BaseResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/core/BaseResultSet.java @@ -6,7 +6,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseResultSet.java,v 1.1 2003/03/07 18:39:41 barry Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/core/Attic/BaseResultSet.java,v 1.2 2003/03/08 06:06:55 barry Exp $ * *------------------------------------------------------------------------- */ @@ -16,16 +16,19 @@ package org.postgresql.core; import java.sql.ResultSet; import java.sql.ResultSetMetaData; import java.sql.SQLException; +import java.text.SimpleDateFormat; import java.util.Vector; public interface BaseResultSet { + public BaseStatement getPGStatement(); public void append(BaseResultSet r); public void close() throws SQLException; public int getColumnCount(); public String getCursorName() throws SQLException; + public SimpleDateFormat getDateFormat(); public String getFixedString(int col) throws SQLException; public long getLastOID(); public ResultSetMetaData getMetaData() throws SQLException; @@ -35,6 +38,8 @@ public interface BaseResultSet public String getStatusString(); public String getString(int columnIndex) throws SQLException; public StringBuffer getStringBuffer(); + public SimpleDateFormat getTimestampFormat(); + public SimpleDateFormat getTimestampTZFormat(); public int getTupleCount(); public boolean next() throws SQLException; public boolean reallyResultSet(); diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java index 179e02c46c..99e42b5c92 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc1/AbstractJdbc1ResultSet.java @@ -1,6 +1,20 @@ +/*------------------------------------------------------------------------- + * + * AbstractJdbc1ResultSet.java + * This class defines methods of the jdbc1 specification. This class is + * extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the + * jdbc2 methods. The real ResultSet class (for jdbc1) is + * org.postgresql.jdbc1.Jdbc1ResultSet + * + * Copyright (c) 2003, PostgreSQL Global Development Group + * + * IDENTIFICATION + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.11 2003/03/08 06:06:55 barry Exp $ + * + *------------------------------------------------------------------------- + */ package org.postgresql.jdbc1; - import java.math.BigDecimal; import java.io.*; import java.sql.*; @@ -19,11 +33,6 @@ import org.postgresql.util.PGbytea; import org.postgresql.util.PGtokenizer; import org.postgresql.util.PSQLException; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1ResultSet.java,v 1.10 2003/03/07 18:39:44 barry Exp $ - * This class defines methods of the jdbc1 specification. This class is - * extended by org.postgresql.jdbc2.AbstractJdbc2ResultSet which adds the jdbc2 - * methods. The real ResultSet class (for jdbc1) is org.postgresql.jdbc1.Jdbc1ResultSet - */ public abstract class AbstractJdbc1ResultSet implements BaseResultSet { @@ -47,6 +56,10 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet private StringBuffer sbuf = null; public byte[][] rowBuffer = null; + private SimpleDateFormat m_tsFormat = null; + private SimpleDateFormat m_tstzFormat = null; + private SimpleDateFormat m_dateFormat = null; + public abstract ResultSetMetaData getMetaData() throws SQLException; public AbstractJdbc1ResultSet(BaseStatement statement, @@ -1020,7 +1033,7 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet l_sbuf.append(":00"); // we'll use this dateformat string to parse the result. - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + df = rs.getTimestampTZFormat(); } else { @@ -1029,11 +1042,11 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet if (pgDataType.equals("timestamptz")) { l_sbuf.append(" GMT"); - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + df = rs.getTimestampTZFormat(); } else { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df = rs.getTimestampFormat(); } } } @@ -1044,11 +1057,11 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet if (pgDataType.equals("timestamptz")) { l_sbuf.append(" GMT"); - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + df = rs.getTimestampTZFormat(); } else { - df = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss"); + df = rs.getTimestampFormat(); } } else @@ -1065,7 +1078,7 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet // We must just have a date. This case is // needed if this method is called on a date // column - df = new SimpleDateFormat("yyyy-MM-dd"); + df = rs.getDateFormat(); } try @@ -1075,8 +1088,7 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet Driver.debug("the data after parsing is " + l_sbuf.toString() + " with " + nanos + " nanos"); - Timestamp result = - new Timestamp(df.parse(l_sbuf.toString()).getTime()); + Timestamp result = new Timestamp(df.parse(l_sbuf.toString()).getTime()); result.setNanos(nanos); return result; } @@ -1087,7 +1099,23 @@ public abstract class AbstractJdbc1ResultSet implements BaseResultSet } } - - + public SimpleDateFormat getTimestampTZFormat() { + if (m_tstzFormat == null) { + m_tstzFormat = new SimpleDateFormat("yyyy-MM-dd HH:mm:ss z"); + } + return m_tstzFormat; + } + public SimpleDateFormat getTimestampFormat() { + if (m_tsFormat == null) { + m_tsFormat = new SimpleDateFormat ("yyyy-MM-dd HH:mm:ss"); + } + return m_tsFormat; + } + public SimpleDateFormat getDateFormat() { + if (m_dateFormat == null) { + m_dateFormat = new SimpleDateFormat("yyyy-MM-dd"); + } + return m_dateFormat; + } } diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java index 766ce9126d..3216f6bf9d 100644 --- a/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java +++ b/src/interfaces/jdbc/org/postgresql/jdbc2/AbstractJdbc2ResultSet.java @@ -16,7 +16,7 @@ import org.postgresql.util.PGbytea; import org.postgresql.util.PSQLException; -/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.15 2003/03/07 18:39:45 barry Exp $ +/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc2/Attic/AbstractJdbc2ResultSet.java,v 1.16 2003/03/08 06:06:55 barry Exp $ * This class defines methods of the jdbc2 specification. This class extends * org.postgresql.jdbc1.AbstractJdbc1ResultSet which provides the jdbc1 * methods. The real Statement class (for jdbc2) is org.postgresql.jdbc2.Jdbc2ResultSet @@ -188,6 +188,10 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra current_row = internalIndex; this_row = (byte[][]) rows.elementAt(internalIndex); + + rowBuffer = new byte[this_row.length][]; + System.arraycopy(this_row, 0, rowBuffer, 0, this_row.length); + return true; } @@ -1319,18 +1323,10 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra else { // otherwise go and get the primary keys and create a hashtable of keys - // if the user has supplied a quoted table name - // remove the quotes, but preserve the case. - // otherwise fold to lower case. - String quotelessTableName; - if (tableName.startsWith("\"") && tableName.endsWith("\"")) { - quotelessTableName = tableName.substring(1,tableName.length()-1); - } else { - quotelessTableName = tableName.toLowerCase(); - } - java.sql.ResultSet rs = ((java.sql.Connection) connection).getMetaData().getPrimaryKeys("", "", quotelessTableName); - - + String[] s = quotelessTableName(tableName); + String quotelessTableName = s[0]; + String quotelessSchemaName = s[1]; + java.sql.ResultSet rs = ((java.sql.Connection) connection).getMetaData().getPrimaryKeys("", quotelessSchemaName, quotelessTableName); for (; rs.next(); i++ ) { String columnName = rs.getString(4); // get the columnName @@ -1363,7 +1359,56 @@ public abstract class AbstractJdbc2ResultSet extends org.postgresql.jdbc1.Abstra return updateable; } - + /** Cracks out the table name and schema (if it exists) from a fully + * qualified table name. + * @param fullname string that we are trying to crack. Test cases:
+	 * Table: table ()
+	 * "Table": Table ()
+	 * Schema.Table: table (schema)
+	 * "Schema"."Table": Table (Schema)
+	 * "Schema"."Dot.Table": Dot.Table (Schema)
+	 * Schema."Dot.Table": Dot.Table (schema)
+	 * 
+ * @return String array with element zero always being the tablename and + * element 1 the schema name which may be a zero length string. + */ + public static String[] quotelessTableName(String fullname) { + StringBuffer buf = new StringBuffer(fullname); + String[] parts = new String[] {null, ""}; + StringBuffer acc = new StringBuffer(); + boolean betweenQuotes = false; + for (int i = 0; i < buf.length(); i++) { + char c = buf.charAt(i); + switch (c) { + case '"': + if ((i < buf.length() - 1) && (buf.charAt(i+1) == '"')) { + // two consecutive quotes - keep one + i++; + acc.append(c); // keep the quote + } + else { // Discard it + betweenQuotes = !betweenQuotes; + } + break; + case '.': + if (betweenQuotes) { // Keep it + acc.append(c); + } + else { // Have schema name + parts[1] = acc.toString(); + acc = new StringBuffer(); + } + break; + default: + acc.append((betweenQuotes) ? c : Character.toLowerCase(c)); + break; + } + } + // Always put table in slot 0 + parts[0] = acc.toString(); + return parts; + } + public void parseQuery() { String[] l_sqlFragments = ((AbstractJdbc2Statement)statement).getSqlFragments(); diff --git a/src/interfaces/jdbc/org/postgresql/util/PSQLException.java b/src/interfaces/jdbc/org/postgresql/util/PSQLException.java index c718f699a3..3dbf257302 100644 --- a/src/interfaces/jdbc/org/postgresql/util/PSQLException.java +++ b/src/interfaces/jdbc/org/postgresql/util/PSQLException.java @@ -7,7 +7,7 @@ * Copyright (c) 2003, PostgreSQL Global Development Group * * IDENTIFICATION - * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/util/Attic/PSQLException.java,v 1.9 2003/03/07 18:39:46 barry Exp $ + * $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/util/Attic/PSQLException.java,v 1.10 2003/03/08 06:06:55 barry Exp $ * *------------------------------------------------------------------------- */ @@ -122,6 +122,6 @@ public class PSQLException extends SQLException */ public String toString() { - return message; + return message != null ? message : ""; } } -- 2.40.0