Charset encoding patch to JDBC driver

From: Javier Yáñez <javier(at)cibal(dot)es>
To: pgsql-jdbc(at)postgresql(dot)org
Subject: Charset encoding patch to JDBC driver
Date: 2005-03-16 09:30:03
Message-ID: 4237FC9B.4000709@cibal.es
Views: Raw Message | Whole Thread | Download mbox | Resend email
Thread:
Lists: 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(at)opencloud(dot)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(at)opencloud(dot)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

Responses

Browse pgsql-jdbc by date

  From Date Subject
Next Message Oliver Jowett 2005-03-16 11:23:41 Re: Charset encoding patch to JDBC driver
Previous Message Oliver Jowett 2005-03-15 05:56:35 Re: executeUpdate("SELECT INTO")