diff --git a/docs/test-results/2026-09-27-complex-arrays.md b/docs/test-results/2026-09-27-complex-arrays.md index ae6a001..7f50ccc 100644 --- a/docs/test-results/2026-09-27-complex-arrays.md +++ b/docs/test-results/2026-09-27-complex-arrays.md @@ -19,5 +19,17 @@ Real DM8 ARM verification: containing high-precision decimals and null elements. The vendored Go tests also exercise malformed nested elements and the modern -SSL CA/hostname validation path. Cross-schema object arrays and other DM8 -server versions still need dedicated regression environments. +SSL CA/hostname validation path. Other DM8 server versions still need dedicated +regression environments. + +Cross-schema regression added in [PR #23](https://github.com/skhe/dmPython/pull/23): +the test account creates same-named types, then reads a SYSDBA VARRAY of +objects from both a SYSDBA table and a table it owns. Both reads preserve the +foreign type owner, `DECIMAL(30,8)`, and Unicode text. The fix uses the server's +type schema ID rather than the result table owner. All PR checks passed, +including the ten ARM Linux real-database combinations across Python 3.9–3.13 +and both Unicode modes. + +The follow-up also reads a direct SYSDBA object type through a table owned by +the test account, with the same-named local object present. The focused GB18030 +real-database check passed. diff --git a/dpi_bridge/third_party/chunanyong_dm/PATCHES.md b/dpi_bridge/third_party/chunanyong_dm/PATCHES.md index dc57b5c..7d15d21 100644 --- a/dpi_bridge/third_party/chunanyong_dm/PATCHES.md +++ b/dpi_bridge/third_party/chunanyong_dm/PATCHES.md @@ -136,6 +136,16 @@ - Local TLS handshakes verify CA trust and DNS/IP SAN matching, including a bracketed IPv6 address, and reject a wrong hostname or untrusted CA. +## Patch: expose complex column type schema ID + +- File: `t.go` +- For a complex result column, append the server descriptor's schema ID to its + type name. The bridge resolves that ID through `ALL_OBJECTS`; the result + table's schema and the type's schema can differ. +- Regression: `tests/integration/test_p1_array_types.py` uses same-named types + in two schemas and reads both a foreign object and an array of those objects + from tables owned by the login user. + ## Patch: resolve service names with the bridge's default port - Files: `n.go`, `zzm.go` diff --git a/tests/integration/test_p1_array_types.py b/tests/integration/test_p1_array_types.py index aebad78..a2ad7b2 100644 --- a/tests/integration/test_p1_array_types.py +++ b/tests/integration/test_p1_array_types.py @@ -191,7 +191,7 @@ def test_varray_of_varray_keeps_decimal_elements(conn, table_name_factory, drop_ cur.close() -def test_cross_schema_varray_of_objects(conn, conn_params, table_name_factory): +def test_cross_schema_objects_and_varrays(conn, conn_params, table_name_factory): admin_password = os.environ.get("DM_CI_ADMIN_PASSWORD") if not admin_password: pytest.skip("cross-schema type regression requires the admin test password") @@ -200,6 +200,7 @@ def test_cross_schema_varray_of_objects(conn, conn_params, table_name_factory): array_type = table_name_factory("DMPY_SHARED_ARRAY") table = table_name_factory("DMPY_SHARED_TAB") local_table = table_name_factory("DMPY_REF_SHARED") + local_object_table = table_name_factory("DMPY_REF_ITEM") values = [[Decimal("12345678901234567890.12345678"), "汉字"], None] admin = dmPython.connect(**{**conn_params, "user": "SYSDBA", "password": admin_password}) created = [] @@ -225,20 +226,29 @@ def test_cross_schema_varray_of_objects(conn, conn_params, table_name_factory): local_created.append(("TYPE", array_type)) cur.execute(f"CREATE TABLE {local_table} (V SYSDBA.{array_type})") local_created.append(("TABLE", local_table)) + cur.execute(f"CREATE TABLE {local_object_table} (V SYSDBA.{object_type})") + local_created.append(("TABLE", local_object_table)) conn.commit() value = dmPython.objectvar(conn, array_type, schema="SYSDBA") assert value.type.schema == "SYSDBA" value.setvalue(values) + item = dmPython.objectvar(conn, object_type, schema="SYSDBA") + item.setvalue(values[0]) with conn.cursor() as cur: cur.execute(f"INSERT INTO SYSDBA.{table} VALUES (?)", (value,)) cur.execute(f"INSERT INTO {local_table} VALUES (?)", (value,)) + cur.execute(f"INSERT INTO {local_object_table} VALUES (?)", (item,)) conn.commit() for source in (f"SYSDBA.{table}", local_table): cur.execute(f"SELECT V FROM {source}") fetched = cur.fetchone()[0] assert fetched.type.schema == "SYSDBA" assert fetched.getvalue() == values + cur.execute(f"SELECT V FROM {local_object_table}") + fetched_item = cur.fetchone()[0] + assert fetched_item.type.schema == "SYSDBA" + assert fetched_item.getvalue() == values[0] finally: conn.rollback() with conn.cursor() as cur: