PostgreSQL 6.5.2 JDBC ドライバ 文字エンコーディングパッチ 1999 11/8 データベースの文字エンコーディングを Java 環境でのデフォルト 文字エンコーディングと区別して扱うようにするパッチです。 src/interfaces/jdbc/ の下で、 % patch -p2 < このファイル でパッチをあてて下さい。 使い方は、src/interfaces/jdbc/ の README.ce.eucjp を見て下さい。 private: mochid@yo.rim.or.jp 持田 修司 -- Do not crack your dream. Be MI by NetBSD -- diff -urN R6_5_2/jdbc/Makefile CE19991108/jdbc/Makefile --- R6_5_2/jdbc/Makefile Wed Sep 15 19:37:46 1999 +++ CE19991108/jdbc/Makefile Mon Nov 8 00:42:42 1999 @@ -16,6 +16,7 @@ JAVADOC = javadoc RM = rm -f TOUCH = touch +MAKE ?= make # This defines how to compile a java class .java.class: @@ -27,7 +28,7 @@ # In 6.5, the all rule builds the makeVersion class which then calls make using # the jdbc1 or jdbc2 rules all: makeVersion.class - make $$($(JAVA) makeVersion) + $(MAKE) `$(JAVA) makeVersion` @echo ------------------------------------------------------------ @echo The JDBC driver has now been built. To make it available to @echo other applications, copy the postgresql.jar file to a public @@ -107,6 +108,20 @@ postgresql/jdbc2/ResultSetMetaData.class \ postgresql/jdbc2/Statement.class +OBJ_CE= postgresql/ce/Driver.class \ + postgresql/ce/PG_Stream.class \ + postgresql/ce/PgCharactorEncoding.class + +OBJ_CE_JDBC1= postgresql/ce/jdbc1/Connection.class \ + postgresql/ce/jdbc1/DatabaseMetaData.class \ + postgresql/ce/jdbc1/ResultSet.class + +OBJ_CE_JDBC2= postgresql/ce/jdbc2/Connection.class \ + postgresql/ce/jdbc2/DatabaseMetaData.class \ + postgresql/ce/jdbc2/ResultSet.class + +OBJ_CE_COMPAT= postgresql/ce/compat/Driver.class + # This rule should never occur, but will be called when makeVersion fails to # understand the java.version property correctly. jdbc0: @@ -131,10 +146,12 @@ @echo # This rule builds the JDBC1 compliant driver -jdbc1: $(OBJ_COMMON) $(OBJ_JDBC1) postgresql.jar +jdbc1: $(OBJ_COMMON) $(OBJ_JDBC1) $(OBJ_CE) $(OBJ_CE_JDBC1) $(OBJ_CE_COMPAT) \ + postgresql.jar # This rule builds the JDBC2 compliant driver -jdbc2: $(OBJ_COMMON) $(OBJ_JDBC2) postgresql.jar +jdbc2: $(OBJ_COMMON) $(OBJ_JDBC2) $(OBJ_CE) $(OBJ_CE_JDBC2) $(OBJ_CE_COMPAT) \ + postgresql.jar # If you have problems with this rule, replace the $( ) with ` ` as some # shells (mainly sh under Solaris) doesn't recognise $( ) @@ -143,7 +160,7 @@ # directory. We use this later for compiling the dual-mode driver. # postgresql.jar: $(OBJ) $(OBJ_COMMON) - $(JAR) -c0f $@ $$($(FIND) postgresql -name "*.class" -print) \ + $(JAR) -c0f $@ `$(FIND) postgresql -name "*.class" -print` \ $(wildcard postgresql/*.properties) # This rule removes any temporary and compiled files from the source tree. diff -urN R6_5_2/jdbc/README.ce.eucjp CE19991108/jdbc/README.ce.eucjp --- R6_5_2/jdbc/README.ce.eucjp Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/README.ce.eucjp Mon Nov 8 00:33:54 1999 @@ -0,0 +1,85 @@ + + $Id$ + +PostgreSQL JDBC ドライバ 文字エンコーディングパッチ + + データベースの文字エンコーディングを Java 環境でのデフォルト + 文字エンコーディングと区別して扱うようにするパッチです。 + + PostgreSQL 6.5.2 付属の JDBC ドライバはデータベースバックエンドと + やりとりするデータの 文字(String)<->バイト列(byte[]) 変換に + 文字エンコーディング指定をしていないため、Java 環境のデフォルト + 文字エンコーディングがそのまま使用されます。両者が異なる場合や、 + ネットワーク越しに JDBC ドライバを取得する等 Java 側に特定の + 文字エンコーディングを仮定できない場合などには区別した扱いが必要です。 + +使い方 + ドライバとして、"postgresql.Driver" でなく、"postgresql.ce.Driver" を + 使って下さい。 + "postgresql.Driver" を指定すると、オリジナルと同じ動作になります。 + (なるはずです。) + + データベースの文字エンコーディングは接続時にドライバ内部で + SQL によってデータベースバックエンドから取得しています。 + なんらかの理由で明示的に指定したい場合は URL に下記のように + 追加すると、こちらを優先するようにしてあります。 + + jdbc:postgresql://pghost/database&charactorEncoding=EUC_JP + ^^^^^^^^^^^^^^^^^^^^^^^^^ + +使用できる文字エンコーディング名について + Java が内部に持つ文字エンコーディング変換機構を利用しているので、 + Java の文字エンコーディング名が使用できます。MULE_INTERNAL は + 使用できません。 + PostgreSQL での文字エンコーディング名は、 + postgresql/ce/PgCharactorEncoding.java のテーブルにあるものについては + Java の文字エンコーディング名にマッピングするようになっています。 + +注意点 + "postgresql.ce.Driver" だけでなく、"postgresql.Driver" も + Class.forName() 等でロードすると、両方のドライバがドライバマネージャに + 登録されてしまいます。扱うサブプロトコルが同じため、PostgreSQL 用の + URL で両方のドライバが有効になるので、文字エンコーディングを + 区別しないドライバが動作する可能性があります。 + +呼び名の変更 + マルチバイトが扱えないのを扱えるようにしたわけでもないので、 + MB という名称はやめました。 + +旧いパッチとの互換性 + "postgresql.ce.compat.Driver" を使うと、6.4 までの指定方法で + 使用できます。Java のシステムプロパティ + "postgresql.databaseencoding" と、 + URL "jdbc:postgresql.EUC_JP://pghost/database" の形式で + 文字エンコーディングを指定できます。 + ただし、今後は廃止するかも知れませんので、できれば使用を避けて下さい。 + +履歴 + ・1999 11/8 6.5.2 対応 + サブクラス化 + URL の一部に符号化した指定ができるようにした + 唐沢@名古屋市大 さんのバグレポートのパッチ(2/20)取り込み + ・1998 12/14 6.4 対応、URL 指定できるように変更 + ・1998 9/30 たかばとしはる さんが pgsql-jp メーリングリストで + 6.3 用に「jdbc UTF8 patch」 + + http://www.sra.co.jp/people/t-ishii/postgres95/mhonarc/pgsql-jp/1998Mar/msg00185.html + [pgsql-jp 3617] + + として公開されたものを他のエンコーディングでも利用できるよう修正 + +このパッチの扱いについて + このパッチは、無保証です。このパッチによってなんらかの損害が発生する + 可能性がありますので、自らの責任において使用して下さい。 + 再配布は自由に行ってもらって結構です。ただし、修正されたものを + 配布される場合は、その旨を明記して下さい。 + +関連 + このパッチ用のページ + http://www.yo.rim.or.jp/~mochid/postgresql-jdbc/ + PostgreSQL ML + http://www.sra.co.jp/people/t-ishii/postgres95/ML/info.html + + + 持田 修司 mochid@yo.rim.or.jp +# End of file diff -urN R6_5_2/jdbc/example/Dbview2.java CE19991108/jdbc/example/Dbview2.java --- R6_5_2/jdbc/example/Dbview2.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/example/Dbview2.java Mon Nov 8 00:42:06 1999 @@ -0,0 +1,232 @@ + +// $Id: Dbview2.java,v 1.1 1999/10/20 10:00:32 mochid Exp mochid $ + +import java.applet.Applet; +import java.awt.*; +import javax.swing.*; +// import javax.swing.event.*; +import java.awt.event.*; +import java.sql.*; +import java.util.*; + +import javax.swing.table.AbstractTableModel; +import javax.swing.event.TableModelEvent; + +class DbModel extends AbstractTableModel { + Connection conn = null; + Statement st = null; + ResultSet rs = null; + ResultSetMetaData rsMetaDatas; + int nColumns = 0; + Vector clmNames = null; + Vector rowList = null; + + public void connect(String driver, + String url, String user, String passwd) + throws ClassNotFoundException, SQLException { + Class.forName(driver); + conn = DriverManager.getConnection(url, user, passwd); + st = conn.createStatement(); + } + + protected void finalize() throws Throwable { + if (rs != null) rs.close(); + if (st != null) st.close(); + if (conn != null) conn.close(); + super.finalize(); + } + + public void fetch(String sql) throws SQLException { + rs = st.executeQuery(sql); + rsMetaDatas = rs.getMetaData(); + nColumns = rsMetaDatas.getColumnCount(); + + clmNames = new Vector(); + for (int i = 0; i < nColumns; i++) + clmNames.addElement(rsMetaDatas.getColumnLabel(i +1)); + rowList = new Vector(); + while (rs.next()) { + Vector row = new Vector(); + for (int i = 0; i < nColumns; i++) + row.addElement(rs.getObject(i +1)); + rowList.addElement(row); + } + fireTableChanged(null); + } + + public int getColumnCount() { + return nColumns; + } + + public int getRowCount() { + int r = 0; + if (rowList != null) + r = rowList.size(); + return r; + } + + public String getColumnName(int column) { + String r = (String)clmNames.elementAt(column); + if (r == null) + r = ""; + return r; + } + + public Class getColumnClass(int column) { + int type; + try { + type = rsMetaDatas.getColumnType(column+1); + } + catch (SQLException e) { + return null; + } + + Class c; + + switch(type) { + case Types.CHAR: + case Types.VARCHAR: + case Types.LONGVARCHAR: + c = String.class; + break; + case Types.BIT: + c = Boolean.class; + break; + case Types.TINYINT: + case Types.SMALLINT: + case Types.INTEGER: + c = Integer.class; + break; + case Types.BIGINT: + c = Long.class; + break; + case Types.FLOAT: + case Types.DOUBLE: + c = Double.class; + break; + case Types.DATE: + c = java.sql.Date.class; + break; + default: + c = Object.class; + break; + } + return c; + } + + public Object getValueAt(int rowIndex, int columnIndex) { + Vector row = (Vector)rowList.elementAt(rowIndex); + if (row == null) + return null; + Object o = row.elementAt(columnIndex); + return o; + } + + public boolean isCellEditable(int rowIndex, int columnIndex) { + return false; + } +} + +public class Dbview2 extends Applet implements ActionListener { + + static final String JDBCDRIVER = "postgresql.ce.Driver"; + + DbModel dbModel; + + Container container; + JLabel urlLabel, userLabel, passwdLabel, tableLabel; + JTextField urlField, userField, tableField; + JPasswordField passwdField; + JLabel statLabel; + + // public Dbview2() { + // } + + public void init() { + urlLabel = new JLabel(" DB URL:"); + urlField = new JTextField("jdbc:postgresql://", 32); + userLabel = new JLabel(" User:"); + userField = new JTextField(16); + passwdLabel = new JLabel(" Password:"); + passwdField = new JPasswordField(16); + tableLabel = new JLabel(" Table:"); + tableField = new JTextField(32); + Button fetchBtn = new Button(" 取得 "); + + // container = new Container("Dbvew"); + container = this; + container.setLayout(new FlowLayout(FlowLayout.LEFT)); + + container.add(fetchBtn); + + Panel panel = new Panel(new FlowLayout()); + panel.add(urlLabel); + panel.add(urlField); + container.add(panel); + panel = new Panel(new FlowLayout()); + panel.add(userLabel); + panel.add(userField); + container.add(panel); + panel = new Panel(new FlowLayout()); + panel.add(passwdLabel); + panel.add(passwdField); + container.add(panel); + panel = new Panel(new FlowLayout()); + panel.add(tableLabel); + panel.add(tableField); + container.add(panel); + + dbModel = new DbModel(); + JTable tbl = new JTable(dbModel); + JScrollPane sclp = new JScrollPane(tbl); + tbl.setAutoResizeMode(JTable.AUTO_RESIZE_OFF); + container.add(sclp); + + statLabel = new JLabel(" "); + container.add(statLabel); + + fetchBtn.addActionListener(this); + } + + public void actionPerformed(ActionEvent event) { + try { + dbModel.connect(JDBCDRIVER, urlField.getText(), + userField.getText(), + new String(passwdField.getPassword())); + } catch (ClassNotFoundException e) { + statLabel.setText("Error: " + e.getMessage()); + return; + } catch (SQLException e) { + statLabel.setText("Error: " + e.getMessage()); + return; + } + + String sql = "select * from " + tableField.getText(); + try { + dbModel.fetch(sql); + } catch (SQLException e) { + statLabel.setText("Error: " + e.getMessage()); + return; + } + } + + public static void main(String s[]) { + JFrame f = new JFrame("Dbview2"); + Dbview2 dbview = new Dbview2(); + dbview.init(); + dbview.start(); + + f.getContentPane().add("Center", dbview); + f.addWindowListener( + new WindowAdapter() { + public void windowClosing(WindowEvent e) { + System.exit(0); + } + }); + + f.setSize(470, 590); + f.show(); + } +} + +// End of file diff -urN R6_5_2/jdbc/postgresql/Connection.java CE19991108/jdbc/postgresql/Connection.java --- R6_5_2/jdbc/postgresql/Connection.java Wed Sep 15 15:42:17 1999 +++ CE19991108/jdbc/postgresql/Connection.java Mon Nov 8 00:42:46 1999 @@ -37,7 +37,7 @@ public boolean autoCommit = true; public boolean readOnly = false; - public Driver this_driver; + public DriverImpl this_driver; private String this_url; private String cursor = null; // The positioned update cursor name @@ -89,7 +89,7 @@ * @return a valid connection profile * @exception SQLException if a database access error occurs */ - protected void openConnection(String host, int port, Properties info, String database, String url, Driver d) throws SQLException + protected void openConnection(String host, int port, Properties info, String database, String url, DriverImpl d) throws SQLException { // Throw an exception if the user or password properties are missing // This occasionally occurs when the client uses the properties version @@ -111,7 +111,7 @@ // Now make the initial connection try { - pg_stream = new PG_Stream(host, port); + newPG_Stream(host, port); } catch (ConnectException cex) { // Added by Peter Mount // ConnectException is thrown when the connection cannot be made. @@ -220,6 +220,10 @@ // firstWarning = null; + // Charactor Encoding Support + execGetDbEncoding(info); + setEncodingToPgStream(); + ExecSQL("set datestyle to 'ISO'"); // Initialise object handling @@ -263,7 +267,11 @@ //currentDateStyle=i+1; // this is the index of the format //} } - + + protected byte[] getBytesByDbEncoding(String sql) throws PSQLException { + return sql.getBytes(); + } + /** * Send a query to the backend. Returns one of the ResultSet * objects. @@ -282,19 +290,18 @@ Field[] fields = null; Vector tuples = new Vector(); - byte[] buf = new byte[sql.length()]; + byte[] buf = getBytesByDbEncoding(sql); int fqp = 0; boolean hfr = false; String recv_status = null, msg; int update_count = 1; SQLException final_error = null; - if (sql.length() > 8192) + if (buf.length > 8192) throw new PSQLException("postgresql.con.toolong",sql); try { pg_stream.SendChar('Q'); - buf = sql.getBytes(); pg_stream.Send(buf); pg_stream.SendChar(0); pg_stream.flush(); @@ -683,7 +690,15 @@ for(int i=0;iThe DriverManager will try to load as many drivers as it can find and - * then for any given connection request, it will ask each driver in turn - * to try to connect to the target URL. - * - *

It is strongly recommended that each Driver class should be small and - * standalone so that the Driver class can be loaded and queried without - * bringing in vast quantities of supporting code. - * - *

When a Driver class is loaded, it should create an instance of itself - * and register it with the DriverManager. This means that a user can load - * and register a driver by doing Class.forName("foo.bah.Driver") - * - * @see postgresql.Connection - * @see java.sql.Driver - */ -public class Driver implements java.sql.Driver +public class Driver extends DriverImpl { - // These should be in sync with the backend that the driver was - // distributed with - static final int MAJORVERSION = 6; - static final int MINORVERSION = 5; - - // Cache the version of the JDK in use - static String connectClass; - static { try { @@ -46,7 +19,7 @@ e.printStackTrace(); } } - + /** * Construct a new driver and register it with DriverManager * @@ -62,295 +35,4 @@ connectClass = "postgresql.jdbc2.Connection"; } } - - /** - * Try to make a database connection to the given URL. The driver - * should return "null" if it realizes it is the wrong kind of - * driver to connect to the given URL. This will be common, as - * when the JDBC driverManager is asked to connect to a given URL, - * it passes the URL to each loaded driver in turn. - * - *

The driver should raise an SQLException if it is the right driver - * to connect to the given URL, but has trouble connecting to the - * database. - * - *

The java.util.Properties argument can be used to pass arbitrary - * string tag/value pairs as connection arguments. Normally, at least - * "user" and "password" properties should be included in the - * properties. - * - * Our protocol takes the forms: - *

-   *	jdbc:postgresql://host:port/database?param1=val1&...
-   * 
- * - * @param url the URL of the database to connect to - * @param info a list of arbitrary tag/value pairs as connection - * arguments - * @return a connection to the URL or null if it isnt us - * @exception SQLException if a database access error occurs - * @see java.sql.Driver#connect - */ - public java.sql.Connection connect(String url, Properties info) throws SQLException - { - if((props = parseURL(url,info))==null) - return null; - - DriverManager.println("Using "+connectClass); - - try { - postgresql.Connection con = (postgresql.Connection)(Class.forName(connectClass).newInstance()); - con.openConnection (host(), port(), props, database(), url, this); - return (java.sql.Connection)con; - } catch(ClassNotFoundException ex) { - throw new PSQLException("postgresql.jvm.version",ex); - } catch(PSQLException ex1) { - // re-throw the exception, otherwise it will be caught next, and a - // postgresql.unusual error will be returned instead. - throw ex1; - } catch(Exception ex2) { - throw new PSQLException("postgresql.unusual",ex2); - } - } - - /** - * Returns true if the driver thinks it can open a connection to the - * given URL. Typically, drivers will return true if they understand - * the subprotocol specified in the URL and false if they don't. Our - * protocols start with jdbc:postgresql: - * - * @see java.sql.Driver#acceptsURL - * @param url the URL of the driver - * @return true if this driver accepts the given URL - * @exception SQLException if a database-access error occurs - * (Dont know why it would *shrug*) - */ - public boolean acceptsURL(String url) throws SQLException - { - if(parseURL(url,null)==null) - return false; - return true; - } - - /** - * The getPropertyInfo method is intended to allow a generic GUI - * tool to discover what properties it should prompt a human for - * in order to get enough information to connect to a database. - * - *

Note that depending on the values the human has supplied so - * far, additional values may become necessary, so it may be necessary - * to iterate through several calls to getPropertyInfo - * - * @param url the Url of the database to connect to - * @param info a proposed list of tag/value pairs that will be sent on - * connect open. - * @return An array of DriverPropertyInfo objects describing - * possible properties. This array may be an empty array if - * no properties are required - * @exception SQLException if a database-access error occurs - * @see java.sql.Driver#getPropertyInfo - */ - public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException - { - Properties p = parseURL(url,info); - - // naughty, but its best for speed. If anyone adds a property here, then - // this _MUST_ be increased to accomodate them. - DriverPropertyInfo d,dpi[] = new DriverPropertyInfo[0]; - //int i=0; - - //dpi[i++] = d = new DriverPropertyInfo("auth",p.getProperty("auth","default")); - //d.description = "determines if password authentication is used"; - //d.choices = new String[4]; - //d.choices[0]="default"; // Get value from postgresql.auth property, defaults to trust - //d.choices[1]="trust"; // No password authentication - //d.choices[2]="password"; // Password authentication - //d.choices[3]="ident"; // Ident (RFC 1413) protocol - - return dpi; - } - - /** - * Gets the drivers major version number - * - * @return the drivers major version number - */ - public int getMajorVersion() - { - return MAJORVERSION; - } - - /** - * Get the drivers minor version number - * - * @return the drivers minor version number - */ - public int getMinorVersion() - { - return MINORVERSION; - } - - /** - * Report whether the driver is a genuine JDBC compliant driver. A - * driver may only report "true" here if it passes the JDBC compliance - * tests, otherwise it is required to return false. JDBC compliance - * requires full support for the JDBC API and full support for SQL 92 - * Entry Level. - * - *

For PostgreSQL, this is not yet possible, as we are not SQL92 - * compliant (yet). - */ - public boolean jdbcCompliant() - { - return false; - } - - private Properties props; - - static private String[] protocols = { "jdbc","postgresql" }; - - /** - * Constructs a new DriverURL, splitting the specified URL into its - * component parts - * @param url JDBC URL to parse - * @param defaults Default properties - * @return Properties with elements added from the url - * @exception SQLException - */ - Properties parseURL(String url,Properties defaults) throws SQLException - { - int state = -1; - Properties urlProps = new Properties(defaults); - String key = new String(); - String value = new String(); - - StringTokenizer st = new StringTokenizer(url, ":/;=&?", true); - for (int count = 0; (st.hasMoreTokens()); count++) { - String token = st.nextToken(); - - // PM June 29 1997 - // Added this, to help me understand how this works. - // Unless you want each token to be processed, leave this commented out - // but don't delete it. - //DriverManager.println("wellFormedURL: state="+state+" count="+count+" token='"+token+"'"); - - // PM Aug 2 1997 - Modified to allow multiple backends - if (count <= 3) { - if ((count % 2) == 1 && token.equals(":")) - ; - else if((count % 2) == 0) { - boolean found=(count==0)?true:false; - for(int tmp=0;tmp 0) { - urlProps.put("Protocol",token); - found=true; - } - } - } - - if(found == false) - return null; - } else return null; - } - else if (count > 3) { - if (count == 4 && token.equals("/")) state = 0; - else if (count == 4) { - urlProps.put("PGDBNAME", token); - state = -2; - } - else if (count == 5 && state == 0 && token.equals("/")) - state = 1; - else if (count == 5 && state == 0) - return null; - else if (count == 6 && state == 1) - urlProps.put("PGHOST", token); - else if (count == 7 && token.equals(":")) state = 2; - else if (count == 8 && state == 2) { - try { - Integer portNumber = Integer.decode(token); - urlProps.put("PGPORT", portNumber.toString()); - } catch (Exception e) { - return null; - } - } - else if ((count == 7 || count == 9) && - (state == 1 || state == 2) && token.equals("/")) - state = -1; - else if (state == -1) { - urlProps.put("PGDBNAME", token); - state = -2; - } - else if (state <= -2 && (count % 2) == 1) { - // PM Aug 2 1997 - added tests for ? and & - if (token.equals(";") || token.equals("?") || token.equals("&") ) state = -3; - else if (token.equals("=")) state = -5; - } - else if (state <= -2 && (count % 2) == 0) { - if (state == -3) key = token; - else if (state == -5) { - value = token; - //DriverManager.println("put("+key+","+value+")"); - urlProps.put(key, value); - state = -2; - } - } - } - } - - // PM June 29 1997 - // This now outputs the properties only if we are logging - if(DriverManager.getLogStream() != null) - urlProps.list(DriverManager.getLogStream()); - - return urlProps; - - } - - /** - * @return the hostname portion of the URL - */ - public String host() - { - return props.getProperty("PGHOST","localhost"); - } - - /** - * @return the port number portion of the URL or -1 if no port was specified - */ - public int port() - { - return Integer.parseInt(props.getProperty("PGPORT","5432")); - } - - /** - * @return the database name of the URL - */ - public String database() - { - return props.getProperty("PGDBNAME"); - } - - /** - * @return the value of any property specified in the URL or properties - * passed to connect(), or null if not found. - */ - public String property(String name) - { - return props.getProperty(name); - } - - /** - * This method was added in v6.5, and simply throws an SQLException - * for an unimplemented method. I decided to do it this way while - * implementing the JDBC2 extensions to JDBC, as it should help keep the - * overall driver size down. - */ - public static SQLException notImplemented() - { - return new PSQLException("postgresql.unimplemented"); - } } - diff -urN R6_5_2/jdbc/postgresql/DriverImpl.java CE19991108/jdbc/postgresql/DriverImpl.java --- R6_5_2/jdbc/postgresql/DriverImpl.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/DriverImpl.java Mon Nov 8 00:42:47 1999 @@ -0,0 +1,330 @@ +package postgresql; + +import java.sql.*; +import java.util.*; + +import postgresql.util.PSQLException; + +/** + * The Java SQL framework allows for multiple database drivers. Each + * driver should supply a class that implements the Driver interface + * + *

The DriverManager will try to load as many drivers as it can find and + * then for any given connection request, it will ask each driver in turn + * to try to connect to the target URL. + * + *

It is strongly recommended that each Driver class should be small and + * standalone so that the Driver class can be loaded and queried without + * bringing in vast quantities of supporting code. + * + *

When a Driver class is loaded, it should create an instance of itself + * and register it with the DriverManager. This means that a user can load + * and register a driver by doing Class.forName("foo.bah.Driver") + * + * @see postgresql.Connection + * @see java.sql.Driver + */ +public abstract class DriverImpl implements java.sql.Driver +{ + // These should be in sync with the backend that the driver was + // distributed with + static final int MAJORVERSION = 6; + static final int MINORVERSION = 5; + + // Cache the version of the JDK in use + static protected String connectClass; + + public DriverImpl() throws SQLException { + } + + /** + * Try to make a database connection to the given URL. The driver + * should return "null" if it realizes it is the wrong kind of + * driver to connect to the given URL. This will be common, as + * when the JDBC driverManager is asked to connect to a given URL, + * it passes the URL to each loaded driver in turn. + * + *

The driver should raise an SQLException if it is the right driver + * to connect to the given URL, but has trouble connecting to the + * database. + * + *

The java.util.Properties argument can be used to pass arbitrary + * string tag/value pairs as connection arguments. Normally, at least + * "user" and "password" properties should be included in the + * properties. + * + * Our protocol takes the forms: + *

+   *	jdbc:postgresql://host:port/database?param1=val1&...
+   * 
+ * + * @param url the URL of the database to connect to + * @param info a list of arbitrary tag/value pairs as connection + * arguments + * @return a connection to the URL or null if it isnt us + * @exception SQLException if a database access error occurs + * @see java.sql.Driver#connect + */ + public java.sql.Connection connect(String url, Properties info) throws SQLException + { + if((props = parseURL(url,info))==null) + return null; + + DriverManager.println("Using "+connectClass); + + try { + postgresql.Connection con = (postgresql.Connection)(Class.forName(connectClass).newInstance()); + con.openConnection (host(), port(), props, database(), url, this); + return (java.sql.Connection)con; + } catch(ClassNotFoundException ex) { + throw new PSQLException("postgresql.jvm.version",ex); + } catch(PSQLException ex1) { + // re-throw the exception, otherwise it will be caught next, and a + // postgresql.unusual error will be returned instead. + throw ex1; + } catch(Exception ex2) { + throw new PSQLException("postgresql.unusual",ex2); + } + } + + /** + * Returns true if the driver thinks it can open a connection to the + * given URL. Typically, drivers will return true if they understand + * the subprotocol specified in the URL and false if they don't. Our + * protocols start with jdbc:postgresql: + * + * @see java.sql.Driver#acceptsURL + * @param url the URL of the driver + * @return true if this driver accepts the given URL + * @exception SQLException if a database-access error occurs + * (Dont know why it would *shrug*) + */ + public boolean acceptsURL(String url) throws SQLException + { + if(parseURL(url,null)==null) + return false; + return true; + } + + /** + * The getPropertyInfo method is intended to allow a generic GUI + * tool to discover what properties it should prompt a human for + * in order to get enough information to connect to a database. + * + *

Note that depending on the values the human has supplied so + * far, additional values may become necessary, so it may be necessary + * to iterate through several calls to getPropertyInfo + * + * @param url the Url of the database to connect to + * @param info a proposed list of tag/value pairs that will be sent on + * connect open. + * @return An array of DriverPropertyInfo objects describing + * possible properties. This array may be an empty array if + * no properties are required + * @exception SQLException if a database-access error occurs + * @see java.sql.Driver#getPropertyInfo + */ + public DriverPropertyInfo[] getPropertyInfo(String url, Properties info) throws SQLException + { + Properties p = parseURL(url,info); + + // naughty, but its best for speed. If anyone adds a property here, then + // this _MUST_ be increased to accomodate them. + DriverPropertyInfo d,dpi[] = new DriverPropertyInfo[0]; + //int i=0; + + //dpi[i++] = d = new DriverPropertyInfo("auth",p.getProperty("auth","default")); + //d.description = "determines if password authentication is used"; + //d.choices = new String[4]; + //d.choices[0]="default"; // Get value from postgresql.auth property, defaults to trust + //d.choices[1]="trust"; // No password authentication + //d.choices[2]="password"; // Password authentication + //d.choices[3]="ident"; // Ident (RFC 1413) protocol + + return dpi; + } + + /** + * Gets the drivers major version number + * + * @return the drivers major version number + */ + public int getMajorVersion() + { + return MAJORVERSION; + } + + /** + * Get the drivers minor version number + * + * @return the drivers minor version number + */ + public int getMinorVersion() + { + return MINORVERSION; + } + + /** + * Report whether the driver is a genuine JDBC compliant driver. A + * driver may only report "true" here if it passes the JDBC compliance + * tests, otherwise it is required to return false. JDBC compliance + * requires full support for the JDBC API and full support for SQL 92 + * Entry Level. + * + *

For PostgreSQL, this is not yet possible, as we are not SQL92 + * compliant (yet). + */ + public boolean jdbcCompliant() + { + return false; + } + + private Properties props; + + static protected String[] protocols = { "jdbc","postgresql" }; + + /** + * Constructs a new DriverURL, splitting the specified URL into its + * component parts + * @param url JDBC URL to parse + * @param defaults Default properties + * @return Properties with elements added from the url + * @exception SQLException + */ + protected Properties parseURL(String url,Properties defaults) throws SQLException + { + int state = -1; + Properties urlProps = new Properties(defaults); + String key = new String(); + String value = new String(); + + StringTokenizer st = new StringTokenizer(url, ":/;=&?", true); + for (int count = 0; (st.hasMoreTokens()); count++) { + String token = st.nextToken(); + + // PM June 29 1997 + // Added this, to help me understand how this works. + // Unless you want each token to be processed, leave this commented out + // but don't delete it. + //DriverManager.println("wellFormedURL: state="+state+" count="+count+" token='"+token+"'"); + + // PM Aug 2 1997 - Modified to allow multiple backends + if (count <= 3) { + if ((count % 2) == 1 && token.equals(":")) + ; + else if((count % 2) == 0) { + boolean found=(count==0)?true:false; + for(int tmp=0;tmp 0) { + urlProps.put("Protocol",token); + found=true; + } + } + } + + if(found == false) + return null; + } else return null; + } + else if (count > 3) { + if (count == 4 && token.equals("/")) state = 0; + else if (count == 4) { + urlProps.put("PGDBNAME", token); + state = -2; + } + else if (count == 5 && state == 0 && token.equals("/")) + state = 1; + else if (count == 5 && state == 0) + return null; + else if (count == 6 && state == 1) + urlProps.put("PGHOST", token); + else if (count == 7 && token.equals(":")) state = 2; + else if (count == 8 && state == 2) { + try { + Integer portNumber = Integer.decode(token); + urlProps.put("PGPORT", portNumber.toString()); + } catch (Exception e) { + return null; + } + } + else if ((count == 7 || count == 9) && + (state == 1 || state == 2) && token.equals("/")) + state = -1; + else if (state == -1) { + urlProps.put("PGDBNAME", token); + state = -2; + } + else if (state <= -2 && (count % 2) == 1) { + // PM Aug 2 1997 - added tests for ? and & + if (token.equals(";") || token.equals("?") || token.equals("&") ) state = -3; + else if (token.equals("=")) state = -5; + } + else if (state <= -2 && (count % 2) == 0) { + if (state == -3) key = token; + else if (state == -5) { + value = token; + //DriverManager.println("put("+key+","+value+")"); + urlProps.put(key, value); + state = -2; + } + } + } + } + + // PM June 29 1997 + // This now outputs the properties only if we are logging + if(DriverManager.getLogStream() != null) + urlProps.list(DriverManager.getLogStream()); + + return urlProps; + + } + + /** + * @return the hostname portion of the URL + */ + public String host() + { + return props.getProperty("PGHOST","localhost"); + } + + /** + * @return the port number portion of the URL or -1 if no port was specified + */ + public int port() + { + return Integer.parseInt(props.getProperty("PGPORT","5432")); + } + + /** + * @return the database name of the URL + */ + public String database() + { + return props.getProperty("PGDBNAME"); + } + + /** + * @return the value of any property specified in the URL or properties + * passed to connect(), or null if not found. + */ + public String property(String name) + { + return props.getProperty(name); + } + + /** + * This method was added in v6.5, and simply throws an SQLException + * for an unimplemented method. I decided to do it this way while + * implementing the JDBC2 extensions to JDBC, as it should help keep the + * overall driver size down. + */ + public static SQLException notImplemented() + { + return new PSQLException("postgresql.unimplemented"); + } +} + diff -urN R6_5_2/jdbc/postgresql/PG_Stream.java CE19991108/jdbc/postgresql/PG_Stream.java --- R6_5_2/jdbc/postgresql/PG_Stream.java Wed Sep 15 15:42:18 1999 +++ CE19991108/jdbc/postgresql/PG_Stream.java Mon Nov 8 00:42:48 1999 @@ -262,8 +262,13 @@ } catch (IOException e) { throw new PSQLException("postgresql.stream.ioerror",e); } - String v = new String(rst, 0, s); + String v = bytesToString(rst, 0, s); return v; + } + + protected String bytesToString(byte[] bytes, int offset, int size) + throws PSQLException { + return new String(bytes, offset, size); } /** diff -urN R6_5_2/jdbc/postgresql/ce/Driver.java CE19991108/jdbc/postgresql/ce/Driver.java --- R6_5_2/jdbc/postgresql/ce/Driver.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/Driver.java Sat Oct 9 23:23:32 1999 @@ -0,0 +1,25 @@ +package postgresql.ce; + +import java.sql.*; + +import postgresql.util.PSQLException; + +public class Driver extends postgresql.DriverImpl +{ + static { + try { + java.sql.DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public Driver() throws SQLException { + if(System.getProperty("java.version").startsWith("1.1")) { + connectClass = "postgresql.ce.jdbc1.Connection"; + } + else { + connectClass = "postgresql.ce.jdbc2.Connection"; + } + } +} diff -urN R6_5_2/jdbc/postgresql/ce/PG_Stream.java CE19991108/jdbc/postgresql/ce/PG_Stream.java --- R6_5_2/jdbc/postgresql/ce/PG_Stream.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/PG_Stream.java Sat Oct 9 23:17:19 1999 @@ -0,0 +1,27 @@ +package postgresql.ce; + +import java.io.*; +import postgresql.util.PSQLException; + +public class PG_Stream extends postgresql.PG_Stream +{ + PgCharactorEncoding encoding = null;; + + public void setCharactorEncoding(PgCharactorEncoding encoding) { + this.encoding = encoding; + } + + public PG_Stream(String host, int port) throws IOException { + super(host, port); + } + + protected String bytesToString(byte[] bytes, int offset, int size) + throws PSQLException{ + String str = null; + if (encoding != null) + str = encoding.bytesToString(bytes, offset, size); + else + str = new String(bytes, offset, size); + return str; + } +} diff -urN R6_5_2/jdbc/postgresql/ce/PgCharactorEncoding.java CE19991108/jdbc/postgresql/ce/PgCharactorEncoding.java --- R6_5_2/jdbc/postgresql/ce/PgCharactorEncoding.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/PgCharactorEncoding.java Mon Nov 8 00:42:52 1999 @@ -0,0 +1,75 @@ +package postgresql.ce; + +import java.util.*; +import java.lang.*; +import java.io.UnsupportedEncodingException; +import postgresql.util.PSQLException; + +public class PgCharactorEncoding + +{ + static final String[] encodingMap = { + "EUC_JP", "EUCJIS", /* use EUCJIS for JDK 1.1.5 */ + "UNICODE", "UTF8", + /* "MULE_INTERNAL" is not supported */ + "SQL_ASCII", "ASCII", + "LATIN1", "ISO8859_1", + "LATIN2", "ISO8859_2", + "LATIN3", "ISO8859_3", + "LATIN4", "ISO8859_4", + "LATIN5", "ISO8859_9", + "KOI8", "KOI8_R", + "WIN", "Cp1251", + "ALT", "Cp866" + }; + + static Hashtable ceTable; + static { + // Encoding string PostgreSQL -> Java mapping + + ceTable = new Hashtable(); + for (int i = 0, len = encodingMap.length; i < len;) + ceTable.put(encodingMap[i++], encodingMap[i++]); + } + + String encoding; + + public PgCharactorEncoding(String encoding) { + setEncoding(encoding); + } + + public void setEncoding(String encoding) { + String mapped = null; + if (encoding != null) + mapped = (String)ceTable.get(encoding); + if (mapped != null) + this.encoding = mapped; + else + this.encoding = encoding; + } + + public byte[] stringToBytes(String str) throws PSQLException { + byte[] bytes = null; + try { + bytes = str.getBytes(encoding); + } catch (UnsupportedEncodingException e) { + throw new PSQLException("postgresql.ce.unsupportedEncoding",e); + } + return bytes; + } + + public String bytesToString(byte[] bytes, int offset, int size) + throws PSQLException { + String str = null; + try { + str = new String(bytes, offset, size, encoding); + } catch (UnsupportedEncodingException e) { + throw new PSQLException("postgresql.ce.unsupportedEncoding",e); + } + return str; + } + + public String bytesToString(byte[] bytes) throws PSQLException { + return bytesToString(bytes, 0, bytes.length); + } +} diff -urN R6_5_2/jdbc/postgresql/ce/compat/Driver.java CE19991108/jdbc/postgresql/ce/compat/Driver.java --- R6_5_2/jdbc/postgresql/ce/compat/Driver.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/compat/Driver.java Mon Nov 8 00:41:56 1999 @@ -0,0 +1,141 @@ +package postgresql.ce.compat; + +import java.sql.*; +import java.util.*; + +import postgresql.util.PSQLException; + +public class Driver extends postgresql.DriverImpl +{ + static final String SYSPROPCENAME = "postgresql.databaseencoding"; + + String sysPropCharactorEncoding = null; + + static { + try { + java.sql.DriverManager.registerDriver(new Driver()); + } catch (SQLException e) { + e.printStackTrace(); + } + } + + public Driver() throws SQLException { + if(System.getProperty("java.version").startsWith("1.1")) { + connectClass = "postgresql.ce.jdbc1.Connection"; + } + else { + connectClass = "postgresql.ce.jdbc2.Connection"; + } + try { + sysPropCharactorEncoding = System.getProperty(SYSPROPCENAME); + } catch (SecurityException e) { + // do nothing. + } + } + + protected Properties parseURL(String url,Properties defaults) throws SQLException + { + int state = -1; + Properties urlProps = new Properties(defaults); + + if (sysPropCharactorEncoding != null) + urlProps.put("PGDB.ce.sysprop", sysPropCharactorEncoding); + + String key = new String(); + String value = new String(); + + StringTokenizer st = new StringTokenizer(url, ":/;=&?", true); + for (int count = 0; (st.hasMoreTokens()); count++) { + String token = st.nextToken(); + + // PM June 29 1997 + // Added this, to help me understand how this works. + // Unless you want each token to be processed, leave this commented out + // but don't delete it. + //DriverManager.println("wellFormedURL: state="+state+" count="+count+" token='"+token+"'"); + + // PM Aug 2 1997 - Modified to allow multiple backends + if (count <= 3) { + if ((count % 2) == 1 && token.equals(":")) + ; + else if((count % 2) == 0) { + boolean found = false; + String encoding = null; + if(count ==2) { + int idx = token.indexOf("."); + if(0 <= idx) { + encoding = token.substring(idx+1); + token = token.substring(0, idx); + } + } + for(int tmp=0;tmp 0) { + urlProps.put("Protocol",token); + if (encoding != null) + urlProps.put("PGDB.ce.url", encoding); + } + } + } + + if(found == false) + return null; + } else return null; + } + else if (count > 3) { + if (count == 4 && token.equals("/")) state = 0; + else if (count == 4) { + urlProps.put("PGDBNAME", token); + state = -2; + } + else if (count == 5 && state == 0 && token.equals("/")) + state = 1; + else if (count == 5 && state == 0) + return null; + else if (count == 6 && state == 1) + urlProps.put("PGHOST", token); + else if (count == 7 && token.equals(":")) state = 2; + else if (count == 8 && state == 2) { + try { + Integer portNumber = Integer.decode(token); + urlProps.put("PGPORT", portNumber.toString()); + } catch (Exception e) { + return null; + } + } + else if ((count == 7 || count == 9) && + (state == 1 || state == 2) && token.equals("/")) + state = -1; + else if (state == -1) { + urlProps.put("PGDBNAME", token); + state = -2; + } + else if (state <= -2 && (count % 2) == 1) { + // PM Aug 2 1997 - added tests for ? and & + if (token.equals(";") || token.equals("?") || token.equals("&") ) state = -3; + else if (token.equals("=")) state = -5; + } + else if (state <= -2 && (count % 2) == 0) { + if (state == -3) key = token; + else if (state == -5) { + value = token; + //DriverManager.println("put("+key+","+value+")"); + urlProps.put(key, value); + state = -2; + } + } + } + } + + // PM June 29 1997 + // This now outputs the properties only if we are logging + if(DriverManager.getLogStream() != null) + urlProps.list(DriverManager.getLogStream()); + + return urlProps; + + } +} diff -urN R6_5_2/jdbc/postgresql/ce/jdbc1/Connection.java CE19991108/jdbc/postgresql/ce/jdbc1/Connection.java --- R6_5_2/jdbc/postgresql/ce/jdbc1/Connection.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/jdbc1/Connection.java Mon Nov 8 00:42:55 1999 @@ -0,0 +1,83 @@ +package postgresql.ce.jdbc1; + +import java.sql.*; +import java.io.*; +import java.util.*; +import postgresql.util.PSQLException; +import postgresql.ce.PgCharactorEncoding; +import postgresql.Field; + +public class Connection extends postgresql.jdbc1.Connection +{ + PgCharactorEncoding dbEncoding = null; + + protected void newPG_Stream(String host, int port) throws IOException { + pg_stream = new postgresql.ce.PG_Stream(host, port); + } + + protected void execGetDbEncoding(Properties drvProps) { + String dbEncodingStr = null; + if (drvProps != null) { + dbEncodingStr = drvProps.getProperty("charactorEncoding"); + if (dbEncodingStr != null) { + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + return; + } + + dbEncodingStr = drvProps.getProperty("PGDB.ce.sysprop"); + if (dbEncodingStr != null) { + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + return; + } + + dbEncodingStr = drvProps.getProperty("PGDB.ce.url"); + if (dbEncodingStr != null) { + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + return; + } + } + + try{ + java.sql.ResultSet r = ExecSQL("select getdatabaseencoding()"); + if (r != null) { + r.next(); + dbEncodingStr = r.getString(1); + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + } + } catch(SQLException e) { + // do nothing. + } + } + + public PgCharactorEncoding getCharactorEncoding() { + return dbEncoding; + } + + protected void setEncodingToPgStream() { + ((postgresql.ce.PG_Stream)pg_stream).setCharactorEncoding(dbEncoding); + } + + protected byte[] getBytesByDbEncoding(String str) throws PSQLException { + byte[] bytes = null; + if (dbEncoding != null) + bytes = dbEncoding.stringToBytes(str); + else + bytes = str.getBytes(); + return bytes; + } + + protected java.sql.ResultSet getResultSet(postgresql.Connection conn, + Field[] fields, Vector tuples, String status, int updateCount) + throws SQLException { + + return new postgresql.ce.jdbc1.ResultSet( + (postgresql.ce.jdbc1.Connection)conn, + fields, tuples, status, updateCount); + } + + public java.sql.DatabaseMetaData getMetaData() throws SQLException { + if (metadata == null) + metadata = new DatabaseMetaData(this); + return metadata; + } +} diff -urN R6_5_2/jdbc/postgresql/ce/jdbc1/DatabaseMetaData.java CE19991108/jdbc/postgresql/ce/jdbc1/DatabaseMetaData.java --- R6_5_2/jdbc/postgresql/ce/jdbc1/DatabaseMetaData.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/jdbc1/DatabaseMetaData.java Wed Sep 15 23:44:04 1999 @@ -0,0 +1,17 @@ +package postgresql.ce.jdbc1; + +import java.sql.*; +import java.util.*; +import postgresql.Field; + +public class DatabaseMetaData extends postgresql.jdbc1.DatabaseMetaData +{ + public DatabaseMetaData(Connection conn) { + super(conn); + } + + protected ResultSet newResultSet(Connection conn, Field[] fields, + Vector tuples, String status, int updateCount) { + return new ResultSet(conn, fields, tuples, status, updateCount); + } +} diff -urN R6_5_2/jdbc/postgresql/ce/jdbc1/ResultSet.java CE19991108/jdbc/postgresql/ce/jdbc1/ResultSet.java --- R6_5_2/jdbc/postgresql/ce/jdbc1/ResultSet.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/jdbc1/ResultSet.java Sat Oct 9 23:18:22 1999 @@ -0,0 +1,28 @@ +package postgresql.ce.jdbc1; + +import java.lang.*; +import java.util.*; +import postgresql.Field; +import postgresql.util.PSQLException; +import postgresql.ce.PgCharactorEncoding; + +public class ResultSet extends postgresql.jdbc1.ResultSet +{ + PgCharactorEncoding encoding = null; + + public ResultSet(Connection conn, Field[] fields, + Vector tuples, String status, int updateCount) { + + super(conn,fields,tuples,status,updateCount); + encoding = ((postgresql.ce.jdbc1.Connection)conn).getCharactorEncoding(); + } + + protected String bytesToString(byte[] bytes) throws PSQLException { + String str = null; + if (encoding != null) + str = encoding.bytesToString(bytes); + else + str = new String(bytes); + return str; + } +} diff -urN R6_5_2/jdbc/postgresql/ce/jdbc2/Connection.java CE19991108/jdbc/postgresql/ce/jdbc2/Connection.java --- R6_5_2/jdbc/postgresql/ce/jdbc2/Connection.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/jdbc2/Connection.java Mon Nov 8 00:42:58 1999 @@ -0,0 +1,83 @@ +package postgresql.ce.jdbc2; + +import java.sql.*; +import java.io.*; +import java.util.*; +import postgresql.util.PSQLException; +import postgresql.ce.PgCharactorEncoding; +import postgresql.Field; + +public class Connection extends postgresql.jdbc2.Connection +{ + PgCharactorEncoding dbEncoding = null; + + protected void newPG_Stream(String host, int port) throws IOException { + pg_stream = new postgresql.ce.PG_Stream(host, port); + } + + protected void execGetDbEncoding(Properties drvProps) { + String dbEncodingStr = null; + if (drvProps != null) { + dbEncodingStr = drvProps.getProperty("charactorEncoding"); + if (dbEncodingStr != null) { + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + return; + } + + dbEncodingStr = drvProps.getProperty("PGDB.ce.sysprop"); + if (dbEncodingStr != null) { + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + return; + } + + dbEncodingStr = drvProps.getProperty("PGDB.ce.url"); + if (dbEncodingStr != null) { + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + return; + } + } + + try{ + java.sql.ResultSet r = ExecSQL("select getdatabaseencoding()"); + if (r != null) { + r.next(); + dbEncodingStr = r.getString(1); + dbEncoding = new PgCharactorEncoding(dbEncodingStr); + } + } catch(SQLException e) { + // do nothing. + } + } + + public PgCharactorEncoding getCharactorEncoding() { + return dbEncoding; + } + + protected void setEncodingToPgStream() { + ((postgresql.ce.PG_Stream)pg_stream).setCharactorEncoding(dbEncoding); + } + + protected byte[] getBytesByDbEncoding(String str) throws PSQLException { + byte[] bytes = null; + if (dbEncoding != null) + bytes = dbEncoding.stringToBytes(str); + else + bytes = str.getBytes(); + return bytes; + } + + protected java.sql.ResultSet getResultSet(postgresql.Connection conn, + Field[] fields, Vector tuples, String status, int updateCount) + throws SQLException { + + return new postgresql.ce.jdbc2.ResultSet( + (postgresql.ce.jdbc2.Connection)conn, + fields, tuples, status, updateCount); + } + + public java.sql.DatabaseMetaData getMetaData() throws SQLException { + if (metadata == null) + metadata = new DatabaseMetaData(this); + return metadata; + } +} diff -urN R6_5_2/jdbc/postgresql/ce/jdbc2/DatabaseMetaData.java CE19991108/jdbc/postgresql/ce/jdbc2/DatabaseMetaData.java --- R6_5_2/jdbc/postgresql/ce/jdbc2/DatabaseMetaData.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/jdbc2/DatabaseMetaData.java Sat Oct 9 23:21:44 1999 @@ -0,0 +1,17 @@ +package postgresql.ce.jdbc2; + +import java.sql.*; +import java.util.*; +import postgresql.Field; + +public class DatabaseMetaData extends postgresql.jdbc2.DatabaseMetaData +{ + public DatabaseMetaData(Connection conn) { + super(conn); + } + + protected ResultSet newResultSet(Connection conn, Field[] fields, + Vector tuples, String status, int updateCount) { + return new ResultSet(conn, fields, tuples, status, updateCount); + } +} diff -urN R6_5_2/jdbc/postgresql/ce/jdbc2/ResultSet.java CE19991108/jdbc/postgresql/ce/jdbc2/ResultSet.java --- R6_5_2/jdbc/postgresql/ce/jdbc2/ResultSet.java Thu Jan 1 09:00:00 1970 +++ CE19991108/jdbc/postgresql/ce/jdbc2/ResultSet.java Sat Oct 9 23:21:44 1999 @@ -0,0 +1,28 @@ +package postgresql.ce.jdbc2; + +import java.lang.*; +import java.util.*; +import postgresql.Field; +import postgresql.util.PSQLException; +import postgresql.ce.PgCharactorEncoding; + +public class ResultSet extends postgresql.jdbc2.ResultSet +{ + PgCharactorEncoding encoding = null; + + public ResultSet(Connection conn, Field[] fields, + Vector tuples, String status, int updateCount) { + + super(conn,fields,tuples,status,updateCount); + encoding = ((postgresql.ce.jdbc2.Connection)conn).getCharactorEncoding(); + } + + protected String bytesToString(byte[] bytes) throws PSQLException { + String str = null; + if (encoding != null) + str = encoding.bytesToString(bytes); + else + str = new String(bytes); + return str; + } +} diff -urN R6_5_2/jdbc/postgresql/errors.properties CE19991108/jdbc/postgresql/errors.properties --- R6_5_2/jdbc/postgresql/errors.properties Wed Sep 15 19:37:50 1999 +++ CE19991108/jdbc/postgresql/errors.properties Wed Sep 15 23:43:55 1999 @@ -65,3 +65,4 @@ postgresql.unusual:Something unusual has occured to cause the driver to fail. Please report this exception: {0} postgresql.unimplemented:This method is not yet implemented. postgresql.unexpected:An unexpected result was returned by a query. +postgresql.ce.unsupportedEncoding:Unsupported Charactor Encoding. diff -urN R6_5_2/jdbc/postgresql/jdbc1/DatabaseMetaData.java CE19991108/jdbc/postgresql/jdbc1/DatabaseMetaData.java --- R6_5_2/jdbc/postgresql/jdbc1/DatabaseMetaData.java Wed Sep 15 15:42:21 1999 +++ CE19991108/jdbc/postgresql/jdbc1/DatabaseMetaData.java Wed Sep 15 23:44:07 1999 @@ -1515,7 +1515,7 @@ v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -1593,7 +1593,7 @@ // add query loop here - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -1694,7 +1694,7 @@ v.addElement(tuple); } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } // This array contains the valid values for the types argument @@ -1741,7 +1741,7 @@ f[0] = new Field(connection,new String("TABLE_SCHEM"),iVarcharOid,32); tuple[0] = "".getBytes(); v.addElement(tuple); - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -1765,7 +1765,7 @@ f[0] = new Field(connection,new String("TABLE_CAT"),iVarcharOid,32); tuple[0] = "".getBytes(); v.addElement(tuple); - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -1792,7 +1792,7 @@ tuple[0] = getTableTypes[i][0].getBytes(); v.addElement(tuple); } - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -1901,9 +1901,10 @@ dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4)); dr.next(); String typname=dr.getString(1); + byte[] typnameByBytes = dr.getBytes(1); dr.close(); tuple[4] = Integer.toString(Field.getSQLType(typname)).getBytes(); // Data type - tuple[5] = typname.getBytes(); // Type name + tuple[5] = typnameByBytes; // Type name // Column size // Looking at the psql source, @@ -1939,7 +1940,7 @@ v.addElement(tuple); } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -2002,7 +2003,7 @@ //v.addElement(tuple); } - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -2091,7 +2092,7 @@ f[6] = new Field(connection, new String("DECIMAL_DIGITS"), iInt2Oid, 2); f[7] = new Field(connection, new String("PSEUDO_COLUMN"), iInt2Oid, 2); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -2426,7 +2427,8 @@ while(rs.next()) { byte[][] tuple = new byte[18][]; String typname=rs.getString(1); - tuple[0] = typname.getBytes(); + byte[] typnameByBytes = rs.getBytes(1); + tuple[0] = typnameByBytes; tuple[1] = Integer.toString(Field.getSQLType(typname)).getBytes(); tuple[2] = b9; // for now tuple[6] = bnn; // for now @@ -2442,7 +2444,7 @@ v.addElement(tuple); } rs.close(); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } return null; @@ -2520,7 +2522,12 @@ f[11] = new Field(connection, new String("PAGES"), iInt4Oid, 4); f[12] = new Field(connection, new String("FILTER_CONDITION"), iVarcharOid, 32); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); + } + + protected ResultSet newResultSet(Connection conn, Field[] fields, + Vector tuples, String status, int updateCount) { + return new ResultSet(conn, fields, tuples, status, updateCount); } } diff -urN R6_5_2/jdbc/postgresql/jdbc1/ResultSet.java CE19991108/jdbc/postgresql/jdbc1/ResultSet.java --- R6_5_2/jdbc/postgresql/jdbc1/ResultSet.java Wed Sep 15 19:37:52 1999 +++ CE19991108/jdbc/postgresql/jdbc1/ResultSet.java Wed Sep 15 23:44:08 1999 @@ -147,9 +147,13 @@ wasNullFlag = (this_row[columnIndex - 1] == null); if(wasNullFlag) return null; - return new String(this_row[columnIndex - 1]); + return bytesToString(this_row[columnIndex - 1]); } + protected String bytesToString(byte[] bytes) throws PSQLException { + return new String(bytes); + } + /** * Get the value of a column in the current row as a Java boolean * diff -urN R6_5_2/jdbc/postgresql/jdbc2/DatabaseMetaData.java CE19991108/jdbc/postgresql/jdbc2/DatabaseMetaData.java --- R6_5_2/jdbc/postgresql/jdbc2/DatabaseMetaData.java Wed Sep 15 15:42:21 1999 +++ CE19991108/jdbc/postgresql/jdbc2/DatabaseMetaData.java Sat Oct 9 23:20:41 1999 @@ -1515,7 +1515,7 @@ v.addElement(tuple); } - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -1593,7 +1593,7 @@ // add query loop here - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -1694,7 +1694,7 @@ v.addElement(tuple); } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } // This array contains the valid values for the types argument @@ -1741,7 +1741,7 @@ f[0] = new Field(connection,new String("TABLE_SCHEM"),iVarcharOid,32); tuple[0] = "".getBytes(); v.addElement(tuple); - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -1765,7 +1765,7 @@ f[0] = new Field(connection,new String("TABLE_CAT"),iVarcharOid,32); tuple[0] = "".getBytes(); v.addElement(tuple); - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -1792,7 +1792,7 @@ tuple[0] = getTableTypes[i][0].getBytes(); v.addElement(tuple); } - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -1901,9 +1901,10 @@ dr = connection.ExecSQL("select typname from pg_type where oid = "+r.getString(4)); dr.next(); String typname=dr.getString(1); + byte[] typnameByBytes = dr.getBytes(1); dr.close(); tuple[4] = Integer.toString(Field.getSQLType(typname)).getBytes(); // Data type - tuple[5] = typname.getBytes(); // Type name + tuple[5] = typnameByBytes; // Type name // Column size // Looking at the psql source, @@ -1939,7 +1940,7 @@ v.addElement(tuple); } r.close(); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -2002,7 +2003,7 @@ //v.addElement(tuple); } - return new ResultSet(connection,f,v,"OK",1); + return newResultSet(connection,f,v,"OK",1); } /** @@ -2091,7 +2092,7 @@ f[6] = new Field(connection, new String("DECIMAL_DIGITS"), iInt2Oid, 2); f[7] = new Field(connection, new String("PSEUDO_COLUMN"), iInt2Oid, 2); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } /** @@ -2426,7 +2427,8 @@ while(rs.next()) { byte[][] tuple = new byte[18][]; String typname=rs.getString(1); - tuple[0] = typname.getBytes(); + byte[] typnameByBytes = rs.getBytes(1); + tuple[0] = typnameByBytes; tuple[1] = Integer.toString(Field.getSQLType(typname)).getBytes(); tuple[2] = b9; // for now tuple[6] = bnn; // for now @@ -2442,7 +2444,7 @@ v.addElement(tuple); } rs.close(); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } return null; @@ -2520,9 +2522,14 @@ f[11] = new Field(connection, new String("PAGES"), iInt4Oid, 4); f[12] = new Field(connection, new String("FILTER_CONDITION"), iVarcharOid, 32); - return new ResultSet(connection, f, v, "OK", 1); + return newResultSet(connection, f, v, "OK", 1); } + protected ResultSet newResultSet(Connection conn, Field[] fields, + Vector tuples, String status, int updateCount) { + return new ResultSet(conn, fields, tuples, status, updateCount); + } + // ** JDBC 2 Extensions ** public boolean deletesAreDetected(int i) throws SQLException diff -urN R6_5_2/jdbc/postgresql/jdbc2/ResultSet.java CE19991108/jdbc/postgresql/jdbc2/ResultSet.java --- R6_5_2/jdbc/postgresql/jdbc2/ResultSet.java Wed Sep 15 19:37:53 1999 +++ CE19991108/jdbc/postgresql/jdbc2/ResultSet.java Sat Oct 9 23:20:41 1999 @@ -148,9 +148,13 @@ wasNullFlag = (this_row[columnIndex - 1] == null); if(wasNullFlag) return null; - return new String(this_row[columnIndex - 1]); + return bytesToString(this_row[columnIndex - 1]); } + protected String bytesToString(byte[] bytes) throws PSQLException { + return new String(bytes); + } + /** * Get the value of a column in the current row as a Java boolean *