88import org .postgresql .fastpath .*;
99import org .postgresql .largeobject .*;
1010import org .postgresql .util .*;
11+ import org .postgresql .core .Encoding ;
1112
1213/**
13- * $Id: Connection.java,v 1.18 2001/07/15 04:21:26 momjian Exp $
14+ * $Id: Connection.java,v 1.19 2001/07/21 18:52:10 momjian Exp $
1415 *
1516 * This abstract class is used by org.postgresql.Driver to open either the JDBC1 or
1617 * JDBC2 versions of the Connection class.
@@ -33,11 +34,8 @@ public abstract class Connection
3334
3435/**
3536 * The encoding to use for this connection.
36- * If <b>null</b>, the encoding has not been specified by the
37- * user, and the default encoding for the platform should be
38- * used.
3937 */
40- private String encoding ;
38+ private Encoding encoding = Encoding . defaultEncoding () ;
4139
4240public boolean CONNECTION_OK =true ;
4341public boolean CONNECTION_BAD =false ;
@@ -162,7 +160,7 @@ protected void openConnection(String host, int port, Properties info, String dat
162160// The most common one to be thrown here is:
163161// "User authentication failed"
164162//
165- throw new SQLException (pg_stream .ReceiveString (getEncoding () ));
163+ throw new SQLException (pg_stream .ReceiveString (encoding ));
166164
167165case 'R' :
168166// Get the type of request
@@ -232,7 +230,7 @@ protected void openConnection(String host, int port, Properties info, String dat
232230break ;
233231case 'E' :
234232case 'N' :
235- throw new SQLException (pg_stream .ReceiveString (getEncoding () ));
233+ throw new SQLException (pg_stream .ReceiveString (encoding ));
236234default :
237235throw new PSQLException ("postgresql.con.setup" );
238236 }
@@ -244,111 +242,34 @@ protected void openConnection(String host, int port, Properties info, String dat
244242break ;
245243case 'E' :
246244case 'N' :
247- throw new SQLException (pg_stream .ReceiveString (getEncoding () ));
245+ throw new SQLException (pg_stream .ReceiveString (encoding ));
248246default :
249247throw new PSQLException ("postgresql.con.setup" );
250248 }
251249
252- // Originally we issued a SHOW DATESTYLE statement to find the databases default
253- // datestyle. However, this caused some problems with timestamps, so in 6.5, we
254- // went the way of ODBC, and set the connection to ISO.
255- //
256- // This may cause some clients to break when they assume anything other than ISO,
257- // but then - they should be using the proper methods ;-)
258- //
259- // We also ask the DB for certain properties (i.e. DatabaseEncoding at this time)
260- //
261250firstWarning =null ;
262251
263- java .sql .ResultSet initrset =ExecSQL ("set datestyle to 'ISO'; " +
264- "select case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end" );
265-
266- String dbEncoding =null ;
267- //retrieve DB properties
268- if (initrset .next ()) {
269-
270- //handle DatabaseEncoding
271- dbEncoding =initrset .getString (1 );
272- //convert from the PostgreSQL name to the Java name
273- if (dbEncoding .equals ("SQL_ASCII" )) {
274- dbEncoding ="ASCII" ;
275- }else if (dbEncoding .equals ("UNICODE" )) {
276- dbEncoding ="UTF8" ;
277- }else if (dbEncoding .equals ("LATIN1" )) {
278- dbEncoding ="ISO8859_1" ;
279- }else if (dbEncoding .equals ("LATIN2" )) {
280- dbEncoding ="ISO8859_2" ;
281- }else if (dbEncoding .equals ("LATIN3" )) {
282- dbEncoding ="ISO8859_3" ;
283- }else if (dbEncoding .equals ("LATIN4" )) {
284- dbEncoding ="ISO8859_4" ;
285- }else if (dbEncoding .equals ("LATIN5" )) {
286- dbEncoding ="ISO8859_5" ;
287- }else if (dbEncoding .equals ("LATIN6" )) {
288- dbEncoding ="ISO8859_6" ;
289- }else if (dbEncoding .equals ("LATIN7" )) {
290- dbEncoding ="ISO8859_7" ;
291- }else if (dbEncoding .equals ("LATIN8" )) {
292- dbEncoding ="ISO8859_8" ;
293- }else if (dbEncoding .equals ("LATIN9" )) {
294- dbEncoding ="ISO8859_9" ;
295- }else if (dbEncoding .equals ("EUC_JP" )) {
296- dbEncoding ="EUC_JP" ;
297- }else if (dbEncoding .equals ("EUC_CN" )) {
298- dbEncoding ="EUC_CN" ;
299- }else if (dbEncoding .equals ("EUC_KR" )) {
300- dbEncoding ="EUC_KR" ;
301- }else if (dbEncoding .equals ("EUC_TW" )) {
302- dbEncoding ="EUC_TW" ;
303- }else if (dbEncoding .equals ("KOI8" )) {
304- // try first if KOI8_U is present, it's a superset of KOI8_R
305- try {
306- dbEncoding ="KOI8_U" ;
307- "test" .getBytes (dbEncoding );
308- }
309- catch (UnsupportedEncodingException uee ) {
310- // well, KOI8_U is still not in standard JDK, falling back to KOI8_R :(
311- dbEncoding ="KOI8_R" ;
312- }
252+ String dbEncoding ;
313253
314- }else if (dbEncoding .equals ("WIN" )) {
315- dbEncoding ="Cp1252" ;
316- }else if (dbEncoding .equals ("UNKNOWN" )) {
317- //This isn't a multibyte database so we don't have an encoding to use
318- //We leave dbEncoding null which will cause the default encoding for the
319- //JVM to be used
320- dbEncoding =null ;
321- }else {
322- dbEncoding =null ;
323- }
324- }
254+ // "pg_encoding_to_char(1)" will return 'EUC_JP' for a backend compiled with multibyte,
255+ // otherwise it's hardcoded to 'SQL_ASCII'.
256+ // If the backend doesn't know about multibyte we can't assume anything about the encoding
257+ // used, so we denote this with 'UNKNOWN'.
258+
259+ final String encodingQuery =
260+ "select case when pg_encoding_to_char(1) = 'SQL_ASCII' then 'UNKNOWN' else getdatabaseencoding() end" ;
325261
262+ // Set datestyle and fetch db encoding in a single call, to avoid making
263+ // more than one round trip to the backend during connection startup.
326264
327- //Set the encoding for this connection
328- //Since the encoding could be specified or obtained from the DB we use the
329- //following order:
330- // 1. passed as a property
331- // 2. value from DB if supported by current JVM
332- // 3. default for JVM (leave encoding null)
333- String passedEncoding =info .getProperty ("charSet" );// could be null
334-
335- if (passedEncoding !=null ) {
336- encoding =passedEncoding ;
337- }else {
338- if (dbEncoding !=null ) {
339- //test DB encoding
340- try {
341- "TEST" .getBytes (dbEncoding );
342- //no error the encoding is supported by the current JVM
343- encoding =dbEncoding ;
344- }catch (UnsupportedEncodingException uee ) {
345- //dbEncoding is not supported by the current JVM
346- encoding =null ;
347- }
348- }else {
349- encoding =null ;
350- }
265+ java .sql .ResultSet resultSet =
266+ ExecSQL ("set datestyle to 'ISO'; " +encodingQuery );
267+
268+ if (!resultSet .next ()) {
269+ throw new PSQLException ("postgresql.con.failed" ,"failed getting backend encoding" );
351270 }
271+ dbEncoding =resultSet .getString (1 );
272+ encoding =Encoding .getEncoding (dbEncoding ,info .getProperty ("charSet" ));
352273
353274// Initialise object handling
354275initObjectTypes ();
@@ -448,22 +369,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
448369int insert_oid =0 ;
449370SQLException final_error =null ;
450371
451- // Commented out as the backend can now handle queries
452- // larger than 8K. Peter June 6 2000
453- //if (sql.length() > 8192)
454- //throw new PSQLException("postgresql.con.toolong",sql);
455-
456- if (getEncoding () ==null )
457- buf =sql .getBytes ();
458- else {
459- try {
460- buf =sql .getBytes (getEncoding ());
461- }catch (UnsupportedEncodingException unse ) {
462- throw new PSQLException ("postgresql.con.encoding" ,
463- unse );
464- }
465- }
466-
372+ buf =encoding .encode (sql );
467373try
468374{
469375pg_stream .SendChar ('Q' );
@@ -484,7 +390,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
484390{
485391case 'A' :// Asynchronous Notify
486392pid =pg_stream .ReceiveInteger (4 );
487- msg =pg_stream .ReceiveString (getEncoding () );
393+ msg =pg_stream .ReceiveString (encoding );
488394break ;
489395case 'B' :// Binary Data Transfer
490396if (fields ==null )
@@ -495,7 +401,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
495401tuples .addElement (tup );
496402break ;
497403case 'C' :// Command Status
498- recv_status =pg_stream .ReceiveString (getEncoding () );
404+ recv_status =pg_stream .ReceiveString (encoding );
499405
500406// Now handle the update count correctly.
501407if (recv_status .startsWith ("INSERT" ) ||recv_status .startsWith ("UPDATE" ) ||recv_status .startsWith ("DELETE" ) ||recv_status .startsWith ("MOVE" )) {
@@ -537,7 +443,7 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
537443tuples .addElement (tup );
538444break ;
539445case 'E' :// Error Message
540- msg =pg_stream .ReceiveString (getEncoding () );
446+ msg =pg_stream .ReceiveString (encoding );
541447final_error =new SQLException (msg );
542448hfr =true ;
543449break ;
@@ -552,10 +458,10 @@ public java.sql.ResultSet ExecSQL(String sql,java.sql.Statement stat) throws SQL
552458hfr =true ;
553459break ;
554460case 'N' :// Error Notification
555- addWarning (pg_stream .ReceiveString (getEncoding () ));
461+ addWarning (pg_stream .ReceiveString (encoding ));
556462break ;
557463case 'P' :// Portal Name
558- String pname =pg_stream .ReceiveString (getEncoding () );
464+ String pname =pg_stream .ReceiveString (encoding );
559465break ;
560466case 'T' :// MetaData Field Description
561467if (fields !=null )
@@ -588,7 +494,7 @@ private Field[] ReceiveFields() throws SQLException
588494
589495for (i =0 ;i <nf ; ++i )
590496 {
591- String typname =pg_stream .ReceiveString (getEncoding () );
497+ String typname =pg_stream .ReceiveString (encoding );
592498int typid =pg_stream .ReceiveIntegerR (4 );
593499int typlen =pg_stream .ReceiveIntegerR (2 );
594500int typmod =pg_stream .ReceiveIntegerR (4 );
@@ -653,11 +559,9 @@ public String getUserName() throws SQLException
653559 }
654560
655561/**
656- * Get the character encoding to use for this connection.
657- * @return the encoding to use, or <b>null</b> for the
658- * default encoding.
562+ * Get the character encoding to use for this connection.
659563 */
660- public String getEncoding ()throws SQLException {
564+ public Encoding getEncoding ()throws SQLException {
661565return encoding ;
662566 }
663567