Skip to content

IGNITE-12381 SQL: Propagate H2 error codes to IgniteSQLException - #13719

Merged
zstan merged 5 commits into
apache:masterfrom
XianReallyHot-ZZH:IGNITE-12381-h2-error-codes
Oct 30, 2026
Merged

zstan merged 5 commits into
apache:masterfrom
XianReallyHot-ZZH:IGNITE-12381-h2-error-codes

Conversation

@XianReallyHot-ZZH

Copy link
Copy Markdown
Contributor

Ticket: IGNITE-12381

What changes

H2Connection.prepareStatement() / prepareStatementNoCache() and the SQLException catch in QueryParser#parseH2 wrapped every H2 error into IgniteSQLException with the generic IgniteQueryErrorCode.PARSING code, so a client could not distinguish, say, a missing table from a plain syntax error without parsing the message text.

This adds H2Utils.h2ErrorCode(int) mapping the H2 error codes that have a direct Ignite counterpart, and uses it at all three wrap sites:

H2 code Ignite code
TABLE_OR_VIEW_NOT_FOUND_1 (42102) TABLE_NOT_FOUND
TABLE_OR_VIEW_ALREADY_EXISTS_1 (42101) TABLE_ALREADY_EXISTS
COLUMN_NOT_FOUND_1 (42122) COLUMN_NOT_FOUND
DUPLICATE_COLUMN_NAME_1 (42121) COLUMN_ALREADY_EXISTS
INDEX_ALREADY_EXISTS_1 (42111) INDEX_ALREADY_EXISTS
INDEX_NOT_FOUND_1 (42112) INDEX_NOT_FOUND
SCHEMA_NOT_FOUND_1 (90079) SCHEMA_NOT_FOUND

All other codes keep the default PARSING. Error messages are unchanged, and so are SQL states — every mapped code already resolves to SqlStateCode.PARSING_EXCEPTION in IgniteQueryErrorCode#codeToSqlState, so only the integer error code visible through JDBC/ODBC becomes more specific. The change affects the H2 engine path (ignite-indexing) only; the default Calcite engine is untouched.

Testing

New testParseErrorCodes in IgniteCacheSqlQueryErrorSelfTest (modules/indexing) asserts IgniteSQLException.statusCode() for selects and DML against missing tables, a missing column, a missing schema, and that a pure syntax error still yields PARSING. All existing message assertions in that class pass unchanged, as do JdbcErrorsSelfTest and JdbcThinErrorsSelfTest (modules/clients, 75 tests).

@XianReallyHot-ZZH

Copy link
Copy Markdown
Contributor Author

The branch is rebased onto the latest master, which includes the fix for the ducktape GitHub checks failing on Ubuntu 26.04 runners (#13728). Could a committer please approve the workflow run so the checks can be re-verified on the new runner configuration? Many thanks!

@zstan

zstan commented Oct 27, 2026

Copy link
Copy Markdown
Contributor

Thanks, I run a TC [1] lets wait for results

[1] https://ci2.ignite.apache.org/buildConfiguration/IgniteTests24Java8_RunAll/9446231

@XianReallyHot-ZZH

Copy link
Copy Markdown
Contributor Author

Thanks for running the TeamCity builds! The C++ tests have been updated to match the propagated H2 error codes (commit edac422):

  • odbc-test TestSyntaxError: the query referenced an unknown column (fasf), which now resolves to COLUMN_NOT_FOUND (H2 42122) and is reported with SQLSTATE 42S22 instead of 42000. The test now uses a statement with a genuine syntax error (missing )) so it keeps covering 42000, and the original query moved to a new TestColumnNotFound case asserting 42S22 — mirroring the existing TestTableNotFound / TestIndexNotFound cases.
  • thin-client-test TestSqlStateOnErrors: select * from "UnknownCache".UNKNOWN_TABLE now resolves to SCHEMA_NOT_FOUND (H2 90079), whose SQLSTATE maps to 50000 through IgniteQueryErrorCode#codeToSqlState. This matches the pre-existing behavior of the schema-validation path (a query with a missing schema produced SCHEMA_NOT_FOUND → 50000 before this change as well). If you think SCHEMA_NOT_FOUND should map to 42000 there instead, I can add it to codeToSqlState — kept as-is for now to avoid changing the existing schema paths.

Also added an INSERT with an unknown column to IgniteCacheSqlQueryErrorSelfTest#testParseErrorCodes to pin the Java-side code (COLUMN_NOT_FOUND) that the ODBC test now relies on.

Verified at the H2 level (1.4.197 patched): INSERT with unknown column → 42122, unknown schema → 90079, unknown table → 42102, the new syntax-error statement → 42001. The full IgniteCacheSqlQueryErrorSelfTest (10 tests, including the new assertion) passes locally on JDK 17. Could you please re-run the C++ TeamCity suites when you have a chance?

@zstan

zstan commented Oct 29, 2026

Copy link
Copy Markdown
Contributor

@XianReallyHot-ZZH sorry but tests still failed:
IgniteOdbcTest: QueriesTestSuite: TestErrorMessag
IgniteOdbcTest: ErrorTestSuite: TestSyntaxError
IgniteOdbcTest: ErrorTestSuite: TestColumnNotFound

…egistered

H2 resolves the table name during statement preparation before reporting
syntax or column errors. TestType is registered in the "cache" schema, so
the previous PUBLIC-schema connections made both INSERT statements fail
with TABLE_NOT_FOUND (42S02) instead of the intended errors.

- TestSyntaxError / TestColumnNotFound: connect with SCHEMA=cache so the
  statements exercise the syntax error (42000) and the column-not-found
  error (42S22) respectively.
- TestErrorMessage: the missing table now surfaces its own SQLSTATE, so
  the expected message prefix is 42S02 instead of 42000.
@XianReallyHot-ZZH

Copy link
Copy Markdown
Contributor Author

Found the root cause — it was in my previous fix, not in the propagation itself. H2 resolves the table name during statement preparation before reporting syntax or column errors, and both new ODBC tests connected with SCHEMA=PUBLIC, while TestType is registered in the cache schema. So both INSERT statements actually failed with TABLE_NOT_FOUND (SQLSTATE 42S02) and never reached the errors the tests assert.

Verified against a local node started with the same caches as the ODBC test configuration (cache/cache2 with TestType/ComplexType) over the thin protocol:

Statement Schema statusCode → SQLSTATE
INSERT INTO TestType(_key VALUES(1) PUBLIC 3001 TABLE_NOT_FOUND → 42S02
INSERT INTO TestType(_key, fasf) VALUES(1, 'some') PUBLIC 3001 TABLE_NOT_FOUND → 42S02
INSERT INTO TestType(_key VALUES(1) cache 1001 PARSING → 42000
INSERT INTO TestType(_key, fasf) VALUES(1, 'some') cache 3008 COLUMN_NOT_FOUND → 42S22
SELECT a FROM B cache 3001 TABLE_NOT_FOUND → 42S02

Fix (commit af81887):

  • TestSyntaxError / TestColumnNotFound now connect with SCHEMA=cache, so the statements exercise the intended syntax error (42000) and column-not-found error (42S22).
  • QueriesTestSuite / TestErrorMessage expected the 42000: ... message prefix for a missing table; a missing table now surfaces its own SQLSTATE, so the prefix is updated to 42S02: ....

Could you please re-run the ODBC TeamCity suites once more? Thanks!

Propagating H2 error codes makes a query against a missing schema reach
the ODBC driver as SCHEMA_NOT_FOUND (3015), which had no case in
ResponseStatusToSqlState and fell through to the generic HY000 state
(the code was reported as 42000 before this change). Map it to the
standard invalid-schema-name state 3F000, add a TestSchemaNotFound case
to the ODBC error suite, and pin the COLUMN_ALREADY_EXISTS mapping
(duplicate column list entry in an INSERT) with a Java-side assertion.

Also drop a dead boost/regex include, fix a stale comment and pass
SQL_NTS instead of sizeof() in TestErrorMessage.
@XianReallyHot-ZZH

XianReallyHot-ZZH commented Oct 30, 2026 •

Copy link
Copy Markdown
Contributor Author

While re-checking the branch I found one more gap in the ODBC path: with the propagated codes, a query against a missing schema (e.g. SELECT * FROM "NoSuchSchema".UNKNOWN_TABLE) now reaches the ODBC driver as SCHEMA_NOT_FOUND (3015), which had no case in ResponseStatusToSqlState — it fell through to the generic HY000 where the client used to see 42000. Commit 5d049d10 maps it to the standard invalid-schema-name SQLSTATE 3F000, adds a TestSchemaNotFound case to the ODBC error suite, and pins the COLUMN_ALREADY_EXISTS mapping (duplicate column in an INSERT column list → 42S21) with a Java-side assertion (testParseErrorCodes, 10/10 green locally on JDK 17).

Two small test cleanups ride along: a stale comment + sizeof() → SQL_NTS in TestErrorMessage, and a dead boost/regex include in errors_test.cpp.

The branch now carries two commits since your last run (af81887 + 5d049d1) — same re-run request stands. Thanks!

@zstan
zstan merged commit 7b4a2a9 into apache:master Oct 30, 2026
5 checks passed
@XianReallyHot-ZZH
XianReallyHot-ZZH deleted the IGNITE-12381-h2-error-codes branch October 30, 2026 15:11
Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment

Labels

None yet

Projects

None yet

Development

Successfully merging this pull request may close these issues.

3 participants