Skip to content

Commit cd68ecf

Browse files
author
Peter Mount
committed
Some late patches from Jens Glaser (jens@jens.de). These upgrade the protocol
to version 2, and fixes ResultSetMetaData.getColumnDisplaySize().
1 parent 4d4378b commit cd68ecf

File tree

8 files changed

+137
-36
lines changed

8 files changed

+137
-36
lines changed

src/interfaces/jdbc/CHANGELOG

Lines changed: 11 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -10,6 +10,17 @@ Mon Sep 13 23:56:00 BST 1999 peter@retep.org.uk
1010
- Replaced $$(cmd...) with `cmd...` in the Makefile. This should allow
1111
the driver to compile when using shells other than Bash.
1212

13+
Thu Sep 9 01:18:39 MEST 1999 jens@jens.de
14+
- fixed bug in handling of DECIMAL type
15+
16+
Wed Aug 4 00:25:18 CEST 1999 jens@jens.de
17+
- updated ResultSetMetaData.getColumnDisplaySize() to return
18+
the actual display size
19+
- updated driver to use postgresql FE/BE-protocol version 2
20+
21+
Mon Aug 2 03:29:35 CEST 1999 jens@jens.de
22+
- fixed bug in DatabaseMetaData.getPrimaryKeys()
23+
1324
Sun Aug 1 18:05:42 CEST 1999 jens@jens.de
1425
- added support for getTransactionIsolation and setTransactionIsolation
1526

src/interfaces/jdbc/postgresql/Connection.java

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

1212
/**
13-
* $Id: Connection.java,v 1.19 1999/09/14 22:43:38 peter Exp $
13+
* $Id: Connection.java,v 1.20 1999/09/15 20:39:50 peter Exp $
1414
*
1515
* This abstract class is used by postgresql.Driver to open either the JDBC1 or
1616
* JDBC2 versions of the Connection class.
@@ -44,7 +44,7 @@ public abstract class Connection
4444
// These are new for v6.3, they determine the current protocol versions
4545
// supported by this version of the driver. They are defined in
4646
// src/include/libpq/pqcomm.h
47-
protected static final int PG_PROTOCOL_LATEST_MAJOR = 1;
47+
protected static final int PG_PROTOCOL_LATEST_MAJOR = 2;
4848
protected static final int PG_PROTOCOL_LATEST_MINOR = 0;
4949
private static final int SM_DATABASE = 64;
5050
private static final int SM_USER = 32;
@@ -69,7 +69,11 @@ public abstract class Connection
6969

7070
// Now handle notices as warnings, so things like "show" now work
7171
public SQLWarning firstWarning = null;
72-
72+
73+
// The PID an cancellation key we get from the backend process
74+
public int pid;
75+
public int ckey;
76+
7377
/**
7478
* This is called by Class.forName() from within postgresql.Driver
7579
*/
@@ -210,6 +214,33 @@ protected void openConnection(String host, int port, Properties info, String dat
210214
throw new PSQLException("postgresql.con.failed",e);
211215
}
212216

217+
218+
// As of protocol version 2.0, we should now receive the cancellation key and the pid
219+
int beresp = pg_stream.ReceiveChar();
220+
switch(beresp) {
221+
case 'K':
222+
pid = pg_stream.ReceiveInteger(4);
223+
ckey = pg_stream.ReceiveInteger(4);
224+
break;
225+
case 'E':
226+
case 'N':
227+
throw new SQLException(pg_stream.ReceiveString(4096));
228+
default:
229+
throw new PSQLException("postgresql.con.setup");
230+
}
231+
232+
// Expect ReadyForQuery packet
233+
beresp = pg_stream.ReceiveChar();
234+
switch(beresp) {
235+
case 'Z':
236+
break;
237+
case 'E':
238+
case 'N':
239+
throw new SQLException(pg_stream.ReceiveString(4096));
240+
default:
241+
throw new PSQLException("postgresql.con.setup");
242+
}
243+
213244
// Originally we issued a SHOW DATESTYLE statement to find the databases default
214245
// datestyle. However, this caused some problems with timestamps, so in 6.5, we
215246
// went the way of ODBC, and set the connection to ISO.
@@ -311,7 +342,7 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
311342
switch (c)
312343
{
313344
case 'A': // Asynchronous Notify
314-
int pid = pg_stream.ReceiveInteger(4);
345+
pid = pg_stream.ReceiveInteger(4);
315346
msg = pg_stream.ReceiveString(8192);
316347
break;
317348
case 'B': // Binary Data Transfer
@@ -383,6 +414,8 @@ public java.sql.ResultSet ExecSQL(String sql) throws SQLException
383414
throw new PSQLException("postgresql.con.multres");
384415
fields = ReceiveFields();
385416
break;
417+
case 'Z': // backend ready for query, ignore for now :-)
418+
break;
386419
default:
387420
throw new PSQLException("postgresql.con.type",new Character((char)c));
388421
}
@@ -410,7 +443,8 @@ private Field[] ReceiveFields() throws SQLException
410443
String typname = pg_stream.ReceiveString(8192);
411444
int typid = pg_stream.ReceiveIntegerR(4);
412445
int typlen = pg_stream.ReceiveIntegerR(2);
413-
fields[i] = new Field(this, typname, typid, typlen);
446+
int typmod = pg_stream.ReceiveIntegerR(4);
447+
fields[i] = new Field(this, typname, typid, typlen, typmod);
414448
}
415449
return fields;
416450
}

src/interfaces/jdbc/postgresql/Field.java

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -14,6 +14,7 @@ public class Field
1414
{
1515
public int length; // Internal Length of this field
1616
public int oid; // OID of the type
17+
public int mod; // type modifier of this field
1718
public String name; // Name of this field
1819

1920
protected Connection conn; // Connection Instantation
@@ -29,14 +30,28 @@ public class Field
2930
* @param oid the OID of the field
3031
* @param len the length of the field
3132
*/
32-
public Field(Connection conn, String name, int oid, int length)
33+
public Field(Connection conn, String name, int oid, int length,int mod)
3334
{
3435
this.conn = conn;
3536
this.name = name;
3637
this.oid = oid;
3738
this.length = length;
39+
this.mod = mod;
3840
}
3941

42+
/**
43+
* Constructor without mod parameter.
44+
*
45+
* @param conn the connection this field came from
46+
* @param name the name of the field
47+
* @param oid the OID of the field
48+
* @param len the length of the field
49+
*/
50+
public Field(Connection conn, String name, int oid, int length)
51+
{
52+
this(conn,name,oid,length,0);
53+
}
54+
4055
/**
4156
* @return the oid of this Field's data type
4257
*/
@@ -103,6 +118,7 @@ public static int getSQLType(String type_name)
103118
"int4","oid",
104119
"int8",
105120
"cash","money",
121+
"numeric",
106122
"float4",
107123
"float8",
108124
"bpchar","char","char2","char4","char8","char16",
@@ -125,6 +141,7 @@ public static int getSQLType(String type_name)
125141
Types.INTEGER,Types.INTEGER,
126142
Types.BIGINT,
127143
Types.DECIMAL,Types.DECIMAL,
144+
Types.NUMERIC,
128145
Types.REAL,
129146
Types.DOUBLE,
130147
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,

src/interfaces/jdbc/postgresql/errors.properties

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@ postgresql.con.kerb5:Kerberos 5 authentication is not supported by this driver.
1212
postgresql.con.multres:Cannot handle multiple result groups.
1313
postgresql.con.pass:The password property is missing. It is mandatory.
1414
postgresql.con.refused:Connection refused. Check that the hostname and port is correct, and that the postmaster is running with the -i flag, which enables TCP/IP networking.
15+
postgresql.con.setup:Protocol error. Session setup failed.
1516
postgresql.con.strobj:The object could not be stored. Check that any tables required have already been created in the database.
1617
postgresql.con.strobjex:Failed to store object - {0}
1718
postgresql.con.toolong:The SQL Statement is too long - {0}

src/interfaces/jdbc/postgresql/jdbc1/ResultSet.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -309,7 +309,7 @@ public double getDouble(int columnIndex) throws SQLException
309309

310310
/**
311311
* Get the value of a column in the current row as a
312-
* java.lang.BigDecimal object
312+
* java.math.BigDecimal object
313313
*
314314
* @param columnIndex the first column is 1, the second is 2...
315315
* @param scale the number of digits to the right of the decimal
@@ -709,7 +709,7 @@ public Object getObject(int columnIndex) throws SQLException
709709
case Types.BIGINT:
710710
return new Long(getLong(columnIndex));
711711
case Types.NUMERIC:
712-
return getBigDecimal(columnIndex, 0);
712+
return getBigDecimal(columnIndex, ((field.mod-4) & 0xffff));
713713
case Types.REAL:
714714
return new Float(getFloat(columnIndex));
715715
case Types.DOUBLE:

src/interfaces/jdbc/postgresql/jdbc1/ResultSetMetaData.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -188,19 +188,38 @@ public boolean isSigned(int column) throws SQLException
188188
*/
189189
public int getColumnDisplaySize(int column) throws SQLException
190190
{
191-
int max = getColumnLabel(column).length();
192-
int i;
193-
194-
for (i = 0 ; i < rows.size(); ++i)
195-
{
196-
byte[][] x = (byte[][])(rows.elementAt(i));
197-
if(x[column-1]!=null) {
198-
int xl = x[column - 1].length;
199-
if (xl > max)
200-
max = xl;
201-
}
202-
}
203-
return max;
191+
Field f = getField(column);
192+
String type_name = f.getTypeName();
193+
int sql_type = f.getSQLType();
194+
int typmod = f.mod;
195+
196+
// I looked at other JDBC implementations and couldn't find a consistent
197+
// interpretation of the "display size" for numeric values, so this is our's
198+
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
199+
200+
// fixed length data types
201+
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign)
202+
if (type_name.equals( "int4" )
203+
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647
204+
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807
205+
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2)
206+
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits
207+
if (type_name.equals( "float8" )) return 20; // dito, 20
208+
if (type_name.equals( "char" )) return 1;
209+
if (type_name.equals( "bool" )) return 1;
210+
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD"
211+
if (type_name.equals( "time" )) return 8; // 00:00:00-23:59:59
212+
if (type_name.equals( "timestamp" )) return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
213+
214+
// variable length fields
215+
typmod -= 4;
216+
if (type_name.equals( "bpchar" )
217+
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4
218+
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff )
219+
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
220+
221+
// if we don't know better
222+
return f.length;
204223
}
205224

206225
/**

src/interfaces/jdbc/postgresql/jdbc2/ResultSet.java

Lines changed: 2 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -310,7 +310,7 @@ public double getDouble(int columnIndex) throws SQLException
310310

311311
/**
312312
* Get the value of a column in the current row as a
313-
* java.lang.BigDecimal object
313+
* java.math.BigDecimal object
314314
*
315315
* @param columnIndex the first column is 1, the second is 2...
316316
* @param scale the number of digits to the right of the decimal
@@ -723,7 +723,7 @@ public Object getObject(int columnIndex) throws SQLException
723723
case Types.BIGINT:
724724
return new Long(getLong(columnIndex));
725725
case Types.NUMERIC:
726-
return getBigDecimal(columnIndex, 0);
726+
return getBigDecimal(columnIndex, ((field.mod-4) & 0xffff));
727727
case Types.REAL:
728728
return new Float(getFloat(columnIndex));
729729
case Types.DOUBLE:

src/interfaces/jdbc/postgresql/jdbc2/ResultSetMetaData.java

Lines changed: 32 additions & 13 deletions
Original file line numberDiff line numberDiff line change
@@ -183,19 +183,38 @@ public boolean isSigned(int column) throws SQLException
183183
*/
184184
public int getColumnDisplaySize(int column) throws SQLException
185185
{
186-
int max = getColumnLabel(column).length();
187-
int i;
188-
189-
for (i = 0 ; i < rows.size(); ++i)
190-
{
191-
byte[][] x = (byte[][])(rows.elementAt(i));
192-
if(x[column-1]!=null) {
193-
int xl = x[column - 1].length;
194-
if (xl > max)
195-
max = xl;
196-
}
197-
}
198-
return max;
186+
Field f = getField(column);
187+
String type_name = f.getTypeName();
188+
int sql_type = f.getSQLType();
189+
int typmod = f.mod;
190+
191+
// I looked at other JDBC implementations and couldn't find a consistent
192+
// interpretation of the "display size" for numeric values, so this is our's
193+
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
194+
195+
// fixed length data types
196+
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign)
197+
if (type_name.equals( "int4" )
198+
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647
199+
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807
200+
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2)
201+
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits
202+
if (type_name.equals( "float8" )) return 20; // dito, 20
203+
if (type_name.equals( "char" )) return 1;
204+
if (type_name.equals( "bool" )) return 1;
205+
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD"
206+
if (type_name.equals( "time" )) return 8; // 00:00:00-23:59:59
207+
if (type_name.equals( "timestamp" )) return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
208+
209+
// variable length fields
210+
typmod -= 4;
211+
if (type_name.equals( "bpchar" )
212+
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4
213+
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff )
214+
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
215+
216+
// if we don't know better
217+
return f.length;
199218
}
200219

201220
/**

0 commit comments

Comments
 (0)