Skip to content

Fixes Issue #2549#2841

Merged
Hydrocharged merged 2 commits into
mainfrom
daylon/cast-fix
Jun 16, 2026
Merged

Fixes Issue #2549#2841
Hydrocharged merged 2 commits into
mainfrom
daylon/cast-fix

Conversation

@Hydrocharged

Copy link
Copy Markdown
Collaborator

@Hydrocharged Hydrocharged requested a review from fulghum June 11, 2026 12:26
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor
Main PR
covering_index_scan_postgres 1831.77/s 1843.01/s +0.6%
groupby_scan_postgres 125.12/s 121.45/s -3.0%
index_join_postgres 632.62/s 639.15/s +1.0%
index_join_scan_postgres 777.61/s 781.70/s +0.5%
index_scan_postgres 24.20/s 23.92/s -1.2%
oltp_delete_insert_postgres 739.65/s 724.04/s -2.2%
oltp_insert 671.71/s 667.84/s -0.6%
oltp_point_select 2745.17/s 2820.56/s +2.7%
oltp_read_only 2833.49/s 2825.32/s -0.3%
oltp_read_write 2173.91/s 2221.68/s +2.1%
oltp_update_index 693.75/s 698.19/s +0.6%
oltp_update_non_index 714.73/s 724.82/s +1.4%
oltp_write_only 1657.77/s 1672.25/s +0.8%
select_random_points 1783.67/s 1771.51/s -0.7%
select_random_ranges 1053.50/s 1067.85/s +1.3%
table_scan_postgres 22.99/s 22.42/s -2.5%
types_delete_insert_postgres 732.30/s 731.90/s -0.1%
types_table_scan_postgres 7.85/s 7.61/s -3.1%

@itoqa

itoqa Bot commented Jun 11, 2026

Copy link
Copy Markdown

Ito QA test results
Commit: b06b865: 8 test cases ran, 1 failed ❌, 6 passed ✅, 1 additional finding ⚠️.

Summary

Overall, the unified run was mostly successful with 6 of 8 tests passing, confirming correct explicit int32-to-bit behavior in normal paths (truncation, DML persistence, fresh-start cast availability, and runtime/catalog consistency) and validating the new pg_cast baseline of 118 rows while reclassifying the legacy 117-row upgrade gate as outdated. Two medium-severity defects remain: negative int32 casts to narrow BIT widths can produce malformed signed outputs like “-1” and “0-1,” and a duplicate cast-registration panic during startup can leave initialization unrecoverable via normal in-process retry, requiring process replacement.

Tests run by Ito

View full run

Result Severity Type Description
Medium severity Semantics The cast returns malformed signed-string artifacts (such as -1 and 0-1) instead of valid bit-only output or a deterministic cast error.
Catalog pg_cast returned the expected post-change baseline count of 118 rows.
Catalog Runtime int4->bit casting and pg_cast metadata stayed consistent for the same capability.
Catalog Upgrade validation confirmed the 117-row legacy gate is outdated while cast behavior remains correct at the 118-row baseline.
Semantics Explicit width casts returned the expected right-truncated values for 5::bit(2) and 6::bit(2).
Semantics Insert and update flows stored expected BIT values (v1=11011010, v2=010) using explicit integer casts.
Startup Fresh startup exposed the new int32-to-bit cast immediately, and SELECT 6::bit(2) returned 10 on first use.
⚠️ Medium severity Startup Instead of recovering cleanly, initialization panics on duplicate cast registration and the normal retry path does not re-run initialization, leaving startup unrecoverable without process replacement.
Additional Findings Details

These findings are unrelated to the current changes but were observed during testing.

🟡 Startup cannot recover after duplicate cast panic
  • Severity: Medium Medium severity
  • Description: Instead of recovering cleanly, initialization panics on duplicate cast registration and the normal retry path does not re-run initialization, leaving startup unrecoverable without process replacement.
  • Impact: A startup-time cast registration collision can leave the process unable to complete initialization through normal retry flow. This affects a core workflow (service startup) but is scoped to the collision path rather than all runtime traffic.
  • Steps to Reproduce:
    1. Start the server with a cast registration state that causes an int32-to-bit duplicate cast key.
    2. Observe that cast registration panics during initialization when the duplicate key is inserted.
    3. Retry startup through the normal in-process initialization path and observe initialization does not recover.
  • Stub / mock content: No stubs, mocks, or bypasses were applied for this test in the recorded run.
  • Code Analysis: I reviewed server/functions/framework/cast.go, server/initialization/initialization.go, and server/cast/int32.go. Cast registration helpers panic on duplicate IDs, and initialization runs inside sync.Once; together this creates a plausible unrecoverable startup state after panic because subsequent in-process retries do not execute initialization again.

Tip

Reply with @itoqa to send us feedback on this test run.

Comment thread server/cast/int32.go
@github-actions

github-actions Bot commented Jun 11, 2026

Copy link
Copy Markdown
Contributor
Main PR
Total 42090 42090
Successful 18269 18269
Failures 23821 23821
Partial Successes1 5333 5333
Main PR
Successful 43.4046% 43.4046%
Failures 56.5954% 56.5954%

Footnotes

  1. These are tests that we're marking as Successful, however they do not match the expected output in some way. This is due to small differences, such as different wording on the error messages, or the column names being incorrect while the data itself is correct.

@fulghum fulghum left a comment

Copy link
Copy Markdown
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Looks good!

Comment thread server/cast/int32.go
@Hydrocharged Hydrocharged enabled auto-merge June 16, 2026 11:34
@itoqa

itoqa Bot commented Jun 16, 2026

Copy link
Copy Markdown

Ito QA test results
Ito Diff Reportb06b8654ae5947: 4 test cases ran, 0 regressions ❌, 0 new failures ❌, 0 still failing ❌, 2 fixed ✅, 0 passing ✅, 2 additional findings ⚠️.

Diff Summary

This diff run surfaced

This run exercised SQL type-conversion behavior around integer-to-bit casting, including edge-case negative values and nested read/write flows, plus a startup hard-failure guard path for invalid cast configuration. Overall, core startup safety behavior looked stable while casting edge paths continue to show known product defects rather than new change-driven breakage.

Safe to merge — the observed issues are medium-severity, pre-existing casting edge-case defects and are not attributed to this PR’s code changes. Results indicate low merge risk for this change, with follow-up work needed separately on integer-to-bit conversion reliability.

Tests run by Ito

View full run

Result State Severity Type Description
❌->✅ Fixed Semantics Negative integer to bit/bit(n) casts failed cleanly and deterministically with EXPLICIT CAST errors, and did not produce malformed signed string artifacts.
❌->✅ Fixed Startup A deliberately injected Int32->Bit cast ID collision consistently triggered a clear startup panic ("duplicate built-in cast") and did not produce a silent or half-initialized server state.
⏸️ Skipped Catalog pg_cast returned the expected post-change baseline count of 118 rows.
⏸️ Skipped Catalog Runtime int4->bit casting and pg_cast metadata stayed consistent for the same capability.
⏸️ Skipped Catalog Upgrade validation confirmed the 117-row legacy gate is outdated while cast behavior remains correct at the 118-row baseline.
⏸️ Skipped Semantics Explicit width casts returned the expected right-truncated values for 5::bit(2) and 6::bit(2).
⏸️ Skipped Semantics Insert and update flows stored expected BIT values (v1=11011010, v2=010) using explicit integer casts.
⏸️ Skipped Startup Fresh startup exposed the new int32-to-bit cast immediately, and SELECT 6::bit(2) returned 10 on first use.
⚠️ Additional Finding Medium severity Semantics Expected the query to return four BIT values, but evaluation stops on EXPLICIT CAST errors such as cast from integer to bit(1) does not exist.
⚠️ Additional Finding Medium severity Semantics The runtime returns EXPLICIT CAST errors (integer -> bit(2) does not exist) for nested cast expressions, so neither read-path evaluation nor write-path materialization can validate requested typmod behavior.
Additional Findings Details

These findings are unrelated to the current changes but were observed during testing.

🟡 Negative integer explicit BIT cast fails
  • Severity: Medium Medium severity
  • Description: Expected the query to return four BIT values, but evaluation stops on EXPLICIT CAST errors such as cast from integer to bit(1) does not exist.
  • Impact: Negative integer-to-bit casts fail at runtime, so queries that rely on this conversion do not return the expected bit values. This breaks a basic SQL type-conversion path for affected users.
  • Steps to Reproduce:
    1. Connect to the local Doltgres instance used for the run.
    2. Execute SELECT (-1)::bit, (-2)::bit, (-5)::bit(2), (-6::int4)::bit(2).
    3. Observe EXPLICIT CAST errors instead of a returned row of bit values.
  • Stub / mock content: Authentication was intentionally bypassed for this local non-production run by setting EnableAuthentication=false, and the query was executed against a locally built Doltgres container with QA fixture setup.
  • Code Analysis: Explicit cast evaluation throws a missing-cast error whenever cast lookup returns an invalid cast in server/expression/explicit_cast.go. The PR changed only test expectations in testing/go/types_test.go and did not modify this runtime path. Cast registration currently includes an int32->bit explicit cast in server/cast/int32.go, but the exercised negative-integer path still resolves to a cast miss at runtime, indicating missing or mismatched cast coverage on the source-type path being resolved for these expressions. A practical fix is to align explicit cast registration/lookup coverage so resolved integer literal variants used by this query map to a valid integer->bit cast.
Evidence Package
🟡 Nested integer to bit cast fails
  • Severity: Medium Medium severity
  • Description: The runtime returns EXPLICIT CAST errors (integer -> bit(2) does not exist) for nested cast expressions, so neither read-path evaluation nor write-path materialization can validate requested typmod behavior.
  • Impact: Nested casts to bit(2) fail during both query evaluation and INSERT materialization, so users cannot rely on the expected type-preserving behavior in this data path.
  • Steps to Reproduce:
    1. Create a table with a BIT(2) column, for example CREATE TABLE t_bit_nested (id INT, v BIT(2)).
    2. Run SELECT ((-5)::int4)::bit(2).
    3. Run INSERT INTO t_bit_nested VALUES (1, ((-6)::int4)::bit(2)).
    4. Observe both statements fail with EXPLICIT CAST errors before any BIT(2) value materializes.
  • Stub / mock content: Authentication was intentionally bypassed for this local QA run by setting EnableAuthentication=false, and the cast checks ran against a local non-production Doltgres instance with test fixtures.
  • Code Analysis: In server/expression/explicit_cast.go, ExplicitCast.Eval resolves a cast via castsColl.GetExplicitCast and aborts when no valid cast ID is found. In server/cast/int32.go, an explicit cast is registered for Int32 -> Bit, but observed runtime still reports integer -> bit(2) as missing in nested/DML execution. This indicates a real cast-resolution gap between resolved source/target types at evaluation time and the registered cast key used for lookup. The smallest practical fix is to normalize integer-family type identity/typmod handling in explicit-cast lookup for BIT(n), or register the missing equivalent explicit-cast mapping used by these nested paths so the existing cast function is reachable.
Evidence Package

Tip

Reply with @itoqa to send us feedback on this test run.

@Hydrocharged Hydrocharged merged commit 49adb2c into main Jun 16, 2026
24 of 25 checks passed
@Hydrocharged Hydrocharged deleted the daylon/cast-fix branch June 16, 2026 23:31
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.

2 participants