1
/*-------------------------------------------------------------------------
3
* AbstractJdbc1Connection.java
4
* This class defines methods of the jdbc1 specification. This class is
5
* extended by org.postgresql.jdbc2.AbstractJdbc2Connection which adds
6
* the jdbc2 methods. The real Connection class (for jdbc1) is
7
* org.postgresql.jdbc1.Jdbc1Connection
9
* Copyright (c) 2003, PostgreSQL Global Development Group
12
* $Header: /cvsroot/pgsql/src/interfaces/jdbc/org/postgresql/jdbc1/Attic/AbstractJdbc1Connection.java,v 1.27.2.4 2004/08/11 06:56:00 jurka Exp $
14
*-------------------------------------------------------------------------
16
package org.postgresql.jdbc1;
19
import java.io.IOException;
20
import java.net.ConnectException;
23
import org.postgresql.Driver;
24
import org.postgresql.PGNotification;
25
import org.postgresql.core.BaseConnection;
26
import org.postgresql.core.BaseResultSet;
27
import org.postgresql.core.BaseStatement;
28
import org.postgresql.core.Encoding;
29
import org.postgresql.core.PGStream;
30
import org.postgresql.core.QueryExecutor;
31
import org.postgresql.core.StartupPacket;
32
import org.postgresql.fastpath.Fastpath;
33
import org.postgresql.largeobject.LargeObjectManager;
34
import org.postgresql.util.MD5Digest;
35
import org.postgresql.util.PGobject;
36
import org.postgresql.util.PSQLException;
37
import org.postgresql.util.PSQLState;
38
import org.postgresql.util.UnixCrypt;
40
public abstract class AbstractJdbc1Connection implements BaseConnection
42
// This is the network stream associated with this connection
43
private PGStream pgStream;
45
public PGStream getPGStream() {
49
protected String PG_HOST;
50
protected int PG_PORT;
51
protected String PG_USER;
52
protected String PG_DATABASE;
53
protected boolean PG_STATUS;
54
protected String compatible;
55
protected boolean useSSL;
57
// The PID an cancellation key we get from the backend process
61
private Vector m_notifications;
64
The encoding to use for this connection.
66
private Encoding encoding = Encoding.defaultEncoding();
68
private String dbVersionNumber;
70
public boolean CONNECTION_OK = true;
71
public boolean CONNECTION_BAD = false;
73
public boolean autoCommit = true;
74
public boolean readOnly = false;
76
public Driver this_driver;
77
private String this_url;
78
private String cursor = null; // The positioned update cursor name
80
private int PGProtocolVersionMajor = 2;
81
private int PGProtocolVersionMinor = 0;
82
public int getPGProtocolVersionMajor() { return PGProtocolVersionMajor; }
83
public int getPGProtocolVersionMinor() { return PGProtocolVersionMinor; }
85
private static final int AUTH_REQ_OK = 0;
86
private static final int AUTH_REQ_KRB4 = 1;
87
private static final int AUTH_REQ_KRB5 = 2;
88
private static final int AUTH_REQ_PASSWORD = 3;
89
private static final int AUTH_REQ_CRYPT = 4;
90
private static final int AUTH_REQ_MD5 = 5;
91
private static final int AUTH_REQ_SCM = 6;
94
// These are used to cache oids, PGTypes and SQLTypes
95
private static Hashtable sqlTypeCache = new Hashtable(); // oid -> SQLType
96
private static Hashtable pgTypeCache = new Hashtable(); // oid -> PGType
97
private static Hashtable typeOidCache = new Hashtable(); //PGType -> oid
99
// Now handle notices as warnings, so things like "show" now work
100
public SQLWarning firstWarning = null;
103
* Cache of the current isolation level
105
private int isolationLevel = Connection.TRANSACTION_READ_COMMITTED;
108
public abstract Statement createStatement() throws SQLException;
109
public abstract DatabaseMetaData getMetaData() throws SQLException;
112
* This method actually opens the connection. It is called by Driver.
114
* @param host the hostname of the database back end
115
* @param port the port number of the postmaster process
116
* @param info a Properties[] thing of the user and password
117
* @param database the database to connect to
118
* @param url the URL of the connection
119
* @param d the Driver instantation of the connection
120
* @exception SQLException if a database access error occurs
122
public void openConnection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException
126
// Throw an exception if the user or password properties are missing
127
// This occasionally occurs when the client uses the properties version
128
// of getConnection(), and is a common question on the email lists
129
if (info.getProperty("user") == null)
130
throw new PSQLException("postgresql.con.user", PSQLState.CONNECTION_REJECTED);
132
this_driver = (Driver)d;
135
PG_DATABASE = database;
136
PG_USER = info.getProperty("user");
138
String password = info.getProperty("password", "");
142
PG_STATUS = CONNECTION_BAD;
144
if (info.getProperty("ssl") != null && Driver.sslEnabled())
153
if (info.getProperty("compatible") == null)
155
compatible = d.getMajorVersion() + "." + d.getMinorVersion();
159
compatible = info.getProperty("compatible");
162
//Read loglevel arg and set the loglevel based on this value
163
//in addition to setting the log level enable output to
164
//standard out if no other printwriter is set
165
String l_logLevelProp = info.getProperty("loglevel", "0");
169
l_logLevel = Integer.parseInt(l_logLevelProp);
170
if (l_logLevel > Driver.DEBUG || l_logLevel < Driver.INFO)
175
catch (Exception l_e)
177
//invalid value for loglevel ignore
181
Driver.setLogLevel(l_logLevel);
182
enableDriverManagerLogging();
185
//Print out the driver version number
187
Driver.info(Driver.getVersion());
188
if (Driver.logDebug) {
189
Driver.debug(" ssl = " + useSSL);
190
Driver.debug(" compatible = " + compatible);
191
Driver.debug(" loglevel = " + l_logLevel);
194
// Now make the initial connection
197
pgStream = new PGStream(host, port);
199
catch (ConnectException cex)
201
// Added by Peter Mount <peter@retep.org.uk>
202
// ConnectException is thrown when the connection cannot be made.
203
// we trap this an return a more meaningful message for the end user
204
throw new PSQLException ("postgresql.con.refused", PSQLState.CONNECTION_REJECTED);
206
catch (IOException e)
208
throw new PSQLException ("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
212
//Now do the protocol work
213
if (haveMinimumCompatibleVersion("7.4")) {
214
openConnectionV3(host,port,info,database,url,d,password);
216
openConnectionV2(host,port,info,database,url,d,password);
218
} catch (SQLException sqle) {
219
// if we fail to completely establish a connection,
220
// close down the socket to not leak resources.
223
} catch (IOException ioe) { }
229
private void openConnectionV3(String p_host, int p_port, Properties p_info, String p_database, String p_url, Driver p_d, String p_password) throws SQLException
231
PGProtocolVersionMajor = 3;
233
Driver.debug("Using Protocol Version3");
235
// Now we need to construct and send an ssl startup packet
240
Driver.debug("Asking server if it supports ssl");
241
pgStream.SendInteger(8,4);
242
pgStream.SendInteger(80877103,4);
244
// now flush the ssl packets to the backend
247
// Now get the response from the backend, either an error message
248
// or an authentication request
249
int beresp = pgStream.ReceiveChar();
251
Driver.debug("Server response was (S=Yes,N=No): "+(char)beresp);
255
// An error occured, so pass the error message to the
258
// The most common one to be thrown here is:
259
// "User authentication failed"
261
throw new PSQLException("postgresql.con.misc", PSQLState.CONNECTION_REJECTED, pgStream.ReceiveString(encoding));
264
// Server does not support ssl
265
throw new PSQLException("postgresql.con.sslnotsupported", PSQLState.CONNECTION_FAILURE);
268
// Server supports ssl
270
Driver.debug("server does support ssl");
271
Driver.makeSSL(pgStream);
275
throw new PSQLException("postgresql.con.sslfail", PSQLState.CONNECTION_FAILURE);
279
catch (IOException e)
281
throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
285
// Now we need to construct and send a startup packet
288
new StartupPacket(PGProtocolVersionMajor,
289
PGProtocolVersionMinor,
291
p_database).writeTo(pgStream);
293
// now flush the startup packets to the backend
296
// Now get the response from the backend, either an error message
297
// or an authentication request
298
int areq = -1; // must have a value here
301
int beresp = pgStream.ReceiveChar();
303
byte [] md5Salt = new byte[4];
307
// An error occured, so pass the error message to the
310
// The most common one to be thrown here is:
311
// "User authentication failed"
313
int l_elen = pgStream.ReceiveIntegerR(4);
314
if (l_elen > 30000) {
315
//if the error length is > than 30000 we assume this is really a v2 protocol
316
//server so try again with a v2 connection
317
//need to create a new connection and try again
321
pgStream = new PGStream(p_host, p_port);
323
catch (ConnectException cex)
325
// Added by Peter Mount <peter@retep.org.uk>
326
// ConnectException is thrown when the connection cannot be made.
327
// we trap this an return a more meaningful message for the end user
328
throw new PSQLException ("postgresql.con.refused", PSQLState.CONNECTION_REJECTED);
330
catch (IOException e)
332
throw new PSQLException ("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
334
openConnectionV2(p_host, p_port, p_info, p_database, p_url, p_d, p_password);
337
throw new PSQLException("postgresql.con.misc", PSQLState.CONNECTION_REJECTED, PSQLException.parseServerError(encoding.decode(pgStream.Receive(l_elen-4))));
340
// Get the message length
341
int l_msgLen = pgStream.ReceiveIntegerR(4);
342
// Get the type of request
343
areq = pgStream.ReceiveIntegerR(4);
344
// Get the crypt password salt if there is one
345
if (areq == AUTH_REQ_CRYPT)
347
byte[] rst = new byte[2];
348
rst[0] = (byte)pgStream.ReceiveChar();
349
rst[1] = (byte)pgStream.ReceiveChar();
350
salt = new String(rst, 0, 2);
352
Driver.debug("Crypt salt=" + salt);
355
// Or get the md5 password salt if there is one
356
if (areq == AUTH_REQ_MD5)
359
md5Salt[0] = (byte)pgStream.ReceiveChar();
360
md5Salt[1] = (byte)pgStream.ReceiveChar();
361
md5Salt[2] = (byte)pgStream.ReceiveChar();
362
md5Salt[3] = (byte)pgStream.ReceiveChar();
363
if (Driver.logDebug) {
364
String md5SaltString = "";
365
for (int i=0; i<md5Salt.length; i++) {
366
md5SaltString += " " + md5Salt[i];
368
Driver.debug("MD5 salt=" + md5SaltString);
372
// now send the auth packet
380
Driver.debug("postgresql: KRB4");
381
throw new PSQLException("postgresql.con.kerb4", PSQLState.CONNECTION_REJECTED);
385
Driver.debug("postgresql: KRB5");
386
throw new PSQLException("postgresql.con.kerb5", PSQLState.CONNECTION_REJECTED);
390
Driver.debug("postgresql: SCM");
391
throw new PSQLException("postgresql.con.scm", PSQLState.CONNECTION_REJECTED);
394
case AUTH_REQ_PASSWORD:
396
Driver.debug("postgresql: PASSWORD");
397
pgStream.SendChar('p');
398
pgStream.SendInteger(5 + p_password.length(), 4);
399
pgStream.Send(p_password.getBytes());
400
pgStream.SendChar(0);
406
Driver.debug("postgresql: CRYPT");
407
String crypted = UnixCrypt.crypt(salt, p_password);
408
pgStream.SendChar('p');
409
pgStream.SendInteger(5 + crypted.length(), 4);
410
pgStream.Send(crypted.getBytes());
411
pgStream.SendChar(0);
417
Driver.debug("postgresql: MD5");
418
byte[] digest = MD5Digest.encode(PG_USER, p_password, md5Salt);
419
pgStream.SendChar('p');
420
pgStream.SendInteger(5 + digest.length, 4);
421
pgStream.Send(digest);
422
pgStream.SendChar(0);
427
throw new PSQLException("postgresql.con.auth", PSQLState.CONNECTION_REJECTED, new Integer(areq));
432
throw new PSQLException("postgresql.con.authfail", PSQLState.CONNECTION_REJECTED);
435
while (areq != AUTH_REQ_OK);
438
catch (IOException e)
440
throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
446
beresp = pgStream.ReceiveChar();
453
int l_msgLen = pgStream.ReceiveIntegerR(4);
454
if (l_msgLen != 12) throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
455
pid = pgStream.ReceiveIntegerR(4);
456
ckey = pgStream.ReceiveIntegerR(4);
459
int l_elen = pgStream.ReceiveIntegerR(4);
460
throw new PSQLException("postgresql.con.backend", PSQLState.CONNECTION_UNABLE_TO_CONNECT, PSQLException.parseServerError(encoding.decode(pgStream.Receive(l_elen-4))));
462
int l_nlen = pgStream.ReceiveIntegerR(4);
463
PSQLException notify = PSQLException.parseServerError(encoding.decode(pgStream.Receive(l_nlen-4)));
464
addWarning(notify.getMessage());
467
//TODO: handle parameter status messages
468
int l_len = pgStream.ReceiveIntegerR(4);
469
String l_pStatus = encoding.decode(pgStream.Receive(l_len-4));
471
Driver.debug("ParameterStatus="+ l_pStatus);
475
Driver.debug("invalid state="+ (char)beresp);
476
throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
479
while (beresp != 'Z');
480
// read ReadyForQuery
481
if (pgStream.ReceiveIntegerR(4) != 5) throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
482
//TODO: handle transaction status
483
char l_tStatus = (char)pgStream.ReceiveChar();
485
// "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte,
486
// otherwise it's hardcoded to 'SQL_ASCII'.
487
// If the backend doesn't know about multibyte we can't assume anything about the encoding
488
// used, so we denote this with 'UNKNOWN'.
489
//Note: begining with 7.2 we should be using pg_client_encoding() which
490
//is new in 7.2. However it isn't easy to conditionally call this new
491
//function, since we don't yet have the information as to what server
492
//version we are talking to. Thus we will continue to call
493
//getdatabaseencoding() until we drop support for 7.1 and older versions
494
//or until someone comes up with a conditional way to run one or
495
//the other function depending on server version that doesn't require
496
//two round trips to the server per connection
498
final String encodingQuery =
499
"case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end";
501
// Set datestyle and fetch db encoding in a single call, to avoid making
502
// more than one round trip to the backend during connection startup.
505
BaseResultSet resultSet
506
= execSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";");
508
if (! resultSet.next())
510
throw new PSQLException("postgresql.con.failed.bad.encoding", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
512
String version = resultSet.getString(1);
513
dbVersionNumber = extractVersionNumber(version);
515
String dbEncoding = resultSet.getString(2);
516
encoding = Encoding.getEncoding(dbEncoding, p_info.getProperty("charSet"));
517
//In 7.3 we are forced to do a second roundtrip to handle the case
518
//where a database may not be running in autocommit mode
519
//jdbc by default assumes autocommit is on until setAutoCommit(false)
520
//is called. Therefore we need to ensure a new connection is
521
//initialized to autocommit on.
522
//We also set the client encoding so that the driver only needs
523
//to deal with utf8. We can only do this in 7.3 because multibyte
524
//support is now always included
525
if (haveMinimumServerVersion("7.3"))
527
BaseResultSet acRset =
528
//TODO: if protocol V3 we can set the client encoding in startup
529
execSQL("set client_encoding = 'UNICODE'");
530
//set encoding to be unicode
531
encoding = Encoding.getEncoding("UNICODE", null);
535
// Initialise object handling
538
// Mark the connection as ok, and cleanup
539
PG_STATUS = CONNECTION_OK;
542
private void openConnectionV2(String host, int port, Properties info, String database, String url, Driver d, String password) throws SQLException
544
PGProtocolVersionMajor = 2;
546
Driver.debug("Using Protocol Version2");
548
// Now we need to construct and send an ssl startup packet
553
Driver.debug("Asking server if it supports ssl");
554
pgStream.SendInteger(8,4);
555
pgStream.SendInteger(80877103,4);
557
// now flush the ssl packets to the backend
560
// Now get the response from the backend, either an error message
561
// or an authentication request
562
int beresp = pgStream.ReceiveChar();
564
Driver.debug("Server response was (S=Yes,N=No): "+(char)beresp);
568
// An error occured, so pass the error message to the
571
// The most common one to be thrown here is:
572
// "User authentication failed"
574
throw new PSQLException("postgresql.con.misc", PSQLState.CONNECTION_REJECTED, pgStream.ReceiveString(encoding));
577
// Server does not support ssl
578
throw new PSQLException("postgresql.con.sslnotsupported", PSQLState.CONNECTION_FAILURE);
581
// Server supports ssl
583
Driver.debug("server does support ssl");
584
Driver.makeSSL(pgStream);
588
throw new PSQLException("postgresql.con.sslfail", PSQLState.CONNECTION_FAILURE);
592
catch (IOException e)
594
throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
598
// Now we need to construct and send a startup packet
601
new StartupPacket(PGProtocolVersionMajor,
602
PGProtocolVersionMinor,
604
database).writeTo(pgStream);
606
// now flush the startup packets to the backend
609
// Now get the response from the backend, either an error message
610
// or an authentication request
611
int areq = -1; // must have a value here
614
int beresp = pgStream.ReceiveChar();
616
byte [] md5Salt = new byte[4];
620
// An error occured, so pass the error message to the
623
// The most common one to be thrown here is:
624
// "User authentication failed"
626
throw new PSQLException("postgresql.con.misc", PSQLState.CONNECTION_REJECTED, pgStream.ReceiveString(encoding));
629
// Get the type of request
630
areq = pgStream.ReceiveIntegerR(4);
631
// Get the crypt password salt if there is one
632
if (areq == AUTH_REQ_CRYPT)
634
byte[] rst = new byte[2];
635
rst[0] = (byte)pgStream.ReceiveChar();
636
rst[1] = (byte)pgStream.ReceiveChar();
637
salt = new String(rst, 0, 2);
639
Driver.debug("Crypt salt=" + salt);
642
// Or get the md5 password salt if there is one
643
if (areq == AUTH_REQ_MD5)
646
md5Salt[0] = (byte)pgStream.ReceiveChar();
647
md5Salt[1] = (byte)pgStream.ReceiveChar();
648
md5Salt[2] = (byte)pgStream.ReceiveChar();
649
md5Salt[3] = (byte)pgStream.ReceiveChar();
650
if (Driver.logDebug) {
651
String md5SaltString = "";
652
for (int i=0; i<md5Salt.length; i++) {
653
md5SaltString += " " + md5Salt[i];
655
Driver.debug("MD5 salt=" + md5SaltString);
659
// now send the auth packet
667
Driver.debug("postgresql: KRB4");
668
throw new PSQLException("postgresql.con.kerb4", PSQLState.CONNECTION_REJECTED);
672
Driver.debug("postgresql: KRB5");
673
throw new PSQLException("postgresql.con.kerb5", PSQLState.CONNECTION_REJECTED);
675
case AUTH_REQ_PASSWORD:
677
Driver.debug("postgresql: PASSWORD");
678
pgStream.SendInteger(5 + password.length(), 4);
679
pgStream.Send(password.getBytes());
680
pgStream.SendInteger(0, 1);
686
Driver.debug("postgresql: CRYPT");
687
String crypted = UnixCrypt.crypt(salt, password);
688
pgStream.SendInteger(5 + crypted.length(), 4);
689
pgStream.Send(crypted.getBytes());
690
pgStream.SendInteger(0, 1);
696
Driver.debug("postgresql: MD5");
697
byte[] digest = MD5Digest.encode(PG_USER, password, md5Salt);
698
pgStream.SendInteger(5 + digest.length, 4);
699
pgStream.Send(digest);
700
pgStream.SendInteger(0, 1);
705
throw new PSQLException("postgresql.con.auth", PSQLState.CONNECTION_REJECTED, new Integer(areq));
710
throw new PSQLException("postgresql.con.authfail", PSQLState.CONNECTION_REJECTED);
713
while (areq != AUTH_REQ_OK);
716
catch (IOException e)
718
//Should be passing exception as arg.
719
throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
723
// As of protocol version 2.0, we should now receive the cancellation key and the pid
727
beresp = pgStream.ReceiveChar();
731
pid = pgStream.ReceiveIntegerR(4);
732
ckey = pgStream.ReceiveIntegerR(4);
735
throw new PSQLException("postgresql.con.backend", PSQLState.CONNECTION_UNABLE_TO_CONNECT, pgStream.ReceiveString(encoding));
737
addWarning(pgStream.ReceiveString(encoding));
740
throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
743
while (beresp == 'N');
745
// Expect ReadyForQuery packet
748
beresp = pgStream.ReceiveChar();
754
addWarning(pgStream.ReceiveString(encoding));
757
throw new PSQLException("postgresql.con.backend", PSQLState.CONNECTION_UNABLE_TO_CONNECT, pgStream.ReceiveString(encoding));
759
throw new PSQLException("postgresql.con.setup", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
762
while (beresp == 'N');
763
// "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte,
764
// otherwise it's hardcoded to 'SQL_ASCII'.
765
// If the backend doesn't know about multibyte we can't assume anything about the encoding
766
// used, so we denote this with 'UNKNOWN'.
767
//Note: begining with 7.2 we should be using pg_client_encoding() which
768
//is new in 7.2. However it isn't easy to conditionally call this new
769
//function, since we don't yet have the information as to what server
770
//version we are talking to. Thus we will continue to call
771
//getdatabaseencoding() until we drop support for 7.1 and older versions
772
//or until someone comes up with a conditional way to run one or
773
//the other function depending on server version that doesn't require
774
//two round trips to the server per connection
776
final String encodingQuery =
777
"case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end";
779
// Set datestyle and fetch db encoding in a single call, to avoid making
780
// more than one round trip to the backend during connection startup.
783
BaseResultSet resultSet
784
= execSQL("set datestyle to 'ISO'; select version(), " + encodingQuery + ";");
786
if (! resultSet.next())
788
throw new PSQLException("postgresql.con.failed.bad.encoding", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
790
String version = resultSet.getString(1);
791
dbVersionNumber = extractVersionNumber(version);
793
String dbEncoding = resultSet.getString(2);
794
encoding = Encoding.getEncoding(dbEncoding, info.getProperty("charSet"));
796
//TODO: remove this once the set is done as part of V3protocol connection initiation
797
if (haveMinimumServerVersion("7.4"))
799
BaseResultSet acRset =
800
execSQL("set client_encoding = 'UNICODE'");
802
//set encoding to be unicode
803
encoding = Encoding.getEncoding("UNICODE", null);
806
//In 7.3 we are forced to do a second roundtrip to handle the case
807
//where a database may not be running in autocommit mode
808
//jdbc by default assumes autocommit is on until setAutoCommit(false)
809
//is called. Therefore we need to ensure a new connection is
810
//initialized to autocommit on.
811
//We also set the client encoding so that the driver only needs
812
//to deal with utf8. We can only do this in 7.3+ because multibyte
813
//support is now always included
814
if (haveMinimumServerVersion("7.3") && !haveMinimumServerVersion("7.4"))
816
BaseResultSet acRset =
817
execSQL("set client_encoding = 'UNICODE'; show autocommit");
819
//set encoding to be unicode
820
encoding = Encoding.getEncoding("UNICODE", null);
824
throw new PSQLException("postgresql.con.failed.bad.autocommit", PSQLState.CONNECTION_UNABLE_TO_CONNECT);
826
//if autocommit is currently off we need to turn it on
827
//note that we will be in a transaction because the select above
828
//will have initiated the transaction so we need a commit
829
//to make the setting permanent
830
if (acRset.getString(1).equals("off"))
832
execSQL("set autocommit = on; commit;");
836
// Initialise object handling
839
// Mark the connection as ok, and cleanup
840
PG_STATUS = CONNECTION_OK;
844
* Return the instance of org.postgresql.Driver
845
* that created this connection
847
public Driver getDriver()
854
* This adds a warning to the warning chain.
855
* @param msg message to add
857
public void addWarning(String msg)
859
// Add the warning to the chain
860
if (firstWarning != null)
861
firstWarning.setNextWarning(new SQLWarning(msg));
863
firstWarning = new SQLWarning(msg);
865
// Now check for some specific messages
867
// This is obsolete in 6.5, but I've left it in here so if we need to use this
868
// technique again, we'll know where to place it.
870
// This is generated by the SQL "show datestyle"
871
//if (msg.startsWith("NOTICE:") && msg.indexOf("DateStyle")>0) {
872
//// 13 is the length off "DateStyle is "
873
//msg = msg.substring(msg.indexOf("DateStyle is ")+13);
875
//for(int i=0;i<dateStyles.length;i+=2)
876
//if (msg.startsWith(dateStyles[i]))
877
//currentDateStyle=i+1; // this is the index of the format
881
/** Simple query execution.
883
public BaseResultSet execSQL (String s) throws SQLException
885
final Object[] nullarr = new Object[0];
886
BaseStatement stat = (BaseStatement) createStatement();
887
return QueryExecutor.execute(new String[] { s },
893
* In SQL, a result table can be retrieved through a cursor that
894
* is named. The current row of a result can be updated or deleted
895
* using a positioned update/delete statement that references the
898
* We support one cursor per connection.
900
* setCursorName sets the cursor name.
902
* @param cursor the cursor name
903
* @exception SQLException if a database access error occurs
905
public void setCursorName(String cursor) throws SQLException
907
this.cursor = cursor;
911
* getCursorName gets the cursor name.
913
* @return the current cursor name
914
* @exception SQLException if a database access error occurs
916
public String getCursorName() throws SQLException
922
* We are required to bring back certain information by
923
* the DatabaseMetaData class. These functions do that.
925
* Method getURL() brings back the URL (good job we saved it)
928
* @exception SQLException just in case...
930
public String getURL() throws SQLException
936
* Method getUserName() brings back the User Name (again, we
939
* @return the user name
940
* @exception SQLException just in case...
943
public String getUserName() throws SQLException
949
* Get the character encoding to use for this connection.
951
public Encoding getEncoding() throws SQLException
957
* This returns the Fastpath API for the current connection.
959
* <p><b>NOTE:</b> This is not part of JDBC, but allows access to
960
* functions on the org.postgresql backend itself.
962
* <p>It is primarily used by the LargeObject API
964
* <p>The best way to use this is as follows:
967
* import org.postgresql.fastpath.*;
969
* Fastpath fp = ((org.postgresql.Connection)myconn).getFastpathAPI();
972
* <p>where myconn is an open Connection to org.postgresql.
974
* @return Fastpath object allowing access to functions on the org.postgresql
976
* @exception SQLException by Fastpath when initialising for first time
978
public Fastpath getFastpathAPI() throws SQLException
980
if (fastpath == null)
981
fastpath = new Fastpath(this, pgStream);
985
// This holds a reference to the Fastpath API if already open
986
private Fastpath fastpath = null;
989
* This returns the LargeObject API for the current connection.
991
* <p><b>NOTE:</b> This is not part of JDBC, but allows access to
992
* functions on the org.postgresql backend itself.
994
* <p>The best way to use this is as follows:
997
* import org.postgresql.largeobject.*;
999
* LargeObjectManager lo = ((org.postgresql.Connection)myconn).getLargeObjectAPI();
1002
* <p>where myconn is an open Connection to org.postgresql.
1004
* @return LargeObject object that implements the API
1005
* @exception SQLException by LargeObject when initialising for first time
1007
public LargeObjectManager getLargeObjectAPI() throws SQLException
1009
if (largeobject == null)
1010
largeobject = new LargeObjectManager(this);
1014
// This holds a reference to the LargeObject API if already open
1015
private LargeObjectManager largeobject = null;
1018
* This method is used internally to return an object based around
1019
* org.postgresql's more unique data types.
1021
* <p>It uses an internal Hashtable to get the handling class. If the
1022
* type is not supported, then an instance of org.postgresql.util.PGobject
1025
* You can use the getValue() or setValue() methods to handle the returned
1026
* object. Custom objects can have their own methods.
1028
* @return PGobject for this type, and set to value
1029
* @exception SQLException if value is not correct for this type
1031
public Object getObject(String type, String value) throws SQLException
1035
Object o = objectTypes.get(type);
1037
// If o is null, then the type is unknown.
1038
// If o is not null, and it is a String, then its a class name that
1039
// extends PGobject.
1041
// This is used to implement the org.postgresql unique types (like lseg,
1043
if (o != null && o instanceof String)
1045
// 6.3 style extending PG_Object
1046
PGobject obj = null;
1047
obj = (PGobject)(Class.forName((String)o).newInstance());
1049
obj.setValue(value);
1053
catch (SQLException sx)
1055
// rethrow the exception. Done because we capture any others next
1056
sx.fillInStackTrace();
1059
catch (Exception ex)
1061
throw new PSQLException("postgresql.con.creobj", PSQLState.CONNECTION_FAILURE, type, ex);
1064
// should never be reached
1069
* This allows client code to add a handler for one of org.postgresql's
1070
* more unique data types.
1072
* <p><b>NOTE:</b> This is not part of JDBC, but an extension.
1074
* <p>The best way to use this is as follows:
1078
* ((org.postgresql.Connection)myconn).addDataType("mytype","my.class.name");
1082
* <p>where myconn is an open Connection to org.postgresql.
1084
* <p>The handling class must extend org.postgresql.util.PGobject
1086
* @see org.postgresql.util.PGobject
1088
public void addDataType(String type, String name)
1090
objectTypes.put(type, name);
1093
// This holds the available types
1094
private Hashtable objectTypes = new Hashtable();
1096
// This array contains the types that are supported as standard.
1098
// The first entry is the types name on the database, the second
1099
// the full class name of the handling class.
1101
private static final String defaultObjectTypes[][] = {
1102
{"box", "org.postgresql.geometric.PGbox"},
1103
{"circle", "org.postgresql.geometric.PGcircle"},
1104
{"line", "org.postgresql.geometric.PGline"},
1105
{"lseg", "org.postgresql.geometric.PGlseg"},
1106
{"path", "org.postgresql.geometric.PGpath"},
1107
{"point", "org.postgresql.geometric.PGpoint"},
1108
{"polygon", "org.postgresql.geometric.PGpolygon"},
1109
{"money", "org.postgresql.util.PGmoney"}
1112
// This initialises the objectTypes hashtable
1113
private void initObjectTypes()
1115
for (int i = 0;i < defaultObjectTypes.length;i++)
1116
objectTypes.put(defaultObjectTypes[i][0], defaultObjectTypes[i][1]);
1120
* In some cases, it is desirable to immediately release a Connection's
1121
* database and JDBC resources instead of waiting for them to be
1122
* automatically released (cant think why off the top of my head)
1124
* <B>Note:</B> A Connection is automatically closed when it is
1125
* garbage collected. Certain fatal errors also result in a closed
1128
* @exception SQLException if a database access error occurs
1130
public void close() throws SQLException
1132
if (getPGProtocolVersionMajor() == 3) {
1139
public void closeV3() throws SQLException
1141
if (pgStream != null)
1145
pgStream.SendChar('X');
1146
pgStream.SendInteger(4,4);
1150
catch (IOException e)
1159
public void closeV2() throws SQLException
1161
if (pgStream != null)
1165
pgStream.SendChar('X');
1169
catch (IOException e)
1179
* A driver may convert the JDBC sql grammar into its system's
1180
* native SQL grammar prior to sending it; nativeSQL returns the
1181
* native form of the statement that the driver would have sent.
1183
* @param sql a SQL statement that may contain one or more '?'
1184
* parameter placeholders
1185
* @return the native form of this statement
1186
* @exception SQLException if a database access error occurs
1188
public String nativeSQL(String sql) throws SQLException
1194
* The first warning reported by calls on this Connection is
1197
* <B>Note:</B> Sebsequent warnings will be changed to this
1200
* @return the first SQLWarning or null
1201
* @exception SQLException if a database access error occurs
1203
public SQLWarning getWarnings() throws SQLException
1205
return firstWarning;
1209
* After this call, getWarnings returns null until a new warning
1210
* is reported for this connection.
1212
* @exception SQLException if a database access error occurs
1214
public void clearWarnings() throws SQLException
1216
firstWarning = null;
1221
* You can put a connection in read-only mode as a hunt to enable
1222
* database optimizations
1224
* <B>Note:</B> setReadOnly cannot be called while in the middle
1227
* @param readOnly - true enables read-only mode; false disables it
1228
* @exception SQLException if a database access error occurs
1230
public void setReadOnly(boolean readOnly) throws SQLException
1232
this.readOnly = readOnly;
1236
* Tests to see if the connection is in Read Only Mode. Note that
1237
* we cannot really put the database in read only mode, but we pretend
1238
* we can by returning the value of the readOnly flag
1240
* @return true if the connection is read only
1241
* @exception SQLException if a database access error occurs
1243
public boolean isReadOnly() throws SQLException
1249
* If a connection is in auto-commit mode, than all its SQL
1250
* statements will be executed and committed as individual
1251
* transactions. Otherwise, its SQL statements are grouped
1252
* into transactions that are terminated by either commit()
1253
* or rollback(). By default, new connections are in auto-
1254
* commit mode. The commit occurs when the statement completes
1255
* or the next execute occurs, whichever comes first. In the
1256
* case of statements returning a ResultSet, the statement
1257
* completes when the last row of the ResultSet has been retrieved
1258
* or the ResultSet has been closed. In advanced cases, a single
1259
* statement may return multiple results as well as output parameter
1260
* values. Here the commit occurs when all results and output param
1261
* values have been retrieved.
1263
* @param autoCommit - true enables auto-commit; false disables it
1264
* @exception SQLException if a database access error occurs
1266
public void setAutoCommit(boolean autoCommit) throws SQLException
1268
if (this.autoCommit == autoCommit)
1276
if (haveMinimumServerVersion("7.1"))
1278
execSQL("begin;" + getIsolationLevelSQL());
1283
execSQL(getIsolationLevelSQL());
1286
this.autoCommit = autoCommit;
1290
* gets the current auto-commit state
1292
* @return Current state of the auto-commit mode
1293
* @see setAutoCommit
1295
public boolean getAutoCommit()
1297
return this.autoCommit;
1301
* The method commit() makes all changes made since the previous
1302
* commit/rollback permanent and releases any database locks currently
1303
* held by the Connection. This method should only be used when
1304
* auto-commit has been disabled. (If autoCommit == true, then we
1305
* just return anyhow)
1307
* @exception SQLException if a database access error occurs
1308
* @see setAutoCommit
1310
public void commit() throws SQLException
1314
//TODO: delay starting new transaction until first command
1315
if (haveMinimumServerVersion("7.1"))
1317
execSQL("commit;begin;" + getIsolationLevelSQL());
1323
execSQL(getIsolationLevelSQL());
1328
* The method rollback() drops all changes made since the previous
1329
* commit/rollback and releases any database locks currently held by
1332
* @exception SQLException if a database access error occurs
1335
public void rollback() throws SQLException
1339
//TODO: delay starting transaction until first command
1340
if (haveMinimumServerVersion("7.1"))
1342
execSQL("rollback; begin;" + getIsolationLevelSQL());
1346
execSQL("rollback");
1348
execSQL(getIsolationLevelSQL());
1353
* Get this Connection's current transaction isolation mode.
1355
* @return the current TRANSACTION_* mode value
1356
* @exception SQLException if a database access error occurs
1358
public int getTransactionIsolation() throws SQLException
1360
String sql = "show transaction isolation level";
1361
String level = null;
1362
if (haveMinimumServerVersion("7.3")) {
1363
BaseResultSet rs = execSQL(sql);
1365
level = rs.getString(1);
1369
BaseResultSet l_rs = execSQL(sql);
1370
BaseStatement l_stat = l_rs.getPGStatement();
1371
SQLWarning warning = l_stat.getWarnings();
1372
if (warning != null)
1374
level = warning.getMessage();
1379
if (level != null) {
1380
level = level.toUpperCase();
1381
if (level.indexOf("READ COMMITTED") != -1)
1382
return Connection.TRANSACTION_READ_COMMITTED;
1383
else if (level.indexOf("READ UNCOMMITTED") != -1)
1384
return Connection.TRANSACTION_READ_UNCOMMITTED;
1385
else if (level.indexOf("REPEATABLE READ") != -1)
1386
return Connection.TRANSACTION_REPEATABLE_READ;
1387
else if (level.indexOf("SERIALIZABLE") != -1)
1388
return Connection.TRANSACTION_SERIALIZABLE;
1390
return Connection.TRANSACTION_READ_COMMITTED;
1394
* You can call this method to try to change the transaction
1395
* isolation level using one of the TRANSACTION_* values.
1397
* <B>Note:</B> setTransactionIsolation cannot be called while
1398
* in the middle of a transaction
1400
* @param level one of the TRANSACTION_* isolation values with
1401
* the exception of TRANSACTION_NONE; some databases may
1402
* not support other values
1403
* @exception SQLException if a database access error occurs
1404
* @see java.sql.DatabaseMetaData#supportsTransactionIsolationLevel
1406
public void setTransactionIsolation(int level) throws SQLException
1408
//In 7.1 and later versions of the server it is possible using
1409
//the "set session" command to set this once for all future txns
1410
//however in 7.0 and prior versions it is necessary to set it in
1411
//each transaction, thus adding complexity below.
1412
//When we decide to drop support for servers older than 7.1
1413
//this can be simplified
1414
isolationLevel = level;
1415
String isolationLevelSQL;
1417
if (!haveMinimumServerVersion("7.1"))
1419
isolationLevelSQL = getIsolationLevelSQL();
1423
isolationLevelSQL = "SET SESSION CHARACTERISTICS AS TRANSACTION ISOLATION LEVEL ";
1424
switch (isolationLevel)
1426
case Connection.TRANSACTION_READ_COMMITTED:
1427
isolationLevelSQL += "READ COMMITTED";
1429
case Connection.TRANSACTION_SERIALIZABLE:
1430
isolationLevelSQL += "SERIALIZABLE";
1433
throw new PSQLException("postgresql.con.isolevel", PSQLState.TRANSACTION_STATE_INVALID,
1434
new Integer(isolationLevel));
1437
execSQL(isolationLevelSQL);
1441
* Helper method used by setTransactionIsolation(), commit(), rollback()
1442
* and setAutoCommit(). This returns the SQL string needed to
1443
* set the isolation level for a transaction. In 7.1 and later it
1444
* is possible to set a default isolation level that applies to all
1445
* future transactions, this method is only necesary for 7.0 and older
1446
* servers, and should be removed when support for these older
1447
* servers are dropped
1449
protected String getIsolationLevelSQL() throws SQLException
1451
//7.1 and higher servers have a default specified so
1452
//no additional SQL is required to set the isolation level
1453
if (haveMinimumServerVersion("7.1"))
1457
StringBuffer sb = new StringBuffer("SET TRANSACTION ISOLATION LEVEL");
1459
switch (isolationLevel)
1461
case Connection.TRANSACTION_READ_COMMITTED:
1462
sb.append(" READ COMMITTED");
1465
case Connection.TRANSACTION_SERIALIZABLE:
1466
sb.append(" SERIALIZABLE");
1470
throw new PSQLException("postgresql.con.isolevel", PSQLState.TRANSACTION_STATE_INVALID, new Integer(isolationLevel));
1472
return sb.toString();
1476
* A sub-space of this Connection's database may be selected by
1477
* setting a catalog name. If the driver does not support catalogs,
1478
* it will silently ignore this request
1480
* @exception SQLException if a database access error occurs
1482
public void setCatalog(String catalog) throws SQLException
1488
* Return the connections current catalog name, or null if no
1489
* catalog name is set, or we dont support catalogs.
1491
* @return the current catalog name or null
1492
* @exception SQLException if a database access error occurs
1494
public String getCatalog() throws SQLException
1500
* Overides finalize(). If called, it closes the connection.
1502
* This was done at the request of Rachel Greenham
1503
* <rachel@enlarion.demon.co.uk> who hit a problem where multiple
1504
* clients didn't close the connection, and once a fortnight enough
1505
* clients were open to kill the org.postgres server.
1507
public void finalize() throws Throwable
1512
private static String extractVersionNumber(String fullVersionString)
1514
StringTokenizer versionParts = new StringTokenizer(fullVersionString);
1515
versionParts.nextToken(); /* "PostgreSQL" */
1516
return versionParts.nextToken(); /* "X.Y.Z" */
1520
* Get server version number
1522
public String getDBVersionNumber()
1524
return dbVersionNumber;
1527
// Parse a "dirty" integer surrounded by non-numeric characters
1528
private static int integerPart(String dirtyString)
1532
for (start = 0; start < dirtyString.length() && !Character.isDigit(dirtyString.charAt(start)); ++start)
1535
for (end = start; end < dirtyString.length() && Character.isDigit(dirtyString.charAt(end)); ++end)
1541
return Integer.parseInt(dirtyString.substring(start, end));
1545
* Get server major version
1547
public int getServerMajorVersion()
1551
StringTokenizer versionTokens = new StringTokenizer(dbVersionNumber, "."); // aaXbb.ccYdd
1552
return integerPart(versionTokens.nextToken()); // return X
1554
catch (NoSuchElementException e)
1561
* Get server minor version
1563
public int getServerMinorVersion()
1567
StringTokenizer versionTokens = new StringTokenizer(dbVersionNumber, "."); // aaXbb.ccYdd
1568
versionTokens.nextToken(); // Skip aaXbb
1569
return integerPart(versionTokens.nextToken()); // return Y
1571
catch (NoSuchElementException e)
1578
* Is the server we are connected to running at least this version?
1579
* This comparison method will fail whenever a major or minor version
1580
* goes to two digits (10.3.0) or (7.10.1).
1582
public boolean haveMinimumServerVersion(String ver) throws SQLException
1584
return (getDBVersionNumber().compareTo(ver) >= 0);
1588
* This method returns true if the compatible level set in the connection
1589
* (which can be passed into the connection or specified in the URL)
1590
* is at least the value passed to this method. This is used to toggle
1591
* between different functionality as it changes across different releases
1592
* of the jdbc driver code. The values here are versions of the jdbc client
1593
* and not server versions. For example in 7.1 get/setBytes worked on
1594
* LargeObject values, in 7.2 these methods were changed to work on bytea
1595
* values. This change in functionality could be disabled by setting the
1596
* "compatible" level to be 7.1, in which case the driver will revert to
1597
* the 7.1 functionality.
1599
public boolean haveMinimumCompatibleVersion(String ver) throws SQLException
1601
return (compatible.compareTo(ver) >= 0);
1606
* This returns the java.sql.Types type for a PG type oid
1608
* @param oid PostgreSQL type oid
1609
* @return the java.sql.Types type
1610
* @exception SQLException if a database access error occurs
1612
public int getSQLType(int oid) throws SQLException
1614
Integer sqlType = (Integer)sqlTypeCache.get(new Integer(oid));
1616
// it's not in the cache, so perform a query, and add the result to the cache
1617
if (sqlType == null)
1620
// The opaque type does not exist in the system catalogs.
1625
if (haveMinimumServerVersion("7.3")) {
1626
sql = "SELECT typname FROM pg_catalog.pg_type WHERE oid = " +oid;
1628
sql = "SELECT typname FROM pg_type WHERE oid = " +oid;
1630
BaseResultSet result = execSQL(sql);
1631
if (result.getColumnCount() != 1 || result.getTupleCount() != 1) {
1632
throw new PSQLException("postgresql.unexpected", PSQLState.UNEXPECTED_ERROR);
1635
pgType = result.getString(1);
1638
Integer iOid = new Integer(oid);
1639
sqlType = new Integer(getSQLType(pgType));
1640
sqlTypeCache.put(iOid, sqlType);
1641
pgTypeCache.put(iOid, pgType);
1644
return sqlType.intValue();
1648
* This returns the oid for a given PG data type
1649
* @param typeName PostgreSQL type name
1650
* @return PostgreSQL oid value for a field of this type
1652
public int getPGType(String typeName) throws SQLException
1655
if (typeName != null)
1657
Integer oidValue = (Integer) typeOidCache.get(typeName);
1658
if (oidValue != null)
1660
oid = oidValue.intValue();
1664
// it's not in the cache, so perform a query, and add the result to the cache
1666
if (haveMinimumServerVersion("7.3")) {
1667
sql = "SELECT oid FROM pg_catalog.pg_type WHERE typname='" + typeName + "'";
1669
sql = "SELECT oid FROM pg_type WHERE typname='" + typeName + "'";
1671
BaseResultSet result = execSQL(sql);
1672
if (result.getColumnCount() != 1 || result.getTupleCount() != 1)
1673
throw new PSQLException("postgresql.unexpected", PSQLState.UNEXPECTED_ERROR);
1675
oid = Integer.parseInt(result.getString(1));
1676
typeOidCache.put(typeName, new Integer(oid));
1684
* We also need to get the PG type name as returned by the back end.
1686
* @return the String representation of the type of this field
1687
* @exception SQLException if a database access error occurs
1689
public String getPGType(int oid) throws SQLException
1691
String pgType = (String) pgTypeCache.get(new Integer(oid));
1695
pgType = (String) pgTypeCache.get(new Integer(oid));
1700
//Because the get/setLogStream methods are deprecated in JDBC2
1701
//we use them for JDBC1 here and override this method in the jdbc2
1702
//version of this class
1703
protected void enableDriverManagerLogging()
1705
if (DriverManager.getLogStream() == null)
1707
DriverManager.setLogStream(System.out);
1711
// This is a cache of the DatabaseMetaData instance for this connection
1712
protected java.sql.DatabaseMetaData metadata;
1716
* Tests to see if a Connection is closed
1718
* @return the status of the connection
1719
* @exception SQLException (why?)
1721
public boolean isClosed() throws SQLException
1723
return (pgStream == null);
1727
* This implemetation uses the jdbc1Types array to support the jdbc1
1728
* datatypes. Basically jdbc1 and jdbc2 are the same, except that
1729
* jdbc2 adds the Array types.
1731
public int getSQLType(String pgTypeName)
1733
int sqlType = Types.OTHER; // default value
1734
for (int i = 0;i < jdbc1Types.length;i++)
1736
if (pgTypeName.equals(jdbc1Types[i]))
1738
sqlType = jdbc1Typei[i];
1746
* This table holds the org.postgresql names for the types supported.
1747
* Any types that map to Types.OTHER (eg POINT) don't go into this table.
1748
* They default automatically to Types.OTHER
1750
* Note: This must be in the same order as below.
1752
* Tip: keep these grouped together by the Types. value
1754
private static final String jdbc1Types[] = {
1762
"bpchar", "char", "char2", "char4", "char8", "char16",
1763
"varchar", "text", "name", "filename",
1769
"abstime", "timestamp", "timestamptz"
1773
* This table holds the JDBC type for each entry above.
1775
* Note: This must be in the same order as above
1777
* Tip: keep these grouped together by the Types. value
1779
private static final int jdbc1Typei[] = {
1781
Types.INTEGER, Types.INTEGER,
1783
Types.DOUBLE, Types.DOUBLE,
1787
Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR, Types.CHAR,
1788
Types.VARCHAR, Types.VARCHAR, Types.VARCHAR, Types.VARCHAR,
1794
Types.TIMESTAMP, Types.TIMESTAMP, Types.TIMESTAMP
1797
public void cancelQuery() throws SQLException
1799
org.postgresql.core.PGStream cancelStream = null;
1802
cancelStream = new org.postgresql.core.PGStream(PG_HOST, PG_PORT);
1804
catch (ConnectException cex)
1806
// Added by Peter Mount <peter@retep.org.uk>
1807
// ConnectException is thrown when the connection cannot be made.
1808
// we trap this an return a more meaningful message for the end user
1809
throw new PSQLException ("postgresql.con.refused", PSQLState.CONNECTION_REJECTED);
1811
catch (IOException e)
1813
throw new PSQLException ("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
1816
// Now we need to construct and send a cancel packet
1819
cancelStream.SendInteger(16, 4);
1820
cancelStream.SendInteger(80877102, 4);
1821
cancelStream.SendInteger(pid, 4);
1822
cancelStream.SendInteger(ckey, 4);
1823
cancelStream.flush();
1825
catch (IOException e)
1827
throw new PSQLException("postgresql.con.failed", PSQLState.CONNECTION_UNABLE_TO_CONNECT, e);
1833
if (cancelStream != null)
1834
cancelStream.close();
1836
catch (IOException e)
1842
//Methods to support postgres notifications
1843
public void addNotification(org.postgresql.PGNotification p_notification)
1845
if (m_notifications == null)
1846
m_notifications = new Vector();
1847
m_notifications.addElement(p_notification);
1850
public PGNotification[] getNotifications()
1852
PGNotification[] l_return = null;
1853
if (m_notifications != null)
1855
l_return = new PGNotification[m_notifications.size()];
1856
m_notifications.copyInto(l_return);
1858
m_notifications = null;