Charset encoding patch to JDBC driver - Mailing list pgsql-jdbc

From Javier Yáñez
Subject Charset encoding patch to JDBC driver
Date
Msg-id 4237FC9B.4000709@cibal.es
Whole thread Raw
Responses Re: Charset encoding patch to JDBC driver
List pgsql-jdbc
I have the necesity of to keep a PostgreSQL database with SQL-ASCII. As
the actual version of pgjdbc only have support for Unicode (at least for
jdbc3), I have make a patch that allow to configure the desired charset.

The available charsets are the indicated in
http://www.postgresql.org/docs/8.0/interactive/multibyte.html#MULTIBYTE-CHARSET-SUPPORTED

I only have probed this patch from JBoss. This a example of DataSource
configuration file for JBoss:

###########################################################################

<?xml version="1.0" encoding="UTF-8"?>

<!--
===================================================================== -->
<!--
    -->
<!--  JBoss Server Configuration
    -->
<!--
    -->
<!--
===================================================================== -->

<!-- $Id: postgres-ds.xml,v 1.1.2.1 2003/09/05 16:38:24 patriot1burke
Exp $ -->
<!--
==================================================================== -->
<!--  Datasource config for Postgres
   -->
<!--
==================================================================== -->


<datasources>
   <local-tx-datasource>
     <jndi-name>clinical</jndi-name>

<connection-url>jdbc:postgresql://192.168.1.1:5432/mydatabase</connection-url>
     <driver-class>org.postgresql.Driver</driver-class>
     <user-name>myusername</user-name>
     <connection-property name="charSet">LATIN1</connection-property>
     <password>mypassword</password>
         <!-- sql to call when connection is created
         <new-connection-sql></new-connection-sql>
         -->

         <!-- sql to call on an existing pooled connection when it is
obtained from pool
         <check-valid-connection-sql></check-valid-connection-sql>
         -->

   </local-tx-datasource>

</datasources>

#####################################################################################

The property charSet indicates the charset (obvious).


I have a patch for every modified file:

org.postgresql.core.v3.ConnectionFactoryImpl.java
org.postgresql.core.v3.QueryExecutorImpl.java
org.postgresql.core.v3.SimpleParameterList.java
org.postgresql.core.v3.SimpleQuery.java

These are the patches:

###################################################################################

Index: ConnectionFactoryImpl.java
===================================================================
RCS file:
/usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/core/v3/ConnectionFactoryImpl.java,v
retrieving revision 1.9
diff -u -r1.9 ConnectionFactoryImpl.java
--- ConnectionFactoryImpl.java    11 Jan 2005 08:25:44 -0000    1.9
+++ ConnectionFactoryImpl.java    10 Mar 2005 13:25:44 -0000
@@ -81,10 +81,14 @@
                  newStream = enableSSL(newStream, requireSSL, info);

              // Construct and send a startup packet.
+            String charSet = info.getProperty("charSet");
+            if (charSet == null) {
+                charSet = "UNICODE";
+            }
              String[][] params = {
                                      { "user", user },
                                      { "database", database },
-                                    { "client_encoding", "UNICODE" },
+                                    { "client_encoding", charSet },
                                      { "DateStyle", "ISO" }
                                  };

@@ -466,9 +470,7 @@
                      protoConnection.setServerVersion(value);
                  else if (name.equals("client_encoding"))
                  {
-                    if (!value.equals("UNICODE"))
-                        throw new PSQLException(GT.tr("Protocol error.
  Session setup failed."), PSQLState.CONNECTION_UNABLE_TO_CONNECT);
-
pgStream.setEncoding(Encoding.getDatabaseEncoding("UNICODE"));
+
pgStream.setEncoding(Encoding.getDatabaseEncoding(value));
                  }

                  break;

######################################################################################


Index: QueryExecutorImpl.java
===================================================================
RCS file:
/usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/core/v3/QueryExecutorImpl.java,v
retrieving revision 1.21
diff -u -r1.21 QueryExecutorImpl.java
--- QueryExecutorImpl.java    1 Feb 2005 07:27:54 -0000    1.21
+++ QueryExecutorImpl.java    10 Mar 2005 13:28:02 -0000
@@ -47,14 +47,14 @@
      //

      public Query createSimpleQuery(String sql) {
-        return parseQuery(sql, false);
+        return parseQuery(sql, false, protoConnection.getEncoding());
      }

      public Query createParameterizedQuery(String sql) {
-        return parseQuery(sql, true);
+        return parseQuery(sql, true, protoConnection.getEncoding());
      }

-    private static Query parseQuery(String query, boolean withParameters) {
+    private static Query parseQuery(String query, boolean
withParameters, Encoding encoding) {
          // Parse query and find parameter placeholders;
          // also break the query into separate statements.

@@ -120,7 +120,7 @@
          if (statementList.size() == 1)
          {
              // Only one statement.
-            return new SimpleQuery((String[]) statementList.get(0));
+            return new SimpleQuery((String[]) statementList.get(0),
encoding);
          }

          // Multiple statements.
@@ -131,7 +131,7 @@
          {
              String[] fragments = (String[]) statementList.get(i);
              offsets[i] = offset;
-            subqueries[i] = new SimpleQuery(fragments);
+            subqueries[i] = new SimpleQuery(fragments, encoding);
              offset += fragments.length - 1;
          }

@@ -476,7 +476,7 @@
      }

      public ParameterList createFastpathParameters(int count) {
-        return new SimpleParameterList(count);
+        return new SimpleParameterList(count,
protoConnection.getEncoding());
      }

      private void sendFastpathCall(int fnid, SimpleParameterList
params) throws SQLException, IOException {
@@ -696,12 +696,12 @@
          {
              if (i != 0)
              {
-                parts[j] = Utils.encodeUTF8("$" + i);
+                parts[j] = protoConnection.getEncoding().encode("$" + i);
                  encodedSize += parts[j].length;
                  ++j;
              }

-            parts[j] = Utils.encodeUTF8(fragments[i]);
+            parts[j] = protoConnection.getEncoding().encode(fragments[i]);
              encodedSize += parts[j].length;
              ++j;
          }
@@ -913,7 +913,7 @@
              Driver.debug(" FE=> ClosePortal(" + portalName + ")");
          }

-        byte[] encodedPortalName = (portalName == null ? null :
Utils.encodeUTF8(portalName));
+        byte[] encodedPortalName = (portalName == null ? null :
protoConnection.getEncoding().encode(portalName));
          int encodedSize = (encodedPortalName == null ? 0 :
encodedPortalName.length);

          // Total size = 4 (size field) + 1 (close type, 'P') + 1 + N
(portal name)
@@ -935,7 +935,7 @@
              Driver.debug(" FE=> CloseStatement(" + statementName + ")");
          }

-        byte[] encodedStatementName = Utils.encodeUTF8(statementName);
+        byte[] encodedStatementName =
protoConnection.getEncoding().encode(statementName);

          // Total size = 4 (size field) + 1 (close type, 'S') + N + 1
(statement name)
          pgStream.SendChar('C');              // Close
@@ -1553,7 +1553,7 @@
      private final PGStream pgStream;
      private final boolean allowEncodingChanges;

-    private final SimpleQuery beginTransactionQuery = new
SimpleQuery(new String[] { "BEGIN" });
+    private final SimpleQuery beginTransactionQuery = new
SimpleQuery(new String[] { "BEGIN" }, null);
      ;
-    private final static SimpleQuery EMPTY_QUERY = new SimpleQuery(new
String[] { "" });
+    private final static SimpleQuery EMPTY_QUERY = new SimpleQuery(new
String[] { "" }, null);
  }


#############################################################################################



Index: SimpleParameterList.java
===================================================================
RCS file:
/usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/core/v3/SimpleParameterList.java,v
retrieving revision 1.8
diff -u -r1.8 SimpleParameterList.java
--- SimpleParameterList.java    1 Feb 2005 07:27:54 -0000    1.8
+++ SimpleParameterList.java    10 Mar 2005 13:30:24 -0000
@@ -27,10 +27,11 @@
   * @author Oliver Jowett (oliver@opencloud.com)
   */
  class SimpleParameterList implements V3ParameterList {
-    SimpleParameterList(int paramCount) {
+    SimpleParameterList(int paramCount, Encoding encoding) {
          this.paramValues = new Object[paramCount];
          this.paramTypes = new int[paramCount];
          this.encoded = new byte[paramCount][];
+        this.encoding = encoding;
      }

      private void bind(int index, Object value, int oid) throws
SQLException {
@@ -156,7 +157,7 @@
          return (paramValues[index -1] instanceof StreamWrapper);
      }

-    int getV3Length(int index) {
+    int getV3Length(int index) throws IOException {
          --index;

          // Null?
@@ -174,8 +175,8 @@
          // Already encoded?
          if (encoded[index] == null)
          {
-            // Encode value and compute actual length using UTF-8.
-            encoded[index] =
Utils.encodeUTF8(paramValues[index].toString());
+            // Encode value and compute actual length.
+            encoded[index] =
encoding.encode(paramValues[index].toString());
          }

          return encoded[index].length;
@@ -204,12 +205,12 @@

          // Encoded string.
          if (encoded[index] == null)
-            encoded[index] = Utils.encodeUTF8((String)paramValues[index]);
+            encoded[index] = encoding.encode((String)paramValues[index]);
          pgStream.Send(encoded[index]);
      }

      public ParameterList copy() {
-        SimpleParameterList newCopy = new
SimpleParameterList(paramValues.length);
+        SimpleParameterList newCopy = new
SimpleParameterList(paramValues.length, encoding);
          System.arraycopy(paramValues, 0, newCopy.paramValues, 0,
paramValues.length);
          System.arraycopy(paramTypes, 0, newCopy.paramTypes, 0,
paramTypes.length);
          return newCopy;
@@ -228,6 +229,7 @@
      private final Object[] paramValues;
      private final int[] paramTypes;
      private final byte[][] encoded;
+    private Encoding encoding;

      /**
Marker object representing NULL; this distinguishes


######################################################################################################

Index: SimpleQuery.java
===================================================================
RCS file:
/usr/local/cvsroot/pgjdbc/pgjdbc/org/postgresql/core/v3/SimpleQuery.java,v
retrieving revision 1.8
diff -u -r1.8 SimpleQuery.java
--- SimpleQuery.java    1 Feb 2005 07:27:54 -0000    1.8
+++ SimpleQuery.java    10 Mar 2005 13:32:13 -0000
@@ -11,6 +11,8 @@
  package org.postgresql.core.v3;

  import org.postgresql.core.*;
+
+import java.io.IOException;
  import java.lang.ref.PhantomReference;

  /**
@@ -22,15 +24,18 @@
   * @author Oliver Jowett (oliver@opencloud.com)
   */
  class SimpleQuery implements V3Query {
-    SimpleQuery(String[] fragments) {
+    SimpleQuery(String[] fragments, Encoding encoding) {
          this.fragments = fragments;
+        if (encoding != null) {
+            this.encoding = encoding;
+        }
      }

      public ParameterList createParameterList() {
          if (fragments.length == 1)
              return NO_PARAMETERS;

-        return new SimpleParameterList(fragments.length - 1);
+        return new SimpleParameterList(fragments.length - 1, encoding);
      }

      public String toString(ParameterList parameters) {
@@ -70,9 +75,9 @@
          return fragments;
      }

-    void setStatementName(String statementName) {
+    void setStatementName(String statementName) throws IOException {
          this.statementName = statementName;
-        this.encodedStatementName = Utils.encodeUTF8(statementName);
+        this.encodedStatementName = encoding.encode(statementName);
      }

      void setStatementTypes(int[] paramTypes) {
@@ -120,8 +125,9 @@
      private byte[] encodedStatementName;
      private PhantomReference cleanupRef;
      private int[] preparedTypes;
+    private Encoding encoding = Encoding.defaultEncoding();

-    final static SimpleParameterList NO_PARAMETERS = new
SimpleParameterList(0);
+    final static SimpleParameterList NO_PARAMETERS = new
SimpleParameterList(0, null);
  }

###################################################################################


Javier Yáñez

--
CIBAL Multimedia S.L.
Edificio 17, C-10
ParcBIT
Camino de Can Manuel s/n
07120 - Palma de Mallorca
Spain


pgsql-jdbc by date:

Previous
From: Oliver Jowett
Date:
Subject: Re: executeUpdate("SELECT INTO")
Next
From: Oliver Jowett
Date:
Subject: Re: Charset encoding patch to JDBC driver