diff --git a/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.json b/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.json index 414ec983cb..1ed6007d48 100644 --- a/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.json +++ b/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.json @@ -1485,9 +1485,9 @@ "case_scenarios": 22, "db2": true, "det": { - "state": "not equal", + "state": "not run", "why": [ - "ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)" + "a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given" ] }, "record": null, @@ -5944,9 +5944,9 @@ "case_scenarios": 22, "db2": true, "det": { - "state": "not equal", + "state": "not run", "why": [ - "ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)" + "a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given" ] }, "record": null, @@ -5958,9 +5958,9 @@ "case_scenarios": 22, "db2": true, "det": { - "state": "not equal", + "state": "not run", "why": [ - "ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)" + "a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given" ] }, "record": null, @@ -5972,7 +5972,7 @@ "det_port": "not yet measured (#4628)" }, "next": [ - "its det port equal on every scenario of cbsa-xfrfun: ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)" + "its det port equal on every scenario of cbsa-xfrfun: a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given" ], "oracle_backing": [ { diff --git a/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.md b/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.md index b50fbc9933..f84359afaf 100644 --- a/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.md +++ b/docs/language_status/evidence_report/cics-banking-sample-application-cbsa/report.md @@ -65,7 +65,7 @@ Translation measured by `cics_census.py survey` at translator commit `3bcbb8c623 | src/base/cobol_src/INQACCCU.cbl | L1 | 186/186 | 0 | — | — | — | — | not measured | not measured | not measured | not yet measured (#4628) | 5/8 | | src/base/cobol_src/INQCUST.cbl | L1 | 162/162 | 0 | — | — | — | — | not measured | not measured | not measured | not yet measured (#4628) | 5/13 | | src/base/cobol_src/UPDACC.cbl | L1 | 58/58 | 0 | cbsa-updacc | not run | 10 | stale | not measured | not measured | not measured | not yet measured (#4628) | 1/3 | -| src/base/cobol_src/XFRFUN.cbl | L1 | 426/426 | 0 | cbsa-xfrfun | not equal | 22 | none | not measured | not measured | not measured | not yet measured (#4628) | 5/9 | +| src/base/cobol_src/XFRFUN.cbl | L1 | 426/426 | 0 | cbsa-xfrfun | not run | 22 | none | not measured | not measured | not measured | not yet measured (#4628) | 5/9 | | src/base/cobol_src/ACCTCTRL.cbl | L0 | 15/18 | 3 | — | — | — | — | not measured | not measured | not measured | not yet measured (#4628) | 1/3 | | src/base/cobol_src/BANKDATA.cbl | L0 | 458/464 | 6 | — | — | — | — | not measured | not measured | not measured | not yet measured (#4628) | — | | src/base/cobol_src/BNK1CAC.cbl | L0 | 383/389 | 6 | — | — | — | — | not measured | not measured | not measured | not yet measured (#4628) | 7/11 | @@ -92,7 +92,7 @@ Translation measured by `cics_census.py survey` at translator commit `3bcbb8c623 - evidence record: none (8 scenarios in case.json) - **Executed equivalence** (cbsa-inqacc, linked, Db2): det port not run (a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given) - evidence record (the case's committed port): stale (stale on harness, oracle, generator); its proof: all equal, 14/14 scenarios equal, 29/29 records equal, 14 runs (0 fault runs); through its deployed entry points 14/14 -- **Executed equivalence** (cbsa-xfrfun, linked, Db2): det port not equal (ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)) +- **Executed equivalence** (cbsa-xfrfun, linked, Db2): det port not run (a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given) - evidence record: none (22 scenarios in case.json) - **Coverage:** not measured - **Oracle backing** (a column, not a level; per CICS command; DIFFERS assumptions reached: not measured): @@ -472,9 +472,9 @@ Translation measured by `cics_census.py survey` at translator commit `3bcbb8c623 ### src/base/cobol_src/XFRFUN.cbl -- L1 -- **Next level needs:** its det port equal on every scenario of cbsa-xfrfun: ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635) +- **Next level needs:** its det port equal on every scenario of cbsa-xfrfun: a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given - **Translation:** 426/426 statements, 0 holes; whole: yes -- **Executed equivalence** (cbsa-xfrfun, program, Db2, the case this report judges): det port not equal (ledgered as differing in det_sweep_baseline.json (#4658): the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)) +- **Executed equivalence** (cbsa-xfrfun, program, Db2, the case this report judges): det port not run (a Db2 case: CI's det-sweep skips Db2 cases and no local sweep was given) - evidence record: none (22 scenarios in case.json) - **Coverage:** not measured - **Oracle backing** (a column, not a level; per CICS command; DIFFERS assumptions reached: not measured): diff --git a/docs/language_status/oracle_assumptions.md b/docs/language_status/oracle_assumptions.md index e89e24213e..0f03797032 100644 --- a/docs/language_status/oracle_assumptions.md +++ b/docs/language_status/oracle_assumptions.md @@ -1041,6 +1041,14 @@ The length READQ TS returns on ITEMERR or QIDERR is not documented, so it is not - **Not compared to z/OS.** SQLSTATE subclasses, SQLERRD values beyond the row count, SQLERRP, and the dialect differences of other statements. +### Q1b. A datetime host variable Db2 rejects: -180 / 22007 on both sides — MATCHED (#4658) +- **What.** An UPDATE binding an unset (non-date) PIC X host variable to a DATE column gets SQLCODE -180, SQLSTATE 22007 + ("the string representation of a datetime value is not valid") from Db2 for LUW, and the same on z/OS Db2 (-180 is the + documented SQLCODE for this, SQLSTATE 22007). IBM's JDBC driver refuses some such values on the client with its own + -4220 (conversion error) before Db2 sees them; that code is never a Db2 SQLCODE an embedded-SQL program meets, so + DetSql maps it to -180 / 22007. Other driver errors pass through unchanged. SQLERRMC/SQLERRD of the mapped error stay + empty (the DISPLAYed SQLERRD(3) is 0 on both sides). + ### Q1a. A binary host variable takes what its bytes hold — MATCHED (#4579) - **What.** SELECT INTO / FETCH INTO a COMP / COMP-4 / BINARY / COMP-5 host variable gives SQLCODE -304 only for a value outside its halfword / fullword / doubleword (Db2 types the host variable by its data type: S9(9) COMP is INTEGER), not diff --git a/gitgalaxy/tools/cobol_to_java/det/cobolrt/sql/DetSql.java b/gitgalaxy/tools/cobol_to_java/det/cobolrt/sql/DetSql.java index e74367ee15..a78519c9c9 100644 --- a/gitgalaxy/tools/cobol_to_java/det/cobolrt/sql/DetSql.java +++ b/gitgalaxy/tools/cobol_to_java/det/cobolrt/sql/DetSql.java @@ -131,6 +131,9 @@ public static void reset(Field ca, Charset cs) { put(ca, SQLSTATE, 5, "00000", cs); } + /** IBM JCC's client-side "invalid conversion" error code, which Db2 itself never returns to a program. */ + private static final int JCC_BAD_CONVERSION = -4220; + private static void code(Field ca, int sqlcode, String state, Charset cs) { putInt(ca, SQLCODE, 4, sqlcode); put(ca, SQLSTATE, 5, state, cs); @@ -147,6 +150,13 @@ private static void warn(Field ca, int which, Charset cs) { private static void failed(Field ca, RuntimeException e, Charset cs) { for (Throwable t = e; t != null; t = t.getCause()) { if (t instanceof SQLException s && s.getErrorCode() != 0) { + if (s.getErrorCode() == JCC_BAD_CONVERSION) { + // #4658: the JDBC driver refused the host variable's bytes on the client (a date column bound to + // an unset, non-date PIC X) before Db2 saw them; the embedded-SQL program, on z/OS as on Db2 LUW, + // gets the server's verdict: -180, SQLSTATE 22007 (the string is not a valid datetime value). + code(ca, -180, "22007", cs); + return; + } code(ca, s.getErrorCode(), s.getSQLState() == null ? " " : s.getSQLState(), cs); db2Sqlca(ca, s, cs); return; diff --git a/tests/cobol_mainframe/test_sql_faults.py b/tests/cobol_mainframe/test_sql_faults.py index 5f3a341204..459e1f6bfa 100644 --- a/tests/cobol_mainframe/test_sql_faults.py +++ b/tests/cobol_mainframe/test_sql_faults.py @@ -132,6 +132,13 @@ def _jdk() -> Path | None: } DetSql.update(ca, "PROG:13", () -> 1, false, StandardCharsets.ISO_8859_1); // another statement: no fault System.out.println("other sqlcode " + sqlcode(ca)); + // #4658: the JDBC driver's client-side -4220 is the -180 / 22007 Db2 gives an embedded-SQL program + DetSql.update(ca, "PROG:14", () -> { throw new RuntimeException(new java.sql.SQLException("bad", (String) null, -4220)); }, + false, StandardCharsets.ISO_8859_1); + System.out.println("jcc sqlcode " + sqlcode(ca) + " state " + new String(ca.storage().bytes, 131, 5, StandardCharsets.ISO_8859_1)); + DetSql.update(ca, "PROG:15", () -> { throw new RuntimeException(new java.sql.SQLException("dup", "23505", -803)); }, + false, StandardCharsets.ISO_8859_1); + System.out.println("other error sqlcode " + sqlcode(ca)); // #4181: a 71-byte record LINKed as a 99-byte DTO: its own bytes, LOW-VALUES past it, and back up to its end Storage rec = new Storage(71); java.util.Arrays.fill(rec.bytes, (byte) 'E'); @@ -166,7 +173,7 @@ def test_detsql_injects_a_planned_fault_and_a_link_window_stops_at_the_record(tm out = subprocess.run([str(jdk / "java"), "-cp", str(tmp_path / "classes"), "ggtest.Main", str(log)], # noqa: S603 capture_output=True, text=True, check=True).stdout.splitlines() # fmt: skip assert out == ["run 1 sqlcode 0 ran 1", "run 2 sqlcode -803 ran 1", "run 3 sqlcode 0 ran 2", - "other sqlcode 0", "window EE 0 0", "back X 71"] # fmt: skip + "other sqlcode 0", "jcc sqlcode -180 state 22007", "other error sqlcode -803", "window EE 0 0", "back X 71"] # fmt: skip assert log.read_text(encoding="ascii").split() == ["SQL", "PROG", "12", "2", "-803"] diff --git a/tests/equivalence/det_sweep_baseline.json b/tests/equivalence/det_sweep_baseline.json index 82d41f7ddf..4a2dc86973 100644 --- a/tests/equivalence/det_sweep_baseline.json +++ b/tests/equivalence/det_sweep_baseline.json @@ -14,10 +14,6 @@ "issue": null, "why": "generated card numbers mix letters and digits: ASCII vs EBCDIC key order picks different duplicates (oracle_assumptions.md D1)" }, - "cbsa-xfrfun": { - "issue": "#4658", - "why": "the det port DISPLAYs SQLCODE -4220 where Db2/GnuCOBOL gives -180 on a null-date update (the proof compares a task's DISPLAY output since #4635)" - }, "mortgage-mpmt": { "issue": "#4271", "why": "IBM DBB EPSMPMT computes its payment through a COMP-1 item in hexadecimal floating point on z/OS, truncated decimal on GnuCOBOL. The det runtime models HFP since #4271 slice 1 (its interest COMPUTE translates), but the payment's (1 + C) ** N, N with decimal places, is a floating-point exponentiation IBM does not document bit for bit: a named hole (oracle_assumptions.md C6; its CBL NUMPROC(MIG) is modelled, C5)"