From 05a966fca4a828413da9d3a9d9492d111e176780 Mon Sep 17 00:00:00 2001
From: Barry Lind <barry@xythos.com>
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 af9830dccaf..c89ad29ec8b 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 179e02c46c1..99e42b5c92c 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 766ce9126db..3216f6bf9d2 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:<pre>
+	 * Table: table ()
+	 * "Table": Table ()
+	 * Schema.Table: table (schema)
+	 * "Schema"."Table": Table (Schema)
+	 * "Schema"."Dot.Table": Dot.Table (Schema)
+	 * Schema."Dot.Table": Dot.Table (schema)
+	 * </pre>
+	 * @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 c718f699a31..3dbf2573021 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 : "";
 	}
 }
-- 
GitLab