mirror of
https://github.com/postgres/postgres.git
synced 2025-05-18 17:41:14 +03:00
Fix the setXXXStream methods. If passed a null InputStream, convert
this to a setNull call. The code originally would try to read the whole stream in one call to read(), but this doesn't work. The InputStream API makes it clear you must be prepared to loop and continue reading if you didn't get the whole request on the first try. Per report from Martin Holz.
This commit is contained in:
parent
7ca2bff95f
commit
9287630fbc
@ -26,7 +26,7 @@ import java.sql.Timestamp;
|
|||||||
import java.sql.Types;
|
import java.sql.Types;
|
||||||
import java.util.Vector;
|
import java.util.Vector;
|
||||||
|
|
||||||
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.41.2.2 2003/12/12 18:39:00 davec Exp $
|
/* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Statement.java,v 1.41.2.3 2004/02/03 05:13:55 jurka Exp $
|
||||||
* This class defines methods of the jdbc1 specification. This class is
|
* This class defines methods of the jdbc1 specification. This class is
|
||||||
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
|
* extended by org.postgresql.jdbc2.AbstractJdbc2Statement which adds the jdbc2
|
||||||
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
|
* methods. The real Statement class (for jdbc1) is org.postgresql.jdbc1.Jdbc1Statement
|
||||||
@ -1342,6 +1342,50 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
|
|||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
|
||||||
|
private void setCharacterStreamPost71(int parameterIndex, InputStream x, int length, String encoding) throws SQLException
|
||||||
|
{
|
||||||
|
|
||||||
|
if (x == null)
|
||||||
|
{
|
||||||
|
setNull(parameterIndex, Types.VARCHAR);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
|
//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, encoding);
|
||||||
|
char[] l_chars = new char[length];
|
||||||
|
int l_charsRead = 0;
|
||||||
|
while (true)
|
||||||
|
{
|
||||||
|
int n = l_inStream.read(l_chars, l_charsRead, length - l_charsRead);
|
||||||
|
if (n == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
l_charsRead += n;
|
||||||
|
|
||||||
|
if (l_charsRead == length)
|
||||||
|
break;
|
||||||
|
}
|
||||||
|
|
||||||
|
setString(parameterIndex, new String(l_chars, 0, l_charsRead), PG_TEXT);
|
||||||
|
}
|
||||||
|
catch (UnsupportedEncodingException l_uee)
|
||||||
|
{
|
||||||
|
throw new PSQLException("postgresql.unusual", PSQLState.UNEXPECTED_ERROR, l_uee);
|
||||||
|
}
|
||||||
|
catch (IOException l_ioe)
|
||||||
|
{
|
||||||
|
throw new PSQLException("postgresql.unusual", PSQLState.UNEXPECTED_ERROR, l_ioe);
|
||||||
|
}
|
||||||
|
}
|
||||||
|
|
||||||
/*
|
/*
|
||||||
* When a very large ASCII value is input to a LONGVARCHAR parameter,
|
* When a very large ASCII value is input to a LONGVARCHAR parameter,
|
||||||
* it may be more practical to send it via a java.io.InputStream.
|
* it may be more practical to send it via a java.io.InputStream.
|
||||||
@ -1362,27 +1406,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
|
|||||||
{
|
{
|
||||||
if (connection.haveMinimumCompatibleVersion("7.2"))
|
if (connection.haveMinimumCompatibleVersion("7.2"))
|
||||||
{
|
{
|
||||||
//Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
|
setCharacterStreamPost71(parameterIndex, x, length, "ASCII");
|
||||||
//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), PG_TEXT);
|
|
||||||
}
|
|
||||||
catch (UnsupportedEncodingException l_uee)
|
|
||||||
{
|
|
||||||
throw new PSQLException("postgresql.unusual", PSQLState.UNEXPECTED_ERROR, l_uee);
|
|
||||||
}
|
|
||||||
catch (IOException l_ioe)
|
|
||||||
{
|
|
||||||
throw new PSQLException("postgresql.unusual", PSQLState.UNEXPECTED_ERROR, l_ioe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1411,27 +1435,7 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
|
|||||||
{
|
{
|
||||||
if (connection.haveMinimumCompatibleVersion("7.2"))
|
if (connection.haveMinimumCompatibleVersion("7.2"))
|
||||||
{
|
{
|
||||||
//Version 7.2 supports AsciiStream for all PG text types (char, varchar, text)
|
setCharacterStreamPost71(parameterIndex, x, length, "UTF-8");
|
||||||
//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), PG_TEXT);
|
|
||||||
}
|
|
||||||
catch (UnsupportedEncodingException l_uee)
|
|
||||||
{
|
|
||||||
throw new PSQLException("postgresql.unusual", PSQLState.UNEXPECTED_ERROR, l_uee);
|
|
||||||
}
|
|
||||||
catch (IOException l_ioe)
|
|
||||||
{
|
|
||||||
throw new PSQLException("postgresql.unusual", PSQLState.UNEXPECTED_ERROR, l_ioe);
|
|
||||||
}
|
|
||||||
}
|
}
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
@ -1459,6 +1463,12 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
|
|||||||
{
|
{
|
||||||
if (connection.haveMinimumCompatibleVersion("7.2"))
|
if (connection.haveMinimumCompatibleVersion("7.2"))
|
||||||
{
|
{
|
||||||
|
if (x == null)
|
||||||
|
{
|
||||||
|
setNull(parameterIndex, Types.VARBINARY);
|
||||||
|
return;
|
||||||
|
}
|
||||||
|
|
||||||
//Version 7.2 supports BinaryStream for for the PG bytea type
|
//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
|
//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
|
//large binary values (i.e. LONGVARBINARY) PG doesn't have a separate
|
||||||
@ -1466,10 +1476,21 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
|
|||||||
//handling very large values. Thus the implementation ends up calling
|
//handling very large values. Thus the implementation ends up calling
|
||||||
//setBytes() since there is no current way to stream the value to the server
|
//setBytes() since there is no current way to stream the value to the server
|
||||||
byte[] l_bytes = new byte[length];
|
byte[] l_bytes = new byte[length];
|
||||||
int l_bytesRead;
|
int l_bytesRead = 0;
|
||||||
try
|
try
|
||||||
{
|
{
|
||||||
l_bytesRead = x.read(l_bytes, 0, length);
|
while (true)
|
||||||
|
{
|
||||||
|
int n = x.read(l_bytes, l_bytesRead, length - l_bytesRead);
|
||||||
|
if (n == -1)
|
||||||
|
break;
|
||||||
|
|
||||||
|
l_bytesRead += n;
|
||||||
|
|
||||||
|
if (l_bytesRead == length)
|
||||||
|
break;
|
||||||
|
|
||||||
|
}
|
||||||
}
|
}
|
||||||
catch (IOException l_ioe)
|
catch (IOException l_ioe)
|
||||||
{
|
{
|
||||||
@ -1479,11 +1500,6 @@ public abstract class AbstractJdbc1Statement implements BaseStatement
|
|||||||
{
|
{
|
||||||
setBytes(parameterIndex, l_bytes);
|
setBytes(parameterIndex, l_bytes);
|
||||||
}
|
}
|
||||||
// x.read will return -1 not 0 on an empty InputStream
|
|
||||||
else if (l_bytesRead == -1)
|
|
||||||
{
|
|
||||||
setBytes(parameterIndex, new byte[0]);
|
|
||||||
}
|
|
||||||
else
|
else
|
||||||
{
|
{
|
||||||
//the stream contained less data than they said
|
//the stream contained less data than they said
|
||||||
|
@ -42,6 +42,7 @@ public class Jdbc2TestSuite extends TestSuite
|
|||||||
suite.addTestSuite(TimestampTest.class);
|
suite.addTestSuite(TimestampTest.class);
|
||||||
|
|
||||||
// PreparedStatement
|
// PreparedStatement
|
||||||
|
suite.addTestSuite(PreparedStatementTest.class);
|
||||||
|
|
||||||
// ServerSide Prepared Statements
|
// ServerSide Prepared Statements
|
||||||
suite.addTestSuite(ServerPreparedStmtTest.class);
|
suite.addTestSuite(ServerPreparedStmtTest.class);
|
||||||
|
@ -0,0 +1,91 @@
|
|||||||
|
package org.postgresql.test.jdbc2;
|
||||||
|
|
||||||
|
import org.postgresql.test.TestUtil;
|
||||||
|
import junit.framework.TestCase;
|
||||||
|
import java.io.*;
|
||||||
|
import java.sql.*;
|
||||||
|
|
||||||
|
|
||||||
|
public class PreparedStatementTest extends TestCase
|
||||||
|
{
|
||||||
|
|
||||||
|
private Connection conn;
|
||||||
|
|
||||||
|
public PreparedStatementTest(String name)
|
||||||
|
{
|
||||||
|
super(name);
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void setUp() throws SQLException
|
||||||
|
{
|
||||||
|
conn = TestUtil.openDB();
|
||||||
|
TestUtil.createTable(conn, "streamtable", "bin bytea, str text");
|
||||||
|
}
|
||||||
|
|
||||||
|
protected void tearDown() throws SQLException
|
||||||
|
{
|
||||||
|
TestUtil.dropTable(conn, "streamtable");
|
||||||
|
TestUtil.closeDB(conn);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSetBinaryStream() throws SQLException
|
||||||
|
{
|
||||||
|
ByteArrayInputStream bais;
|
||||||
|
byte buf[] = new byte[10];
|
||||||
|
for (int i=0; i<buf.length; i++) {
|
||||||
|
buf[i] = (byte)i;
|
||||||
|
}
|
||||||
|
|
||||||
|
bais = null;
|
||||||
|
doSetBinaryStream(bais,0);
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(new byte[0]);
|
||||||
|
doSetBinaryStream(bais,100);
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(buf);
|
||||||
|
doSetBinaryStream(bais,0);
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(buf);
|
||||||
|
doSetBinaryStream(bais,10);
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(buf);
|
||||||
|
doSetBinaryStream(bais,100);
|
||||||
|
}
|
||||||
|
|
||||||
|
public void testSetAsciiStream() throws Exception
|
||||||
|
{
|
||||||
|
ByteArrayOutputStream baos = new ByteArrayOutputStream();
|
||||||
|
PrintWriter pw = new PrintWriter(new OutputStreamWriter(baos,"ASCII"));
|
||||||
|
pw.println("Hello");
|
||||||
|
pw.flush();
|
||||||
|
|
||||||
|
ByteArrayInputStream bais;
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(baos.toByteArray());
|
||||||
|
doSetAsciiStream(bais, 0);
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(baos.toByteArray());
|
||||||
|
doSetAsciiStream(bais, 6);
|
||||||
|
|
||||||
|
bais = new ByteArrayInputStream(baos.toByteArray());
|
||||||
|
doSetAsciiStream(bais, 100);
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSetBinaryStream(ByteArrayInputStream bais, int length) throws SQLException
|
||||||
|
{
|
||||||
|
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO streamtable (bin,str) VALUES (?,?)");
|
||||||
|
pstmt.setBinaryStream(1,bais, length);
|
||||||
|
pstmt.setString(2,null);
|
||||||
|
pstmt.executeUpdate();
|
||||||
|
pstmt.close();
|
||||||
|
}
|
||||||
|
|
||||||
|
private void doSetAsciiStream(InputStream is, int length) throws SQLException
|
||||||
|
{
|
||||||
|
PreparedStatement pstmt = conn.prepareStatement("INSERT INTO streamtable (bin,str) VALUES (?,?)");
|
||||||
|
pstmt.setBytes(1,null);
|
||||||
|
pstmt.setAsciiStream(2, is, length);
|
||||||
|
pstmt.executeUpdate();
|
||||||
|
pstmt.close();
|
||||||
|
}
|
||||||
|
}
|
Loading…
x
Reference in New Issue
Block a user