Skip to content

Commit b08e86d

Browse files
committed
The attached patch fixes problems with the JDBC driver handling long
null terminated strings. The FE/BE protocol sends in some cases null terminated strings to the client. The docs for the FE/BE protocol state that there is no limit on the size of a null terminated string sent to the client and a client should be coded using an expanding buffer to deal with large strings. The old code did not do this and gave an error if a null terminated string was greater than either 4 or 8K. It appears that with the advent of TOAST very long SQL statements are becoming more common, and apparently some error messages from the backend include the SQL statement thus easily exceeding the 8K limit in the old code. In fixing I also cleaned up some calls in the JDBC fastpath code that were not doing character set conversion under multibyte, and removed some methods that were no longer needed. I also removed a potential threading problem with a shared variable that was being used in Connection.java. Thanks to Steve Wampler for discovering the problem and sending the initial diffs that were the basis of this patch. thanks, --Barry
1 parent 4046e58 commit b08e86d

File tree

3 files changed

+35
-68
lines changed

3 files changed

+35
-68
lines changed

src/interfaces/jdbc/org/postgresql/Connection.java

Lines changed: 10 additions & 17 deletions
Original file line numberDiff line numberDiff line change
@@ -10,7 +10,7 @@
1010
import org.postgresql.util.*;
1111

1212
/**
13-
* $Id: Connection.java,v 1.17 2001/06/07 00:09:32 momjian Exp $
13+
* $Id: Connection.java,v 1.18 2001/07/15 04:21:26 momjian Exp $
1414
*
1515
* This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
1616
* JDBC2 versions of the Connection class.
@@ -82,11 +82,6 @@ public abstract class Connection
8282
public int pid;
8383
public int ckey;
8484

85-
// This receive_sbuf should be used by the different methods
86-
// that call pg_stream.ReceiveString() in this Connection, so
87-
// so we avoid uneccesary new allocations.
88-
byte receive_sbuf[] = new byte[8192];
89-
9085
/**
9186
* This is called by Class.forName() from within org.postgresql.Driver
9287
*/
@@ -167,8 +162,7 @@ protected void openConnection(String host, int port, Properties info, String dat
167162
// The most common one to be thrown here is:
168163
// "User authentication failed"
169164
//
170-
throw new SQLException(pg_stream.ReceiveString
171-
(receive_sbuf, 4096, getEncoding()));
165+
throw new SQLException(pg_stream.ReceiveString(getEncoding()));
172166

173167
case 'R':
174168
// Get the type of request
@@ -238,8 +232,7 @@ protected void openConnection(String host, int port, Properties info, String dat
238232
break;
239233
case 'E':
240234
case 'N':
241-
throw new SQLException(pg_stream.ReceiveString
242-
(receive_sbuf, 4096, getEncoding()));
235+
throw new SQLException(pg_stream.ReceiveString(getEncoding()));
243236
default:
244237
throw new PSQLException("postgresql.con.setup");
245238
}
@@ -251,7 +244,7 @@ protected void openConnection(String host, int port, Properties info, String dat
251244
break;
252245
case 'E':
253246
case 'N':
254-
throw new SQLException(pg_stream.ReceiveString(receive_sbuf, 4096, getEncoding()));
247+
throw new SQLException(pg_stream.ReceiveString(getEncoding()));
255248
default:
256249
throw new PSQLException("postgresql.con.setup");
257250
}
@@ -491,7 +484,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
491484
{
492485
case 'A': // Asynchronous Notify
493486
pid = pg_stream.ReceiveInteger(4);
494-
msg = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding());
487+
msg = pg_stream.ReceiveString(getEncoding());
495488
break;
496489
case 'B': // Binary Data Transfer
497490
if (fields == null)
@@ -502,7 +495,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
502495
tuples.addElement(tup);
503496
break;
504497
case 'C': // Command Status
505-
recv_status = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding());
498+
recv_status = pg_stream.ReceiveString(getEncoding());
506499

507500
// Now handle the update count correctly.
508501
if(recv_status.startsWith("INSERT") || recv_status.startsWith("UPDATE") || recv_status.startsWith("DELETE") || recv_status.startsWith("MOVE")) {
@@ -544,7 +537,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
544537
tuples.addElement(tup);
545538
break;
546539
case 'E': // Error Message
547-
msg = pg_stream.ReceiveString(receive_sbuf,4096,getEncoding());
540+
msg = pg_stream.ReceiveString(getEncoding());
548541
final_error = new SQLException(msg);
549542
hfr = true;
550543
break;
@@ -559,10 +552,10 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
559552
hfr = true;
560553
break;
561554
case 'N': // Error Notification
562-
addWarning(pg_stream.ReceiveString(receive_sbuf,4096,getEncoding()));
555+
addWarning(pg_stream.ReceiveString(getEncoding()));
563556
break;
564557
case 'P': // Portal Name
565-
String pname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding());
558+
String pname = pg_stream.ReceiveString(getEncoding());
566559
break;
567560
case 'T': // MetaData Field Description
568561
if (fields != null)
@@ -595,7 +588,7 @@ private Field[] ReceiveFields() throws SQLException
595588

596589
for (i = 0 ; i < nf ; ++i)
597590
{
598-
String typname = pg_stream.ReceiveString(receive_sbuf,8192,getEncoding());
591+
String typname = pg_stream.ReceiveString(getEncoding());
599592
int typid = pg_stream.ReceiveIntegerR(4);
600593
int typlen = pg_stream.ReceiveIntegerR(2);
601594
int typmod = pg_stream.ReceiveIntegerR(4);

src/interfaces/jdbc/org/postgresql/PG_Stream.java

Lines changed: 22 additions & 48 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,7 @@ public class PG_Stream
2323
private Socket connection;
2424
private InputStream pg_input;
2525
private BufferedOutputStream pg_output;
26+
private byte[] byte_buf = new byte[8*1024];
2627

2728
BytePoolDim1 bytePoolDim1 = new BytePoolDim1();
2829
BytePoolDim2 bytePoolDim2 = new BytePoolDim2();
@@ -200,72 +201,45 @@ public int ReceiveIntegerR(int siz) throws SQLException
200201
}
201202

202203
/**
203-
* Receives a null-terminated string from the backend. Maximum of
204-
* maxsiz bytes - if we don't see a null, then we assume something
205-
* has gone wrong.
204+
* Receives a null-terminated string from the backend. If we don't see a
205+
* null, then we assume something has gone wrong.
206206
*
207-
* @param maxsiz maximum length of string
208-
* @return string from back end
209-
* @exception SQLException if an I/O error occurs
210-
*/
211-
public String ReceiveString(int maxsiz) throws SQLException
212-
{
213-
byte[] rst = bytePoolDim1.allocByte(maxsiz);
214-
return ReceiveString(rst, maxsiz, null);
215-
}
216-
217-
/**
218-
* Receives a null-terminated string from the backend. Maximum of
219-
* maxsiz bytes - if we don't see a null, then we assume something
220-
* has gone wrong.
221-
*
222-
* @param maxsiz maximum length of string
223-
* @param encoding the charset encoding to use.
224-
* @param maxsiz maximum length of string in bytes
225-
* @return string from back end
226-
* @exception SQLException if an I/O error occurs
227-
*/
228-
public String ReceiveString(int maxsiz, String encoding) throws SQLException
229-
{
230-
byte[] rst = bytePoolDim1.allocByte(maxsiz);
231-
return ReceiveString(rst, maxsiz, encoding);
232-
}
233-
234-
/**
235-
* Receives a null-terminated string from the backend. Maximum of
236-
* maxsiz bytes - if we don't see a null, then we assume something
237-
* has gone wrong.
238-
*
239-
* @param rst byte array to read the String into. rst.length must
240-
* equal to or greater than maxsize.
241-
* @param maxsiz maximum length of string in bytes
242207
* @param encoding the charset encoding to use.
243208
* @return string from back end
244-
* @exception SQLException if an I/O error occurs
209+
* @exception SQLException if an I/O error occurs, or end of file
245210
*/
246-
public String ReceiveString(byte rst[], int maxsiz, String encoding)
211+
public String ReceiveString(String encoding)
247212
throws SQLException
248213
{
249214
int s = 0;
250-
251-
try
252-
{
253-
while (s < maxsiz)
254-
{
215+
byte[] rst = byte_buf;
216+
try {
217+
int buflen = rst.length;
218+
boolean done = false;
219+
while (!done) {
220+
while (s < buflen) {
255221
int c = pg_input.read();
256222
if (c < 0)
257223
throw new PSQLException("postgresql.stream.eof");
258224
else if (c == 0) {
259225
rst[s] = 0;
226+
done = true;
260227
break;
261-
} else
228+
} else {
262229
rst[s++] = (byte)c;
263230
}
264-
if (s >= maxsiz)
265-
throw new PSQLException("postgresql.stream.toomuch");
231+
if (s >= buflen) { // Grow the buffer
232+
buflen = (int)(buflen*2); // 100% bigger
233+
byte[] newrst = new byte[buflen];
234+
System.arraycopy(rst, 0, newrst, 0, s);
235+
rst = newrst;
236+
}
237+
}
238+
}
266239
} catch (IOException e) {
267240
throw new PSQLException("postgresql.stream.ioerror",e);
268241
}
242+
269243
String v = null;
270244
if (encoding == null)
271245
v = new String(rst, 0, s);

src/interfaces/jdbc/org/postgresql/fastpath/Fastpath.java

Lines changed: 3 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -89,7 +89,7 @@ public Object fastpath(int fnid,boolean resulttype,FastpathArg[] args) throws SQ
8989
//DriverManager.println("ReceiveChar() = "+in+" '"+((char)in)+"'");
9090
//if(in!='V') {
9191
//if(in=='E')
92-
//throw new SQLException(stream.ReceiveString(4096));
92+
//throw new SQLException(stream.ReceiveString(conn.getEncoding()));
9393
//throw new SQLException("Fastpath: expected 'V' from backend, got "+((char)in));
9494
//}
9595

@@ -123,12 +123,12 @@ public Object fastpath(int fnid,boolean resulttype,FastpathArg[] args) throws SQ
123123
//------------------------------
124124
// Error message returned
125125
case 'E':
126-
throw new PSQLException("postgresql.fp.error",stream.ReceiveString(4096));
126+
throw new PSQLException("postgresql.fp.error",stream.ReceiveString(conn.getEncoding()));
127127

128128
//------------------------------
129129
// Notice from backend
130130
case 'N':
131-
conn.addWarning(stream.ReceiveString(4096));
131+
conn.addWarning(stream.ReceiveString(conn.getEncoding()));
132132
break;
133133

134134
//------------------------------

0 commit comments

Comments
 (0)