Some late patches from Jens Glaser (jens@jens.de). These upgrade the protocol

to version 2, and fixes ResultSetMetaData.getColumnDisplaySize().
This commit is contained in:
Peter Mount 1999-09-15 20:40:02 +00:00
parent 4d4378b70f
commit cd68ecfef6
8 changed files with 137 additions and 36 deletions

View File

@ -10,6 +10,17 @@ Mon Sep 13 23:56:00 BST 1999 peter@retep.org.uk
- Replaced $$(cmd...) with `cmd...` in the Makefile. This should allow
the driver to compile when using shells other than Bash.
Thu Sep 9 01:18:39 MEST 1999 jens@jens.de
- fixed bug in handling of DECIMAL type
Wed Aug 4 00:25:18 CEST 1999 jens@jens.de
- updated ResultSetMetaData.getColumnDisplaySize() to return
the actual display size
- updated driver to use postgresql FE/BE-protocol version 2
Mon Aug 2 03:29:35 CEST 1999 jens@jens.de
- fixed bug in DatabaseMetaData.getPrimaryKeys()
Sun Aug 1 18:05:42 CEST 1999 jens@jens.de
- added support for getTransactionIsolation and setTransactionIsolation

View File

@ -10,7 +10,7 @@ import postgresql.largeobject.*;
import postgresql.util.*;
/**
* $Id: Connection.java,v 1.19 1999/09/14 22:43:38 peter Exp $
* $Id: Connection.java,v 1.20 1999/09/15 20:39:50 peter Exp $
*
* This abstract class is used by postgresql.Driver to open either the JDBC1 or
* JDBC2 versions of the Connection class.
@ -44,7 +44,7 @@ public abstract class Connection
// These are new for v6.3, they determine the current protocol versions
// supported by this version of the driver. They are defined in
// src/include/libpq/pqcomm.h
protected static final int PG_PROTOCOL_LATEST_MAJOR = 1;
protected static final int PG_PROTOCOL_LATEST_MAJOR = 2;
protected static final int PG_PROTOCOL_LATEST_MINOR = 0;
private static final int SM_DATABASE = 64;
private static final int SM_USER = 32;
@ -69,7 +69,11 @@ public abstract class Connection
// Now handle notices as warnings, so things like "show" now work
public SQLWarning firstWarning = null;
// The PID an cancellation key we get from the backend process
public int pid;
public int ckey;
/**
* This is called by Class.forName() from within postgresql.Driver
*/
@ -210,6 +214,33 @@ public abstract class Connection
throw new PSQLException("postgresql.con.failed",e);
}
// As of protocol version 2.0, we should now receive the cancellation key and the pid
int beresp = pg_stream.ReceiveChar();
switch(beresp) {
case 'K':
pid = pg_stream.ReceiveInteger(4);
ckey = pg_stream.ReceiveInteger(4);
break;
case 'E':
case 'N':
throw new SQLException(pg_stream.ReceiveString(4096));
default:
throw new PSQLException("postgresql.con.setup");
}
// Expect ReadyForQuery packet
beresp = pg_stream.ReceiveChar();
switch(beresp) {
case 'Z':
break;
case 'E':
case 'N':
throw new SQLException(pg_stream.ReceiveString(4096));
default:
throw new PSQLException("postgresql.con.setup");
}
// Originally we issued a SHOW DATESTYLE statement to find the databases default
// datestyle. However, this caused some problems with timestamps, so in 6.5, we
// went the way of ODBC, and set the connection to ISO.
@ -311,7 +342,7 @@ public abstract class Connection
switch (c)
{
case 'A': // Asynchronous Notify
int pid = pg_stream.ReceiveInteger(4);
pid = pg_stream.ReceiveInteger(4);
msg = pg_stream.ReceiveString(8192);
break;
case 'B': // Binary Data Transfer
@ -383,6 +414,8 @@ public abstract class Connection
throw new PSQLException("postgresql.con.multres");
fields = ReceiveFields();
break;
case 'Z': // backend ready for query, ignore for now :-)
break;
default:
throw new PSQLException("postgresql.con.type",new Character((char)c));
}
@ -410,7 +443,8 @@ public abstract class Connection
String typname = pg_stream.ReceiveString(8192);
int typid = pg_stream.ReceiveIntegerR(4);
int typlen = pg_stream.ReceiveIntegerR(2);
fields[i] = new Field(this, typname, typid, typlen);
int typmod = pg_stream.ReceiveIntegerR(4);
fields[i] = new Field(this, typname, typid, typlen, typmod);
}
return fields;
}

View File

@ -14,6 +14,7 @@ public class Field
{
public int length; // Internal Length of this field
public int oid; // OID of the type
public int mod; // type modifier of this field
public String name; // Name of this field
protected Connection conn; // Connection Instantation
@ -29,14 +30,28 @@ public class Field
* @param oid the OID of the field
* @param len the length of the field
*/
public Field(Connection conn, String name, int oid, int length)
public Field(Connection conn, String name, int oid, int length,int mod)
{
this.conn = conn;
this.name = name;
this.oid = oid;
this.length = length;
this.mod = mod;
}
/**
* Constructor without mod parameter.
*
* @param conn the connection this field came from
* @param name the name of the field
* @param oid the OID of the field
* @param len the length of the field
*/
public Field(Connection conn, String name, int oid, int length)
{
this(conn,name,oid,length,0);
}
/**
* @return the oid of this Field's data type
*/
@ -103,6 +118,7 @@ public class Field
"int4","oid",
"int8",
"cash","money",
"numeric",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
@ -125,6 +141,7 @@ public class Field
Types.INTEGER,Types.INTEGER,
Types.BIGINT,
Types.DECIMAL,Types.DECIMAL,
Types.NUMERIC,
Types.REAL,
Types.DOUBLE,
Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,Types.CHAR,

View File

@ -12,6 +12,7 @@ postgresql.con.kerb5:Kerberos 5 authentication is not supported by this driver.
postgresql.con.multres:Cannot handle multiple result groups.
postgresql.con.pass:The password property is missing. It is mandatory.
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.
postgresql.con.setup:Protocol error. Session setup failed.
postgresql.con.strobj:The object could not be stored. Check that any tables required have already been created in the database.
postgresql.con.strobjex:Failed to store object - {0}
postgresql.con.toolong:The SQL Statement is too long - {0}

View File

@ -309,7 +309,7 @@ public class ResultSet extends postgresql.ResultSet implements java.sql.ResultSe
/**
* Get the value of a column in the current row as a
* java.lang.BigDecimal object
* java.math.BigDecimal object
*
* @param columnIndex the first column is 1, the second is 2...
* @param scale the number of digits to the right of the decimal
@ -709,7 +709,7 @@ public class ResultSet extends postgresql.ResultSet implements java.sql.ResultSe
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
return getBigDecimal(columnIndex, 0);
return getBigDecimal(columnIndex, ((field.mod-4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.DOUBLE:

View File

@ -188,19 +188,38 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
*/
public int getColumnDisplaySize(int column) throws SQLException
{
int max = getColumnLabel(column).length();
int i;
for (i = 0 ; i < rows.size(); ++i)
{
byte[][] x = (byte[][])(rows.elementAt(i));
if(x[column-1]!=null) {
int xl = x[column - 1].length;
if (xl > max)
max = xl;
}
}
return max;
Field f = getField(column);
String type_name = f.getTypeName();
int sql_type = f.getSQLType();
int typmod = f.mod;
// I looked at other JDBC implementations and couldn't find a consistent
// interpretation of the "display size" for numeric values, so this is our's
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
// fixed length data types
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign)
if (type_name.equals( "int4" )
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2)
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits
if (type_name.equals( "float8" )) return 20; // dito, 20
if (type_name.equals( "char" )) return 1;
if (type_name.equals( "bool" )) return 1;
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD"
if (type_name.equals( "time" )) return 8; // 00:00:00-23:59:59
if (type_name.equals( "timestamp" )) return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
// variable length fields
typmod -= 4;
if (type_name.equals( "bpchar" )
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff )
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
// if we don't know better
return f.length;
}
/**

View File

@ -310,7 +310,7 @@ public class ResultSet extends postgresql.ResultSet implements java.sql.ResultSe
/**
* Get the value of a column in the current row as a
* java.lang.BigDecimal object
* java.math.BigDecimal object
*
* @param columnIndex the first column is 1, the second is 2...
* @param scale the number of digits to the right of the decimal
@ -723,7 +723,7 @@ public class ResultSet extends postgresql.ResultSet implements java.sql.ResultSe
case Types.BIGINT:
return new Long(getLong(columnIndex));
case Types.NUMERIC:
return getBigDecimal(columnIndex, 0);
return getBigDecimal(columnIndex, ((field.mod-4) & 0xffff));
case Types.REAL:
return new Float(getFloat(columnIndex));
case Types.DOUBLE:

View File

@ -183,19 +183,38 @@ public class ResultSetMetaData implements java.sql.ResultSetMetaData
*/
public int getColumnDisplaySize(int column) throws SQLException
{
int max = getColumnLabel(column).length();
int i;
for (i = 0 ; i < rows.size(); ++i)
{
byte[][] x = (byte[][])(rows.elementAt(i));
if(x[column-1]!=null) {
int xl = x[column - 1].length;
if (xl > max)
max = xl;
}
}
return max;
Field f = getField(column);
String type_name = f.getTypeName();
int sql_type = f.getSQLType();
int typmod = f.mod;
// I looked at other JDBC implementations and couldn't find a consistent
// interpretation of the "display size" for numeric values, so this is our's
// FIXME: currently, only types with a SQL92 or SQL3 pendant are implemented - jens@jens.de
// fixed length data types
if (type_name.equals( "int2" )) return 6; // -32768 to +32768 (5 digits and a sign)
if (type_name.equals( "int4" )
|| type_name.equals( "oid" )) return 11; // -2147483648 to +2147483647
if (type_name.equals( "int8" )) return 20; // -9223372036854775808 to +9223372036854775807
if (type_name.equals( "money" )) return 12; // MONEY = DECIMAL(9,2)
if (type_name.equals( "float4" )) return 11; // i checked it out ans wasn't able to produce more than 11 digits
if (type_name.equals( "float8" )) return 20; // dito, 20
if (type_name.equals( "char" )) return 1;
if (type_name.equals( "bool" )) return 1;
if (type_name.equals( "date" )) return 14; // "01/01/4713 BC" - "31/12/32767 AD"
if (type_name.equals( "time" )) return 8; // 00:00:00-23:59:59
if (type_name.equals( "timestamp" )) return 22; // hhmmm ... the output looks like this: 1999-08-03 22:22:08+02
// variable length fields
typmod -= 4;
if (type_name.equals( "bpchar" )
|| type_name.equals( "varchar" )) return typmod; // VARHDRSZ=sizeof(int32)=4
if (type_name.equals( "numeric" )) return ( (typmod >>16) & 0xffff )
+ 1 + ( typmod & 0xffff ); // DECIMAL(p,s) = (p digits).(s digits)
// if we don't know better
return f.length;
}
/**