IBM Support

[Db2] JDBC アプリケーションが -4220 エラーで失敗する原因となったデーターを特定する方法

How To


Summary

Error code = -4220 は文字変換中にエラーが発生した事を意味します。問題の抜本的解決には、エラーの原因となったデーターの除去や修正などの対応が必要です。

Objective

文字変換に失敗したデーターを特定だけではなく、該当のデーターを含むレコードを特定する事が重要です。
そこで、以下のステップでは、問題のデーターを戻した SQL ステートメントや、ステートメントのパラメーター・マーカーに渡された値、データーが格納された表とカラムの型もあわせて確認し、最後にレコード全体を取り出します。

Steps

1. JCC トレースの取得

次のいずれかの方法で JCC トレースを取得します。

[DB2 LUW] アプリケーションを変更せずに JDBC トレースを採取する方法

[DB2 LUW] JDBC トレース取得手順 (Universal JDBC Driver)


2. -4220 を受けたデーターを含む ResultSet オブジェクトの確認

JCC トレースで -4220 エラーが戻された場所を確認すると、ここでは、 ResultSet オブジェクトの getObject メソッドでエラーを受けていることが分かります。
ここで [ResultSet@54d7df97]getObject(1) は ResultSet オブジェクト ResultSet@54d7df97 に含まれる、ある行の 1 列目のデーターを取り出すことを意味します。

[jcc][Time:2017-11-15-11:23:46.752][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject (1) called
[jcc] BEGIN TRACE_DIAGNOSTICS
[jcc][Thread:pool-1-thread-1][SQLException@6242e669] java.sql.SQLException
[jcc][Thread:pool-1-thread-1][SQLException@6242e669] SQL state  = null
[jcc][Thread:pool-1-thread-1][SQLException@6242e669] Error code = -4220
[jcc][Thread:pool-1-thread-1][SQLException@6242e669] Message    = [jcc][t4][1065][12306][4.21.29] java.io.CharConversionException をキャッチしました。  詳しくは、添付の Throwable を参照してください。 ERRORCODE=-4220, SQLSTATE=null
[jcc][Thread:pool-1-thread-1][SQLException@6242e669] Stack trace follows
com.ibm.db2.jcc.am.SqlException: [jcc][t4][1065][12306][4.21.29] java.io.CharConversionException をキャッチしました。  詳しくは、添付の Throwable を参照してください。 ERRORCODE=-4220, SQLSTATE=null
        at com.ibm.db2.jcc.am.kd.a(kd.java:794)
        at com.ibm.db2.jcc.am.kd.a(kd.java:66)
        at com.ibm.db2.jcc.am.kd.a(kd.java:125)
        at com.ibm.db2.jcc.am.mc.a(mc.java:2963)
        at com.ibm.db2.jcc.am.mc.a(mc.java:630)
        at com.ibm.db2.jcc.am.mc.q(mc.java:609)
        at com.ibm.db2.jcc.am.mc.bb(mc.java:2830)
        at com.ibm.db2.jcc.am.ResultSet.getObjectX(ResultSet.java:1482)
        at com.ibm.db2.jcc.am.ResultSet.getObject(ResultSet.java:1453)


3. ResultSet を返した SQL ステートメントの特定

ステップ 2 で確認した ResultSet@54d7df97 を戻す SQL ステートメントを突き止め、問題のデーターを格納する表と列の名前を確認します。
ResultSet@54d7df97 の @ の後の番号 54d7df97 を return している関数を、トレース上で時間を遡って探すと、次の行が見つかりました。

[jcc][Time:2017-11-15-11:20:02.128][Thread:pool-1-thread-1][PreparedStatement@3224a577]executeQuery () returned com.ibm.db2.jcc.t4.h@54d7df97

ここでは 54d7df97 を戻したのは PrepareStatement (準備済み SQL ステートメント) のオブジェクト PreparedStatement@3224a577 に対する executeQuery (PreparedStatement の実行) とわかります。 トレースをさらに遡り、この PreparedStatement@3224a577 を 準備 (Prepare) している箇所を探すと、次の SQL ステートメントが確認できました。

[jcc][Time:2017-11-15-11:19:12.250][Thread:main][Connection@13df2a8c]prepareStatement (SELECT Q1.C1 A1, Q1.C2 A2, Q1.C3 A3, Q1.C4 A4, Q1.C5 A5, Q1.C6 A6, Q1.C7 A7, Q1.C8 A8, Q1.C9 A9, Q1.C10 A10, Q1.C11 A11, Q1.C12 A12, Q1.C13 A13, Q1.C14 A14, Q1.C15 A15, Q1.C16 A16, Q1.C17 A17, Q1.C18 A18, Q1.C19 A19, Q1.C20 A20, Q1.C21 A21, SUBSTR(Q2.C22,1,10) A22  FROM MYTAB1 Q1 INNER JOIN MYTAB2 Q2 ON Q1.C1 = Q2.C1 AND Q2.C2 = ' ' INNER JOIN (SELECT MYTAB3.C1, MYTAB3.C2 FROM MYTAB3 INNER JOIN (SELECT C1, MAX(C3) C3 FROM MYTAB3 GROUP BY C1 ) Q3 ON MYTAB3.C1 = Q3.C1 AND MYTAB3.C3 = Q3.C3 WHERE C4 = '2' ) Q4 ON Q1.C2 = Q4.C2 WHERE Q1.C1 BETWEEN ? AND ? AND Q1.C21 <> 0 GROUP BY Q1.C1, Q1.C2, Q1.C3, Q1.C4, Q1.C5, Q1.C6, Q1.C7, Q1.C9, Q1.C8, Q1.C10, Q1.C11, Q1.C12, Q1.C13, Q1.C14, Q1.C15, Q1.C16, Q1.C17, Q1.C18, Q1.C19, Q1.C20, Q1.C21, Q1.C22, SUBSTR(Q2.C22,1,10)) called
[jcc][Time:2017-11-15-11:19:12.250][Thread:main][Connection@13df2a8c]prepareStatement () returned LogicalPreparedStatement@352ff4da[com.ibm.db2.jcc.am.tp@3224a577]


4. SQL ステートメントに渡されたパラメーター・マーカー値の確認 (オプション作業)

ステップ 3 で確認した SQL ステートメントの条件には「Q1.C1 BETWEEN ? AND ?」と 2 つのパラメーター・マーカーが使用されていました。そこで、パラメーター・マーカーに設定されていた値を確認してみます。

パラメーター・マーカーへの値の設定は、PreparedStatement クラスの setObject メソッドを使用します。
そこで、トレースで prepareStatement がコールされる箇所から executeQuery がコールされまでの間で setObject を探すと、準備済み SQL ステートメント PreparedStatement@3224a577 の 1 つ目のパラメーター・マーカーには 000000000000 が、2 つ目には 008063134327 が設定されていました。

[jcc][Time:2017-11-15-11:19:12.351][Thread:pool-1-thread-1][PreparedStatement@3224a577]setObject (1, 000000000000) called
..........

[jcc][Time:2017-11-15-11:19:12.361][Thread:pool-1-thread-1][PreparedStatement@3224a577]setObject (2, 008063134327) called
..........

[jcc][Time:2017-11-15-11:19:12.361][Thread:pool-1-thread-1][PreparedStatement@3224a577]executeQuery () called


これらの値を、ステップ 3 で確認した SQL ステートメント中のパラメーター・マーカーに置き換えて実行すれば、表のデーターが変更されていない限り、問題発生時と同じレコードが戻されるはずです。


5. 問題のデーターを含むカラムの情報確認 (オプション作業)

トレースには、準備済み SQL ステートメント PreparedStatement@3224a577 の実行で戻される ResultSet の Column 1 から 22 までのカラムのメタデーターが出力されています。
この出力より、問題となっている getObject(1)  がアクセスする Column 1 は、データベース MYDB のスキーマ MYSCHEMA1 の表 MYTAB1 の列  C1 と分かります。また列タイプは CHAR で長さは 12、NOT NULL でないと分かります。

[jcc][ResultSetMetaData@268489c5] BEGIN TRACE_RESULT_SET_META_DATA
[jcc][ResultSetMetaData@268489c5] Result set meta data for statement Statement@3224a577
[jcc][ResultSetMetaData@268489c5] Number of result set columns: 22
isDescribed=true
[jcc][ResultSetMetaData@268489c5] Column 1: { label=A1, name=C1, type name=CHAR, type=1, nullable=0, precision=12, scale=0, schema name=MYSCHEMA1 , table name=MYTAB1, writable=false, sqlPrecision=0, sqlScale=0, sqlLength=12, sqlType=452, sqlCcsid=1208, sqlArrExtent=0, sqlName=A1, sqlLabel=null, sqlUnnamed=0, sqlComment=null, sqludtxType=<null>, sqludtRdb=<null>, sqludtSchema=<null>, sqludtName=<null>, sqlxKeymem=0, sqlxGenerated=0, sqlxParmmode=0, sqlxOptlck=0, sqlxCorname=null, sqlxName=C1, sqlxBasename=MYTAB1, sqlxUpdatable=0, sqlxSchema=MYSCHEMA1 , sqlxRdbnam=MYDB, internal type=1, is locator parameter=false }
..........

[jcc][ResultSetMetaData@268489c5] Column 22: { label=A22 , name=A22 , type name=CHAR, type=1, nullable=1, precision=10, scale=0, schema name=, table name=, writable=false, sqlPrecision=0, sqlScale=0, sqlLength=10, sqlType=453, sqlCcsid=1208, sqlArrExtent=0, sqlName=A22 , sqlLabel=null, sqlUnnamed=0, sqlComment=null, sqludtxType=<null>, sqludtRdb=<null>, sqludtSchema=<null>, sqludtName=<null>, sqlxKeymem=0, sqlxGenerated=0, sqlxParmmode=0, sqlxOptlck=0, sqlxCorname=null, sqlxName=null, sqlxBasename=null, sqlxUpdatable=0, sqlxSchema=null, sqlxRdbnam=MYDB, internal type=1, is locator parameter=false }


6. Error code = -4220 を生じたレコードの1つ前のレコードの確認

JCC トレースには受信バッファーの内容がダンプされています。
このダンプには、 読み出しに失敗したレコードを含む ResultSet の内容が出力されています。
そこで、まず読み出しに成功した最後のレコードを確認し、そのレコードの次のレコード(=問題のレコード)を受信バッファーのダンプより探します。

まず Error -4220 を出力した行を改めてトレースより探します。

[jcc][Thread:pool-1-thread-1][SQLException@6242e669] Error code = -4220


次に、この行よりトレースを遡り、最後に成功した getObject を探します。
ここでは getObject (22) に戻された 640384084 が、最後に読み出したレコードのデーターでした。
レコードの 1 番目のカラム値(getObject(1) の戻り値) から最後の 22 番目のカラム値(getObject(22) の戻り値) を記録しておきます。
その後の next() で ResultSet より取り出している次のレコードが、getObject(1) が失敗した問題のデーターです。

[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject (1) called
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject () returned 008015354197
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject (2) called
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject () returned 8097
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject (3) called
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject () returned 201709
..........

[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject (21) called
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject () returned 221
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject (22) called
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]getObject () returned 640384084
[jcc][SystemMonitor:start]
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]next () called
[jcc][Time:2017-11-15-11:23:46.741][Thread:pool-1-thread-1][ResultSet@54d7df97]next () returned true


上記のトレース出力よりさらにトレースを遡って確認した、直近の "RECEIVE BUFFER: QRYDTA" が、問題のレコードを含む ResultSet です。
下記の例では、 QRYDTA の最初の12バイト 190AD05300011904  241BFF00 以降が ResultSet のデーターです。
各レコードはFF00で区切られ、各カラム・データーは00で区切られています。

[jcc][t4]        RECEIVE BUFFER: QRYDTA              (ASCII)           (EBCDIC)
[jcc][t4]        0 1 2 3 4 5 6 7   8 9 A B C D E F   0123456789ABCDEF  0123456789ABCDEF
[jcc][t4] 0000   190AD05300011904  241BFF0030303830  ...S....$...0080  ..}.............
[jcc][t4] 0010   3135333435303534  0031333739003230  15345054.1379.20  ................
[jcc][t4] 0020   31373034000C0000  0000323031373039  1704......201709  ................
[jcc][t4] 0030   0032303137313000  8A01000000310000  .201710......1..  ................
[jcc][t4] 0040   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 0050   0000000000000000  1401000000140100  ................  ................
[jcc][t4] 0060   00000D0000000000  0000000000000000  ................  ................
[jcc][t4] 0070   0000000000000000  0000009701000000  ................  ...........p....
[jcc][t4] 0080   2020202020202020  2020FF0030303830            ..0080  ................
[jcc][t4] 0090   3135333436343832  0038303937003230  15346482.8097.20  ................
[jcc][t4] 00A0   3137303900010000  0000323031373039  1709......201709  ................
[jcc][t4] 00B0   0032303137313000  0000000000330000  .201710......3..  ................
[jcc][t4] 00C0   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 00D0   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 00E0   000000000000005B  0000000000000000  .......[........  .......$........
[jcc][t4] 00F0   0000000000000000  0000005B00000000  ...........[....  ...........$....
..........

ここで最初の12バイトは先頭から、次のようになります。

  • 4バイトのLength:190A
  • 4バイトのDDM Carrier:Chained OBJDSS(D053)
  • 4バイトのCorrelation identifier:0001
  • 4バイトのLength:1904
  • 4バイトのDDM Object:QRYDTA(241B) 
  • データーの先頭のFF00

※詳細は The Open Group Library より DRDA : FORMATTED DATA OBJECT CONTENT ARCHITECTURE 等をご確認ください。

QRYDTA の中から、1 番目のカラム値が 008015354197 、2 番目が 8097、・・・22列目のカラム値が 640384084 のレコードを探すと、オフセット050C 以降に見つかりました。
640384084 の16進標記 0x36343033383430383420 の後のレコード・セパレーター FF00 以降の 12 バイト 0x2B29226C1E1DA86BAF296AB8 が異常なデーターです。

[jcc][t4] 0500   3536313130313036  3020FF0030303830  561101060 ..0080  ................
[jcc][t4] 0510   3135333534313937  0038303937003230  15354197.8097.20  ................
[jcc][t4] 0520   3137303900010000  0000323031373039  1709......201709  ................
[jcc][t4] 0530   0032303137313000  0000000000330000  .201710......3..  ................
[jcc][t4] 0540   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 0550   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 0560   00000000000000DD  0000000000000000  ................  ................
[jcc][t4] 0570   0000000000000000  000000DD00000000  ................  ................
[jcc][t4] 0580   3634303338343038  3420FF002B29226C  640384084 ..+)"l  ...............%
[jcc][t4] 0590   1E1DA86BAF296AB8  00522E722D00E6D3  ...k.)j..R.r-...  ..y,..|.......WL
[jcc][t4] 05A0   B6095BA5008A5648  0E00B355513CA9B1  ..[...VH...UQ<..  ..$v..........z.
[jcc][t4] 05B0   0038AF017D83BD00  E7205AA9004F0075  .8..}.... Z..O.u  ....'c..X.!z.|..
[jcc][t4] 05C0   39C97800EECF240F  00CCA92FD10061AD  9.x...$..../..a.  .I........z.J./.
[jcc][t4] 05D0   FF6E003F12D33F00  9089C5460001B543  .n.?..?....F...C  .>...L...iE.....
[jcc][t4] 05E0   79008F832FD3000C  15FD2D008326E45D  y.../.....-..&.]  `..c.L......c.U)
[jcc][t4] 05F0   00C42D4EDA00F87E  FA4200EECA4CC90  ..-N...~.B...L..  .D.+..8=.....<A.
[jcc][t4] 0600   4DCD1BE57D461B21  64CFFF0030303830  M...}F.!d...0080  (..V'...........
[jcc][t4] 0610   3135333535343334  0030393639003230  15355434.0969.20  ................
[jcc][t4] 0620   31373034000C0000  0000323031373039  1704......201709  ................
[jcc][t4] 0630   0032303137313000  1400000000330000  .201710......3..  ................
[jcc][t4] 0640   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 0650   0000000000000000  0A000000000A0000  ................  ................
[jcc][t4] 0660   0000000000000000  0000000000000000  ................  ................
[jcc][t4] 0670   0000000000000000  0000001400000000  ................  ................
[jcc][t4] 0680   3034393138303431  2020FF0030303830  04918041  ..0080  ................


ステップ 3 で確認した SQL ステートメントもしくはステップ 5 で確認した ResultSet カラムのメタ情報より、問題のデーターは表 MYTAB1 の列  C1 と分かりました。

そこで、問題のデーターを含むレコード全体を確認するには、次の SQL を実行します。必要に応じて、フィールド・セパレーター 00 で区切られた他の値も用いて検索してください。

SELECT * FROM MYTAB1 where C1=x'29226C1E1DA86BAF296AB8'

Additional Information

 DB2 V10.5 Fix Pack 7 より古いレベルの JDBC ドライバーをご利用の場合は、次の技術文書を確認の上、必要な措置を取るようにしてください。

[{"Business Unit":{"code":"BU058","label":"IBM Infrastructure w\/TPS"},"Product":{"code":"SSEPGG","label":"Db2 for Linux, UNIX and Windows"},"Component":"","Platform":[{"code":"PF002","label":"AIX"},{"code":"PF010","label":"HP-UX"},{"code":"PF016","label":"Linux"},{"code":"PF027","label":"Solaris"},{"code":"PF033","label":"Windows"}],"Version":"All Versions","Edition":"","Line of Business":{"code":"LOB10","label":"Data and AI"}}]

Document Information

Modified date:
29 November 2022

UID

ibm10744699