@@ -34,6 +34,9 @@ public class Connection implements java.sql.Connection
3434// This is set by postgresql.Statement.setMaxRows()
3535protected int maxrows =0 ;// maximum no. of rows; 0 = unlimited
3636
37+ // This is a cache of the DatabaseMetaData instance for this connection
38+ protected DatabaseMetaData metadata ;
39+
3740private String PG_HOST ;
3841private int PG_PORT ;
3942private String PG_USER ;
@@ -44,17 +47,6 @@ public class Connection implements java.sql.Connection
4447public boolean CONNECTION_OK =true ;
4548public boolean CONNECTION_BAD =false ;
4649
47- //private static final int STARTUP_LEN = 288;// Length of a startup packet
48-
49- // These are defined in src/include/libpq/pqcomm.h
50- //private int STARTUP_CODE = STARTUP_USER;
51- //private static final int STARTUP_USER = 7;// User auth
52- //private static final int STARTUP_KRB4 = 10;// Kerberos 4 (unused)
53- //private static final int STARTUP_KRB5 = 11;// Kerberos 5 (unused)
54- //private static final int STARTUP_HBA = 12;// Host Based
55- //private static final int STARTUP_NONE = 13;// Unauthenticated (unused)
56- //private static final int STARTUP_PASS = 14;// Password auth
57-
5850private boolean autoCommit =true ;
5951private boolean readOnly =false ;
6052
@@ -88,12 +80,6 @@ public class Connection implements java.sql.Connection
8880// be across all connections, which could be to different backends.
8981protected Hashtable fieldCache =new Hashtable ();
9082
91- // This is used by Field to cache oid -> names.
92- // It's here, because it's shared across this connection only.
93- // Hence it cannot be static within the Field class, because it would then
94- // be across all connections, which could be to different backends.
95- protected Hashtable fieldCache =new Hashtable ();
96-
9783/**
9884 * This is the current date style of the backend
9985 */
@@ -150,8 +136,6 @@ public class Connection implements java.sql.Connection
150136 */
151137public Connection (String host ,int port ,Properties info ,String database ,String url ,Driver d )throws SQLException
152138 {
153- //int len = STARTUP_LEN;// Length of a startup packet
154-
155139// Throw an exception if the user or password properties are missing
156140// This occasionally occurs when the client uses the properties version
157141// of getConnection(), and is a common question on the email lists
@@ -169,61 +153,33 @@ public Connection(String host, int port, Properties info, String database, Strin
169153PG_HOST =new String (host );
170154PG_STATUS =CONNECTION_BAD ;
171155
172- // Pre 6.3 code
173- // This handles the auth property. Any value begining with p enables
174- // password authentication, while anything begining with i enables
175- // ident (RFC 1413) authentication. Any other values default to trust.
176- //
177- // Also, the postgresql.auth system property can be used to change the
178- // local default, if the auth property is not present.
179- //
180- //String auth = info.getProperty("auth",System.getProperty("postgresql.auth","trust")).toLowerCase();
181- //if(auth.startsWith("p")) {
182- //// Password authentication
183- //STARTUP_CODE=STARTUP_PASS;
184- //} else if(auth.startsWith("i")) {
185- //// Ident (RFC 1413) authentication
186- //STARTUP_CODE=STARTUP_HBA;
187- //} else {
188- //// Anything else defaults to trust authentication
189- //STARTUP_CODE=STARTUP_USER;
190- //}
191-
192156// Now make the initial connection
193157try
194158 {
195159pg_stream =new PG_Stream (host ,port );
160+ }catch (ConnectException cex ) {
161+ // Added by Peter Mount <peter@retep.org.uk>
162+ // ConnectException is thrown when the connection cannot be made.
163+ // we trap this an return a more meaningful message for the end user
164+ throw new SQLException ("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." );
196165 }catch (IOException e ) {
197166throw new SQLException ("Connection failed: " +e .toString ());
198167 }
199168
200169// Now we need to construct and send a startup packet
201170try
202171{
203- // Pre 6.3 code
204- //pg_stream.SendInteger(len, 4);len -= 4;
205- //pg_stream.SendInteger(STARTUP_CODE, 4);len -= 4;
206- //pg_stream.Send(database.getBytes(), 64);len -= 64;
207- //pg_stream.Send(PG_USER.getBytes(), len);
208- //
209- //// Send the password packet if required
210- //if(STARTUP_CODE == STARTUP_PASS) {
211- //len=STARTUP_LEN;
212- //pg_stream.SendInteger(len, 4);len -= 4;
213- //pg_stream.SendInteger(STARTUP_PASS, 4);len -= 4;
214- //pg_stream.Send(PG_USER.getBytes(), PG_USER.length());
215- //len-=PG_USER.length();
216- //pg_stream.SendInteger(0,1);len -= 1;
217- //pg_stream.Send(PG_PASSWORD.getBytes(), len);
218- //}
219-
220172// Ver 6.3 code
221173pg_stream .SendInteger (4 +4 +SM_DATABASE +SM_USER +SM_OPTIONS +SM_UNUSED +SM_TTY ,4 );
222174pg_stream .SendInteger (PG_PROTOCOL_LATEST_MAJOR ,2 );
223175pg_stream .SendInteger (PG_PROTOCOL_LATEST_MINOR ,2 );
224176pg_stream .Send (database .getBytes (),SM_DATABASE );
177+
178+ // This last send includes the unused fields
225179pg_stream .Send (PG_USER .getBytes (),SM_USER +SM_OPTIONS +SM_UNUSED +SM_TTY );
226- // The last send includes the unused fields
180+
181+ // now flush the startup packets to the backend
182+ pg_stream .flush ();
227183
228184// Now get the response from the backend, either an error message
229185// or an authentication request
@@ -233,6 +189,12 @@ public Connection(String host, int port, Properties info, String database, Strin
233189switch (beresp )
234190 {
235191case 'E' :
192+ // An error occured, so pass the error message to the
193+ // user.
194+ //
195+ // The most common one to be thrown here is:
196+ // "User authentication failed"
197+ //
236198throw new SQLException (pg_stream .ReceiveString (4096 ));
237199
238200case 'R' :
@@ -267,7 +229,7 @@ public Connection(String host, int port, Properties info, String database, Strin
267229pg_stream .SendInteger (5 +PG_PASSWORD .length (),4 );
268230pg_stream .Send (PG_PASSWORD .getBytes ());
269231pg_stream .SendInteger (0 ,1 );
270- // pg_stream.SendPacket(PG_PASSWORD.getBytes() );
232+ pg_stream .flush ( );
271233break ;
272234
273235case AUTH_REQ_CRYPT :
@@ -276,11 +238,11 @@ public Connection(String host, int port, Properties info, String database, Strin
276238pg_stream .SendInteger (5 +crypted .length (),4 );
277239pg_stream .Send (crypted .getBytes ());
278240pg_stream .SendInteger (0 ,1 );
279- // pg_stream.SendPacket(UnixCrypt.crypt(salt,PG_PASSWORD).getBytes() );
241+ pg_stream .flush ( );
280242break ;
281243
282244default :
283- throw new SQLException ("Authentication type " +areq +" not supported" );
245+ throw new SQLException ("Authentication type " +areq +" not supported. Check that you have configured the pg_hba.conf file to include the client's IP address or Subnet, and is using a supported authentication scheme. " );
284246 }
285247break ;
286248
@@ -511,7 +473,9 @@ public boolean isClosed() throws SQLException
511473 */
512474public java .sql .DatabaseMetaData getMetaData ()throws SQLException
513475 {
514- return new DatabaseMetaData (this );
476+ if (metadata ==null )
477+ metadata =new DatabaseMetaData (this );
478+ return metadata ;
515479 }
516480
517481/**
@@ -631,8 +595,6 @@ public void clearWarnings() throws SQLException
631595 */
632596public void addWarning (String msg )
633597 {
634- //PrintStream log = DriverManager.getLogStream();
635- //if(log!=null)
636598DriverManager .println (msg );
637599
638600// Add the warning to the chain
@@ -691,6 +653,7 @@ public synchronized ResultSet ExecSQL(String sql) throws SQLException
691653buf =sql .getBytes ();
692654pg_stream .Send (buf );
693655pg_stream .SendChar (0 );
656+ pg_stream .flush ();
694657 }catch (IOException e ) {
695658throw new SQLException ("I/O Error: " +e .toString ());
696659 }
@@ -726,6 +689,7 @@ public synchronized ResultSet ExecSQL(String sql) throws SQLException
726689pg_stream .SendChar ('Q' );
727690pg_stream .SendChar (' ' );
728691pg_stream .SendChar (0 );
692+ pg_stream .flush ();
729693 }catch (IOException e ) {
730694throw new SQLException ("I/O Error: " +e .toString ());
731695 }
@@ -964,6 +928,8 @@ protected Object getObject(String type,String value) throws SQLException
964928return ((Serialize )o ).fetch (Integer .parseInt (value ));
965929 }
966930 }catch (SQLException sx ) {
931+ // rethrow the exception. Done because we capture any others next
932+ sx .fillInStackTrace ();
967933throw sx ;
968934 }catch (Exception ex ) {
969935throw new SQLException ("Failed to create object for " +type +": " +ex );
@@ -999,14 +965,17 @@ protected int putObject(Object o) throws SQLException
999965// If so, then call it's fetch method.
1000966if (x instanceof Serialize )
1001967return ((Serialize )x ).store (o );
968+
969+ // Thow an exception because the type is unknown
970+ throw new SQLException ("The object could not be stored. Check that any tables required have already been created in the database." );
971+
1002972 }catch (SQLException sx ) {
973+ // rethrow the exception. Done because we capture any others next
974+ sx .fillInStackTrace ();
1003975throw sx ;
1004976 }catch (Exception ex ) {
1005977throw new SQLException ("Failed to store object: " +ex );
1006978 }
1007-
1008- // should never be reached
1009- return 0 ;
1010979 }
1011980
1012981/**
@@ -1045,10 +1014,12 @@ public void addDataType(String type,String name)
10451014private static final String defaultObjectTypes [][] = {
10461015 {"box" ,"postgresql.geometric.PGbox" },
10471016 {"circle" ,"postgresql.geometric.PGcircle" },
1017+ {"line" ,"postgresql.geometric.PGline" },
10481018 {"lseg" ,"postgresql.geometric.PGlseg" },
10491019 {"path" ,"postgresql.geometric.PGpath" },
10501020 {"point" ,"postgresql.geometric.PGpoint" },
1051- {"polygon" ,"postgresql.geometric.PGpolygon" }
1021+ {"polygon" ,"postgresql.geometric.PGpolygon" },
1022+ {"money" ,"postgresql.util.PGmoney" }
10521023 };
10531024
10541025// This initialises the objectTypes hashtable