diff --git a/src/interfaces/jdbc/org/postgresql/Connection.java b/src/interfaces/jdbc/org/postgresql/Connection.java
index fc03116f43c..aba2849171c 100644
--- a/src/interfaces/jdbc/org/postgresql/Connection.java
+++ b/src/interfaces/jdbc/org/postgresql/Connection.java
@@ -11,7 +11,7 @@ import org.postgresql.util.*;
import org.postgresql.core.*;
/**
- * $Id: Connection.java,v 1.28 2001/09/07 22:17:02 momjian Exp $
+ * $Id: Connection.java,v 1.29 2001/09/10 15:07:05 momjian Exp $
*
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
* JDBC2 versions of the Connection class.
@@ -22,15 +22,13 @@ public abstract class Connection
// This is the network stream associated with this connection
public PG_Stream pg_stream;
- // This is set by org.postgresql.Statement.setMaxRows()
- //public int maxrows = 0; // maximum no. of rows; 0 = unlimited
-
private String PG_HOST;
private int PG_PORT;
private String PG_USER;
private String PG_PASSWORD;
private String PG_DATABASE;
private boolean PG_STATUS;
+ private String compatible;
/**
* The encoding to use for this connection.
@@ -123,6 +121,11 @@ public abstract class Connection
PG_PORT = port;
PG_HOST = host;
PG_STATUS = CONNECTION_BAD;
+ if(info.getProperty("compatible")==null) {
+ compatible = d.getMajorVersion() + "." + d.getMinorVersion();
+ } else {
+ compatible = info.getProperty("compatible");
+ }
// Now make the initial connection
try
@@ -968,6 +971,23 @@ public abstract class Connection
return (getDBVersionNumber().compareTo(ver) >= 0);
}
+ /**
+ * This method returns true if the compatible level set in the connection
+ * (which can be passed into the connection or specified in the URL)
+ * is at least the value passed to this method. This is used to toggle
+ * between different functionality as it changes across different releases
+ * of the jdbc driver code. The values here are versions of the jdbc client
+ * and not server versions. For example in 7.1 get/setBytes worked on
+ * LargeObject values, in 7.2 these methods were changed to work on bytea
+ * values. This change in functionality could be disabled by setting the
+ * "compatible" level to be 7.1, in which case the driver will revert to
+ * the 7.1 functionality.
+ */
+ public boolean haveMinimumCompatibleVersion(String ver) throws SQLException
+ {
+ return (compatible.compareTo(ver) >= 0);
+ }
+
/**
* This returns the java.sql.Types type for a PG type oid
diff --git a/src/interfaces/jdbc/org/postgresql/Driver.java.in b/src/interfaces/jdbc/org/postgresql/Driver.java.in
index c243a2f284f..a0d5c6e70b6 100644
--- a/src/interfaces/jdbc/org/postgresql/Driver.java.in
+++ b/src/interfaces/jdbc/org/postgresql/Driver.java.in
@@ -85,12 +85,26 @@ public class Driver implements java.sql.Driver
* database.
*
*
The java.util.Properties argument can be used to pass arbitrary
- * string tag/value pairs as connection arguments. Normally, at least
+ * string tag/value pairs as connection arguments.
+ *
+ * user - (optional) The user to connect as
+ * password - (optional) The password for the user
+ * charSet - (optional) The character set to be used for converting
+ * to/from the database to unicode. If multibyte is enabled on the
+ * server then the character set of the database is used as the default,
+ * otherwise the jvm character encoding is used as the default.
+ * compatible - This is used to toggle
+ * between different functionality as it changes across different releases
+ * of the jdbc driver code. The values here are versions of the jdbc
+ * client and not server versions. For example in 7.1 get/setBytes
+ * worked on LargeObject values, in 7.2 these methods were changed
+ * to work on bytea values. This change in functionality could
+ * be disabled by setting the compatible level to be "7.1", in
+ * which case the driver will revert to the 7.1 functionality.
+ *
+ *
Normally, at least
* "user" and "password" properties should be included in the
- * properties. In addition, the "charSet" property can be used to
- * set a character set encoding (e.g. "utf-8") other than the platform
- * default (typically Latin1). This is necessary in particular if storing
- * multibyte characters in the database. For a list of supported
+ * properties. For a list of supported
* character encoding , see
* http://java.sun.com/products/jdk/1.2/docs/guide/internat/encoding.doc.html
* Note that you will probably want to have set up the Postgres database
diff --git a/src/interfaces/jdbc/org/postgresql/ResultSet.java b/src/interfaces/jdbc/org/postgresql/ResultSet.java
index bea07e639b1..8757d21c7ec 100644
--- a/src/interfaces/jdbc/org/postgresql/ResultSet.java
+++ b/src/interfaces/jdbc/org/postgresql/ResultSet.java
@@ -192,7 +192,8 @@ public abstract class ResultSet
String s = getString(col);
// Handle SQL Null
- if(s==null)
+ wasNullFlag = (this_row[col - 1] == null);
+ if(wasNullFlag)
return null;
// Handle Money
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java
index cf2b4bfd29f..814d693df5b 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/Connection.java
@@ -17,7 +17,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/**
- * $Id: Connection.java,v 1.9 2001/09/06 03:13:34 momjian Exp $
+ * $Id: Connection.java,v 1.10 2001/09/10 15:07:05 momjian Exp $
*
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
@@ -174,6 +174,7 @@ public class Connection extends org.postgresql.Connection implements java.sql.Co
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
+ "bytea",
"bool",
"date",
"time",
@@ -197,6 +198,7 @@ public class Connection extends org.postgresql.Connection implements java.sql.Co
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
+ Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java
index b2b68d50a55..0c850e36ea0 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc1/PreparedStatement.java
@@ -82,7 +82,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* A Prepared SQL query is executed and its ResultSet is returned
*
* @return a ResultSet that contains the data produced by the
- * query - never null
+ * * query - never null
* @exception SQLException if a database access error occurs
*/
public java.sql.ResultSet executeQuery() throws SQLException
@@ -107,7 +107,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* be executed.
*
* @return either the row count for INSERT, UPDATE or DELETE; or
- * 0 for SQL statements that return nothing.
+ * * 0 for SQL statements that return nothing.
* @exception SQLException if a database access error occurs
*/
public int executeUpdate() throws SQLException
@@ -294,12 +294,22 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setBytes(int parameterIndex, byte x[]) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports the bytea datatype for byte arrays
+ if(null == x){
+ setNull(parameterIndex,Types.OTHER);
+ } else {
+ setString(parameterIndex, PGbytea.toPGString(x));
+ }
+ } else {
+ //Version 7.1 and earlier support done as LargeObjects
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
lob.write(x);
lob.close();
setInt(parameterIndex,oid);
+ }
}
/**
@@ -386,8 +396,29 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large String values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long varchar datatype, but with toast all text datatypes are capable of
+ //handling very large values. Thus the implementation ends up calling
+ //setString() since there is no current way to stream the value to the server
+ try {
+ InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
+ char[] l_chars = new char[length];
+ int l_charsRead = l_inStream.read(l_chars,0,length);
+ setString(parameterIndex, new String(l_chars,0,l_charsRead));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual",l_uee);
+ } catch (IOException l_ioe) {
+ throw new PSQLException("postgresql.unusual",l_ioe);
+ }
+ } else {
+ //Version 7.1 supported only LargeObjects by treating everything
+ //as binary data
setBinaryStream(parameterIndex, x, length);
}
+ }
/**
* When a very large Unicode value is input to a LONGVARCHAR parameter,
@@ -406,8 +437,29 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large String values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long varchar datatype, but with toast all text datatypes are capable of
+ //handling very large values. Thus the implementation ends up calling
+ //setString() since there is no current way to stream the value to the server
+ try {
+ InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
+ char[] l_chars = new char[length];
+ int l_charsRead = l_inStream.read(l_chars,0,length);
+ setString(parameterIndex, new String(l_chars,0,l_charsRead));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual",l_uee);
+ } catch (IOException l_ioe) {
+ throw new PSQLException("postgresql.unusual",l_ioe);
+ }
+ } else {
+ //Version 7.1 supported only LargeObjects by treating everything
+ //as binary data
setBinaryStream(parameterIndex, x, length);
}
+ }
/**
* When a very large binary value is input to a LONGVARBINARY parameter,
@@ -425,7 +477,54 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
{
- throw org.postgresql.Driver.notImplemented();
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports BinaryStream for for the PG bytea type
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
+ //long binary datatype, but with toast the bytea datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //setBytes() since there is no current way to stream the value to the server
+ byte[] l_bytes = new byte[length];
+ int l_bytesRead;
+ try {
+ l_bytesRead = x.read(l_bytes,0,length);
+ } catch (IOException l_ioe) {
+ throw new PSQLException("postgresql.unusual",l_ioe);
+ }
+ if (l_bytesRead == length) {
+ setBytes(parameterIndex, l_bytes);
+ } else {
+ //the stream contained less data than they said
+ byte[] l_bytes2 = new byte[l_bytesRead];
+ System.arraycopy(l_bytes,0,l_bytes2,0,l_bytesRead);
+ setBytes(parameterIndex, l_bytes2);
+ }
+ } else {
+ //Version 7.1 only supported streams for LargeObjects
+ //but the jdbc spec indicates that streams should be
+ //available for LONGVARBINARY instead
+ LargeObjectManager lom = connection.getLargeObjectAPI();
+ int oid = lom.create();
+ LargeObject lob = lom.open(oid);
+ OutputStream los = lob.getOutputStream();
+ try {
+ // could be buffered, but then the OutputStream returned by LargeObject
+ // is buffered internally anyhow, so there would be no performance
+ // boost gained, if anything it would be worse!
+ int c=x.read();
+ int p=0;
+ while(c>-1 && p fields.length)
throw new PSQLException("postgresql.res.colrange");
- wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports the bytea datatype for byte arrays
+ return PGbytea.toBytes(getString(columnIndex));
+ } else {
+ //Version 7.1 and earlier supports LargeObjects for byte arrays
+ wasNullFlag = (this_row[columnIndex - 1] == null);
// Handle OID's as BLOBS
- if(!wasNullFlag)
+ if(!wasNullFlag) {
if( fields[columnIndex - 1].getOID() == 26) {
LargeObjectManager lom = connection.getLargeObjectAPI();
LargeObject lob = lom.open(getInt(columnIndex));
@@ -385,8 +390,9 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
lob.close();
return buf;
}
-
- return this_row[columnIndex - 1];
+ }
+ }
+ return null;
}
/**
@@ -545,8 +551,27 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
*/
public InputStream getAsciiStream(int columnIndex) throws SQLException
{
+ wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (wasNullFlag)
+ return null;
+
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all the PG text types
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long string datatype, but with toast the text datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getString() since there is no current way to stream the value from the server
+ try {
+ return new ByteArrayInputStream(getString(columnIndex).getBytes("ASCII"));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual", l_uee);
+ }
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
return getBinaryStream(columnIndex);
}
+ }
/**
* A column value can also be retrieved as a stream of Unicode
@@ -562,8 +587,27 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
*/
public InputStream getUnicodeStream(int columnIndex) throws SQLException
{
+ wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (wasNullFlag)
+ return null;
+
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all the PG text types
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long string datatype, but with toast the text datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getString() since there is no current way to stream the value from the server
+ try {
+ return new ByteArrayInputStream(getString(columnIndex).getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual", l_uee);
+ }
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
return getBinaryStream(columnIndex);
}
+ }
/**
* A column value can also be retrieved as a binary strea. This
@@ -579,11 +623,29 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
*/
public InputStream getBinaryStream(int columnIndex) throws SQLException
{
- byte b[] = getBytes(columnIndex);
+ wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (wasNullFlag)
+ return null;
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports BinaryStream for all PG bytea type
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
+ //long binary datatype, but with toast the bytea datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getBytes() since there is no current way to stream the value from the server
+ byte b[] = getBytes(columnIndex);
if (b != null)
return new ByteArrayInputStream(b);
- return null; // SQL NULL
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
+ if( fields[columnIndex - 1].getOID() == 26) {
+ LargeObjectManager lom = connection.getLargeObjectAPI();
+ LargeObject lob = lom.open(getInt(columnIndex));
+ return lob.getInputStream();
+ }
+ }
+ return null;
}
/**
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java b/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java
index f705693983c..9aa98cdbb62 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/Connection.java
@@ -17,7 +17,7 @@ import org.postgresql.largeobject.*;
import org.postgresql.util.*;
/**
- * $Id: Connection.java,v 1.11 2001/09/06 03:13:34 momjian Exp $
+ * $Id: Connection.java,v 1.12 2001/09/10 15:07:05 momjian Exp $
*
* A Connection represents a session with a specific database. Within the
* context of a Connection, SQL statements are executed and results are
@@ -291,12 +291,15 @@ public class Connection extends org.postgresql.Connection implements java.sql.Co
"float8",
"bpchar","char","char2","char4","char8","char16",
"varchar","text","name","filename",
+ "bytea",
"bool",
"date",
"time",
"abstime","timestamp",
- "_bool", "_char", "_int2", "_int4", "_text", "_oid", "_varchar", "_int8",
- "_float4", "_float8", "_abstime", "_date", "_time", "_timestamp", "_numeric"
+ "_bool", "_char", "_int2", "_int4", "_text",
+ "_oid", "_varchar", "_int8", "_float4", "_float8",
+ "_abstime", "_date", "_time", "_timestamp", "_numeric",
+ "_bytea"
};
/**
@@ -316,12 +319,15 @@ public class Connection extends org.postgresql.Connection implements java.sql.Co
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,
Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,Types.VARCHAR,
+ Types.BINARY,
Types.BIT,
Types.DATE,
Types.TIME,
Types.TIMESTAMP,Types.TIMESTAMP,
- Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
- Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY
+ Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
+ Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
+ Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY, Types.ARRAY,
+ Types.ARRAY
};
diff --git a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java
index aabb4923097..16b07ab5b66 100644
--- a/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java
+++ b/src/interfaces/jdbc/org/postgresql/jdbc2/PreparedStatement.java
@@ -91,7 +91,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* A Prepared SQL query is executed and its ResultSet is returned
*
* @return a ResultSet that contains the data produced by the
- * query - never null
+ * * query - never null
* @exception SQLException if a database access error occurs
*/
public java.sql.ResultSet executeQuery() throws SQLException
@@ -105,7 +105,7 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
* be executed.
*
* @return either the row count for INSERT, UPDATE or DELETE; or
- * 0 for SQL statements that return nothing.
+ * * 0 for SQL statements that return nothing.
* @exception SQLException if a database access error occurs
*/
public int executeUpdate() throws SQLException
@@ -305,12 +305,22 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setBytes(int parameterIndex, byte x[]) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports the bytea datatype for byte arrays
+ if(null == x){
+ setNull(parameterIndex,Types.OTHER);
+ } else {
+ setString(parameterIndex, PGbytea.toPGString(x));
+ }
+ } else {
+ //Version 7.1 and earlier support done as LargeObjects
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
lob.write(x);
lob.close();
setInt(parameterIndex,oid);
+ }
}
/**
@@ -413,8 +423,29 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setAsciiStream(int parameterIndex, InputStream x, int length) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large String values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long varchar datatype, but with toast all text datatypes are capable of
+ //handling very large values. Thus the implementation ends up calling
+ //setString() since there is no current way to stream the value to the server
+ try {
+ InputStreamReader l_inStream = new InputStreamReader(x, "ASCII");
+ char[] l_chars = new char[length];
+ int l_charsRead = l_inStream.read(l_chars,0,length);
+ setString(parameterIndex, new String(l_chars,0,l_charsRead));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual",l_uee);
+ } catch (IOException l_ioe) {
+ throw new PSQLException("postgresql.unusual",l_ioe);
+ }
+ } else {
+ //Version 7.1 supported only LargeObjects by treating everything
+ //as binary data
setBinaryStream(parameterIndex, x, length);
}
+ }
/**
* When a very large Unicode value is input to a LONGVARCHAR parameter,
@@ -436,8 +467,29 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setUnicodeStream(int parameterIndex, InputStream x, int length) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large String values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long varchar datatype, but with toast all text datatypes are capable of
+ //handling very large values. Thus the implementation ends up calling
+ //setString() since there is no current way to stream the value to the server
+ try {
+ InputStreamReader l_inStream = new InputStreamReader(x, "UTF-8");
+ char[] l_chars = new char[length];
+ int l_charsRead = l_inStream.read(l_chars,0,length);
+ setString(parameterIndex, new String(l_chars,0,l_charsRead));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual",l_uee);
+ } catch (IOException l_ioe) {
+ throw new PSQLException("postgresql.unusual",l_ioe);
+ }
+ } else {
+ //Version 7.1 supported only LargeObjects by treating everything
+ //as binary data
setBinaryStream(parameterIndex, x, length);
}
+ }
/**
* When a very large binary value is input to a LONGVARBINARY parameter,
@@ -455,6 +507,32 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
*/
public void setBinaryStream(int parameterIndex, InputStream x, int length) throws SQLException
{
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports BinaryStream for for the PG bytea type
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
+ //long binary datatype, but with toast the bytea datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //setBytes() since there is no current way to stream the value to the server
+ byte[] l_bytes = new byte[length];
+ int l_bytesRead;
+ try {
+ l_bytesRead = x.read(l_bytes,0,length);
+ } catch (IOException l_ioe) {
+ throw new PSQLException("postgresql.unusual",l_ioe);
+ }
+ if (l_bytesRead == length) {
+ setBytes(parameterIndex, l_bytes);
+ } else {
+ //the stream contained less data than they said
+ byte[] l_bytes2 = new byte[l_bytesRead];
+ System.arraycopy(l_bytes,0,l_bytes2,0,l_bytesRead);
+ setBytes(parameterIndex, l_bytes2);
+ }
+ } else {
+ //Version 7.1 only supported streams for LargeObjects
+ //but the jdbc spec indicates that streams should be
+ //available for LONGVARBINARY instead
LargeObjectManager lom = connection.getLargeObjectAPI();
int oid = lom.create();
LargeObject lob = lom.open(oid);
@@ -472,11 +550,12 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
}
los.close();
} catch(IOException se) {
- throw new PSQLException("postgresql.prep.is",se);
+ throw new PSQLException("postgresql.unusual",se);
}
// lob is closed by the stream so don't call lob.close()
setInt(parameterIndex,oid);
}
+ }
/**
* In general, parameter values remain in force for repeated used of a
@@ -728,11 +807,33 @@ public class PreparedStatement extends Statement implements java.sql.PreparedSta
}
/**
- * Sets a Blob - basically its similar to setBinaryStream()
+ * Sets a Blob
*/
public void setBlob(int i,Blob x) throws SQLException
{
- setBinaryStream(i,x.getBinaryStream(),(int)x.length());
+ InputStream l_inStream = x.getBinaryStream();
+ int l_length = (int) x.length();
+ LargeObjectManager lom = connection.getLargeObjectAPI();
+ int oid = lom.create();
+ LargeObject lob = lom.open(oid);
+ OutputStream los = lob.getOutputStream();
+ try {
+ // could be buffered, but then the OutputStream returned by LargeObject
+ // is buffered internally anyhow, so there would be no performance
+ // boost gained, if anything it would be worse!
+ int c=l_inStream.read();
+ int p=0;
+ while(c>-1 && p-1 && p fields.length)
throw new PSQLException("postgresql.res.colrange");
- wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports the bytea datatype for byte arrays
+ return PGbytea.toBytes(getString(columnIndex));
+ } else {
+ //Version 7.1 and earlier supports LargeObjects for byte arrays
+ wasNullFlag = (this_row[columnIndex - 1] == null);
// Handle OID's as BLOBS
- if(!wasNullFlag)
+ if(!wasNullFlag) {
if( fields[columnIndex - 1].getOID() == 26) {
LargeObjectManager lom = connection.getLargeObjectAPI();
LargeObject lob = lom.open(getInt(columnIndex));
@@ -323,8 +328,9 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
lob.close();
return buf;
}
-
- return this_row[columnIndex - 1];
+ }
+ }
+ return null;
}
/**
@@ -392,8 +398,27 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
*/
public InputStream getAsciiStream(int columnIndex) throws SQLException
{
+ wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (wasNullFlag)
+ return null;
+
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all the PG text types
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long string datatype, but with toast the text datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getString() since there is no current way to stream the value from the server
+ try {
+ return new ByteArrayInputStream(getString(columnIndex).getBytes("ASCII"));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual", l_uee);
+ }
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
return getBinaryStream(columnIndex);
}
+ }
/**
* A column value can also be retrieved as a stream of Unicode
@@ -412,8 +437,27 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
*/
public InputStream getUnicodeStream(int columnIndex) throws SQLException
{
+ wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (wasNullFlag)
+ return null;
+
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all the PG text types
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long string datatype, but with toast the text datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getString() since there is no current way to stream the value from the server
+ try {
+ return new ByteArrayInputStream(getString(columnIndex).getBytes("UTF-8"));
+ } catch (UnsupportedEncodingException l_uee) {
+ throw new PSQLException("postgresql.unusual", l_uee);
+ }
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
return getBinaryStream(columnIndex);
}
+ }
/**
* A column value can also be retrieved as a binary strea. This
@@ -429,20 +473,29 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
*/
public InputStream getBinaryStream(int columnIndex) throws SQLException
{
- // New in 7.1 Handle OID's as BLOBS so return the input stream
- if(!wasNullFlag)
+ wasNullFlag = (this_row[columnIndex - 1] == null);
+ if (wasNullFlag)
+ return null;
+
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports BinaryStream for all PG bytea type
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
+ //long binary datatype, but with toast the bytea datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getBytes() since there is no current way to stream the value from the server
+ byte b[] = getBytes(columnIndex);
+ if (b != null)
+ return new ByteArrayInputStream(b);
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
if( fields[columnIndex - 1].getOID() == 26) {
LargeObjectManager lom = connection.getLargeObjectAPI();
LargeObject lob = lom.open(getInt(columnIndex));
return lob.getInputStream();
}
-
- // Not an OID so fake the stream
- byte b[] = getBytes(columnIndex);
-
- if (b != null)
- return new ByteArrayInputStream(b);
- return null; // SQL NULL
+ }
+ return null;
}
/**
@@ -731,7 +784,7 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
//if index<0, count from the end of the result set, but check
//to be sure that it is not beyond the first index
if (index<0)
- if (index > -rows_size)
+ if (index >= -rows_size)
internalIndex = rows_size+index;
else {
beforeFirst();
@@ -794,6 +847,10 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
public java.sql.Array getArray(int i) throws SQLException
{
+ wasNullFlag = (this_row[i - 1] == null);
+ if(wasNullFlag)
+ return null;
+
if (i < 1 || i > fields.length)
throw new PSQLException("postgresql.res.colrange");
return (java.sql.Array) new org.postgresql.jdbc2.Array( connection, i, fields[i-1], this );
@@ -826,10 +883,25 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
public java.io.Reader getCharacterStream(int i) throws SQLException
{
+ wasNullFlag = (this_row[i - 1] == null);
+ if (wasNullFlag)
+ return null;
+
+ if (connection.haveMinimumCompatibleVersion("7.2")) {
+ //Version 7.2 supports AsciiStream for all the PG text types
+ //As the spec/javadoc for this method indicate this is to be used for
+ //large text values (i.e. LONGVARCHAR) PG doesn't have a separate
+ //long string datatype, but with toast the text datatype is capable of
+ //handling very large values. Thus the implementation ends up calling
+ //getString() since there is no current way to stream the value from the server
+ return new CharArrayReader(getString(i).toCharArray());
+ } else {
+ // In 7.1 Handle as BLOBS so return the LargeObject input stream
Encoding encoding = connection.getEncoding();
InputStream input = getBinaryStream(i);
return encoding.getDecodingReader(input);
}
+ }
/**
* New in 7.1
@@ -1485,4 +1557,7 @@ public class ResultSet extends org.postgresql.ResultSet implements java.sql.Resu
}
}
}
+
+
}
+
diff --git a/src/interfaces/jdbc/org/postgresql/util/PGbytea.java b/src/interfaces/jdbc/org/postgresql/util/PGbytea.java
new file mode 100644
index 00000000000..e994fce5bcd
--- /dev/null
+++ b/src/interfaces/jdbc/org/postgresql/util/PGbytea.java
@@ -0,0 +1,86 @@
+package org.postgresql.util;
+
+import java.sql.*;
+
+/**
+ * Converts to and from the postgresql bytea datatype used by the backend.
+ *
+ * $Id: PGbytea.java,v 1.1 2001/09/10 15:07:05 momjian Exp $
+ */
+
+public class PGbytea {
+
+ /**
+ * Converts a PG bytea string (i.e. the text representation
+ * of the bytea data type) into a java byte[]
+ */
+ public static byte[] toBytes(String s) throws SQLException {
+ if(s==null)
+ return null;
+ int slength = s.length();
+ byte[] buf = new byte[slength];
+ int bufpos = 0;
+ int thebyte;
+ char nextchar;
+ char secondchar;
+ for (int i = 0; i < slength; i++) {
+ nextchar = s.charAt(i);
+ if (nextchar == '\\') {
+ secondchar = s.charAt(++i);
+ if (secondchar == '\\') {
+ //escaped \
+ buf[bufpos++] = (byte)'\\';
+ } else {
+ thebyte = (secondchar-48)*64 + (s.charAt(++i)-48)*8 + (s.charAt(++i)-48);
+ if (thebyte > 127)
+ thebyte -= 256;
+ buf[bufpos++] = (byte)thebyte;
+ }
+ } else {
+ buf[bufpos++] = (byte)nextchar;
+ }
+ }
+ byte[] l_return = new byte[bufpos];
+ System.arraycopy(buf,0,l_return,0,bufpos);
+ return l_return;
+ }
+
+ /**
+ * Converts a java byte[] into a PG bytea string (i.e. the text
+ * representation of the bytea data type)
+ */
+ public static String toPGString(byte[] p_buf) throws SQLException
+ {
+ if(p_buf==null)
+ return null;
+ StringBuffer l_strbuf = new StringBuffer();
+ for (int i = 0; i < p_buf.length; i++) {
+ int l_int = (int)p_buf[i];
+ if (l_int < 0) {
+ l_int = 256 + l_int;
+ }
+ //we escape the same non-printable characters as the backend
+ //we must escape all 8bit characters otherwise when convering
+ //from java unicode to the db character set we may end up with
+ //question marks if the character set is SQL_ASCII
+ if (l_int < 040 || l_int > 0176) {
+ //escape charcter with the form \000, but need two \\ because of
+ //the parser
+ l_strbuf.append("\\");
+ l_strbuf.append((char)(((l_int >> 6) & 0x3)+48));
+ l_strbuf.append((char)(((l_int >> 3) & 0x7)+48));
+ l_strbuf.append((char)((l_int & 0x07)+48));
+ } else if (p_buf[i] == (byte)'\\') {
+ //escape the backslash character as \\, but need four \\\\ because
+ //of the parser
+ l_strbuf.append("\\\\");
+ } else {
+ //other characters are left alone
+ l_strbuf.append((char)p_buf[i]);
+ }
+ }
+ return l_strbuf.toString();
+ }
+
+
+}