to version 2, and fixes ResultSetMetaData.getColumnDisplaySize().
- 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
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.
// 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;
// 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
*/
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.
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
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));
}
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;
}
{
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
* @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
*/
"int4","oid",
"int8",
"cash","money",
+ "numeric",
"float4",
"float8",
"bpchar","char","char2","char4","char8","char16",
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,
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}
/**
* 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
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:
*/
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;
}
/**
/**
* 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
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:
*/
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;
}
/**