[pgpool-general-jp: 1203] Re: JDBC API の executeBatch() メソッドの実行について

Yugo Nagata nagata @ sraoss.co.jp
2013年 10月 18日 (金) 18:00:29 JST


沖様

長田です。

返信が遅くなってしまい大変申し訳ありません。
JDBC の仕様を調査しまして原因および対処法がわかりましたのでご報告いたします。

この JDBC の例外は「default が now() であるカラムがあるテーブル」に対して、
その値を省略した INSERT のプリペアド文を「5回以上」実行すると発生します。

default が now() のカラムがある場合、pgpool はその時刻値を事前に取得し、
プリペアド文に新しいパラメータとして追加します。これはレプリケーション
モードで複数のバックエンドに同じ時刻値を送信する必要があるためです。

一方で JDBC は、同じ文の5回目以降の実行の際には Describe メッセージを
DB に送信し「文に含まれるパラメータの型」を取得します。

しかし pgpool が途中でパラメータを追加しているため、JDBC が期待する個数
以上のパラメータ型が JDBC に返って来てしまいます。これが、
java.lang.ArrayIndexOutOfBoundsException を引き起こす原因です。

これは pgpool-II の不具合ですが、対応については検討中で時期は未定です。

なお上述の JDBC の動作の「5回目」というのは、prepareThreshold という
パラメータに関係しており、JDBC はこの回数以前の実行か、それ以降かで
振る舞いが異なります。このパラメータのデフォルト値が 5 となっています。

# ここでは詳細は省きますが、6回目以降は Parse を省略し、同じ文を使いまわす
# という機能です。5回目の実行ではその準備を行います。

ですので、workaroud となりますが、以下のように preparedThreshold の機能を無効
にすることで、今回の例外は防ぐことができます。

jdbc.url=jdbc:postgresql://localhost:5432/test?prepareThreshold=0

以上、よろしくお願いいたします。

On Tue, 10 Sep 2013 16:39:11 +0900
沖賢治 <kenjio @ h-t.co.jp> wrote:

> 長田様
> お世話になっております。沖です。
> 
> お手間取らせてしまい
> 申し訳ありません。
> 再現させる事が出来まして、良かったです。
> 
> 大変、申し訳ありませんが
> ご調査の程、よろしくお願い致します。
> 
> 
> 2013年9月10日 15:40 Yugo Nagata <nagata @ sraoss.co.jp>:
> > 沖様
> >
> > 長田です。
> >
> > 情報提供ありがとうございます。エラーを再現することができました。
> > テーブルの not null 制約を外した場合、以下のようなプログラムでも
> > 再現できることがわかりました。
> >
> >   stmt = connection.prepareStatement("insert into t_test(c2) values(?)");
> >   for (int i = 0; i < 10; i++) {
> >       Object param;
> >       param = new java.util.Date();
> >       stmt.setTimestamp(1, new java.sql.Timestamp(
> >           ((java.util.Date)param).getTime()));
> >       stmt.addBatch();
> >   }
> >   stmt.executeBatch();
> >   connection.commit();
> >
> > 原因につきましては、現在調査中です。
> >
> > On Mon, 9 Sep 2013 21:06:13 +0900
> > 沖賢治 <kenjio @ h-t.co.jp> wrote:
> >
> >> 長田様
> >> お世話になっております。沖です。
> >>
> >> ご返信頂き、誠にありがとうございます。
> >>
> >> 抜粋ではございますが
> >> 以下にソースを記述致します。
> >>
> >> ################### テストしているテーブル構造 ######################
> >>
> >> CREATE TABLE t_test
> >> (
> >>   c1 integer NOT NULL,
> >>   c2 date NOT NULL,
> >>   c3 integer NOT NULL,
> >>   c4 integer NOT NULL,
> >>   c5 integer NOT NULL,
> >>   c6 timestamp with time zone DEFAULT now(),
> >>   c7 timestamp with time zone,
> >>   c8 integer,
> >> )
> >>
> >> ###################  実行している Java のソースの抜粋   ###############
> >>
> >>     String url = "jdbc:postgresql://192.168.0.1:9999/test";
> >>
> >>     Connection con = DriverManager.getConnection(url, "postgres", "123456");
> >>     con.setAutoCommit(false);
> >>     PreparedStatement stmt = con.prepareStatement(
> >>             "insert into t_test(c1, c2, c3, c4, c5) values(?,?,?,?,?)");
> >>     for (List paramList : rowParameterList) {
> >>         for (int i = 0; i < paramList.size(); i++) {
> >>             Object param = paramList.get(i);
> >>             if (param instanceof Date) {
> >>                 stmt.setTimestamp(i + 1, new
> >> java.sql.Timestamp(((Date) param).getTime()));
> >>             } else {
> >>                 stmt.setObject(i + 1, param);
> >>             }
> >>         }
> >>         stmt.addBatch();
> >>     }
> >>     stmt.executeBatch();
> >>
> >>     con.commit();
> >>     stmt.close();
> >>     con.close();
> >>
> >> ##############################################################
> >>
> >> またその後、調査を行っていて以下の事が分かりました。
> >>
> >> c6 のカラムをバインド変数で指定するように
> >> したところ、エラーが発生しないようになりました。
> >> (c6 には デフォルト値で now() が指定されており
> >>  デフォルト値でINSERTを行う場合はエラーとなり、
> >>  Java側で値を指定してINSERTするようにしたら
> >>  正常に実行できるようになりました。)
> >>
> >>
> >> 以上となります。
> >> 何卒、よろしくお願い致します。
> >>
> >> 2013年9月9日 19:05 Yugo Nagata <nagata @ sraoss.co.jp>:
> >> > はじめまして、長田です。
> >> > ご報告ありがとうございます。
> >> >
> >> > 以下の環境で現象の再現を試みましたが、pgpool-II 3.3.0 で executeBatch()
> >> > のエラーは発生させることはできませんでした。
> >> >
> >> >  pgpool-II 3.3.0
> >> >  postgreql 9.2.4
> >> >  JDBCドライバー  postgresql-9.2-1003.jdbc4.jar
> >> >  Java  1.6.0_24 および 1.7.0
> >> >
> >> > お手数ですが、再現プログラムを提供いただけないでしょうか。
> >> >
> >> > On Fri, 6 Sep 2013 19:43:19 +0900
> >> > 沖賢治 <kenjio @ h-t.co.jp> wrote:
> >> >
> >> >> はじめまして、沖と申します。
> >> >> お世話になっております。
> >> >>
> >> >> 現在、pgpool 3.4.1  を利用していまして
> >> >> pgpool-II 3.3.0 へのアップグレードを検討しています。
> >> >> しかし、問題が発生して、困っています。
> >> >> ご意見いただければ幸いでございます。
> >> >>
> >> >> 【現在発生している問題】
> >> >> 弊社では、Javaベースのシステムを構築しているのですが
> >> >> JDBC APIのexecuteBatch()メソッドを実行すると
> >> >> 以下のエラーが出力され実行が行えません。
> >> >>
> >> >> java.lang.ArrayIndexOutOfBoundsException: 5
> >> >> at org.postgresql.core.v3.SimpleParameterList.setResolvedType(SimpleParameterList.java:269)
> >> >> at org.postgresql.core.v3.QueryExecutorImpl.processResults(QueryExecutorImpl.java:1738)
> >> >> at org.postgresql.core.v3.QueryExecutorImpl.execute(QueryExecutorImpl.java:405)
> >> >> at org.postgresql.jdbc2.AbstractJdbc2Statement.executeBatch(AbstractJdbc2Statement.java:2893)
> >> >> ・・・
> >> >>
> >> >> このエラーは、現在利用している pgpool 3.4.1 環境下では発生せず、
> >> >> pgpool-II 3.3.0 環境下では発生致します。
> >> >> また、pgpool-II 3.3.0 環境下でも JDBCの接続文字列に 「protocolVersion=2」
> >> >> を付加して接続を行うと正常に実行されます。
> >> >> 出来ましたら、
> >> >> pgpool-II 3.3.0 環境下でも、protocolVersion=2の指定なし(プロトコルバージョンV3)で
> >> >> 接続させてxecuteBatch()メソッドを動作できるようにしたいのですが
> >> >> なにか原因となる部分が想定できますでしょうか?
> >> >>
> >> >> 検証しました環境は、以下の通りとなります。
> >> >> pgpool-II 3.3.0
> >> >> postgreql 9.2.4
> >> >> JDBCドライバー  postgresql-9.2-1003.jdbc4.jar
> >> >> Java  1.6.0_34-b04
> >> >>
> >> >> DBサーバは、2台構成で
> >> >> replication_mode = on
> >> >> load_balance_mode = on
> >> >> で設定しています。
> >> >>
> >> >> ※ pgpool 以外は、現在運用を行っている環境と同じ設定となっております。
> >> >>
> >> >>
> >> >> 以上となります。
> >> >> 何卒、よろしくお願い致します。
> >> >> _______________________________________________
> >> >> pgpool-general-jp mailing list
> >> >> pgpool-general-jp @ sraoss.jp
> >> >> http://www.sraoss.jp/mailman/listinfo/pgpool-general-jp
> >> >
> >> >
> >> > --
> >> > Yugo Nagata <nagata @ sraoss.co.jp>
> >
> >
> > --
> > Yugo Nagata <nagata @ sraoss.co.jp>


-- 
Yugo Nagata <nagata @ sraoss.co.jp>


pgpool-general-jp メーリングリストの案内