core: carry enums, views and missing placeholders through the analysis core - #4614
Open
kyleconroy wants to merge 3 commits into
Open
core: carry enums, views and missing placeholders through the analysis core#4614kyleconroy wants to merge 3 commits into
kyleconroy wants to merge 3 commits into
Conversation
The core catalog created an enum type on CREATE TYPE ... AS ENUM but kept none of its labels, and the dump that hands the catalog to codegen carried relations only. Under SQLCEXPERIMENT=coreanalyzer every enum was missing from models.go, PostgreSQL enum columns were typed any and MySQL ENUM columns string. The catalog now stores enum labels (sql_enum_label, modeled on pg_enum) and the schema package applies the statements that change them: ALTER TYPE ADD VALUE (with BEFORE/AFTER and IF NOT EXISTS), RENAME VALUE, RENAME TO, SET SCHEMA, and DROP TYPE. A MySQL ENUM or SET column declares an enum of its own, named <table>_<column> as the legacy catalog names it; it follows the column and the table through renames, is replaced on MODIFY, and goes with a dropped column or table. The dump adds each enum to its schema so codegen builds the same Go types either way a query set was analyzed. Type names now keep the schema an engine reports on the TypeName itself and drop a spelled-out "public.", so foo.mood and public.status resolve the way their column references do. In the core replay context 46 more cases pass, with no case regressing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XZcKb4GFiZQbeo9oVmyF3m
The dump that carries the core catalog to codegen listed tables only, so under SQLCEXPERIMENT=coreanalyzer a view, a materialized view or a table created from a query had no model in models.go, and a query selecting all of one got a row struct of its own instead of the view's model. The listing now covers the relations a query selects rows from the same way, which is what codegen builds a model for. In the core replay context 8 more cases pass, with no case regressing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XZcKb4GFiZQbeo9oVmyF3m
Under SQLCEXPERIMENT=coreanalyzer several statement shapes lost their parameters, so the generated function took fewer arguments than the query has placeholders: - INSERT ... SELECT: the engines report the source query with an empty VALUES list rather than none, so the analyzer took the VALUES branch and walked nothing. The query is analyzed now, and a placeholder selected directly stands in for the column it lands in. - UPDATE ... LIMIT and DELETE ... LIMIT, and LIMIT/OFFSET on a UNION, INTERSECT or EXCEPT, were never looked at. - ON DUPLICATE KEY UPDATE assignments were never looked at; they bind the way SET does. - x IN (SELECT ...) on MySQL arrives wrapped in a sublink, which the IN node did not look through. - x COLLATE c: SQLite puts the expression in the node's other field and the collation's name where PostgreSQL puts the expression, so the placeholder underneath was neither found nor typed. - CALL: the compiler only sent SELECT, INSERT, UPDATE and DELETE through the core, and the schema package skipped CREATE PROCEDURE. A procedure is recorded now, with a void pseudo type as its result, and a CALL types each placeholder from the procedure's declared parameter, by position or by name, and names it after the parameter. The AST gains IsProcedure, which both parsers set, since a function with only OUT parameters also declares no return type. A placeholder on the left of an IN list takes its type from the members, the way the other operand of a comparison would. In the core replay context 12 more cases pass, with no case regressing. Co-Authored-By: Claude Fable 5.1 <noreply@anthropic.com> Claude-Session: https://claude.ai/code/session_01XZcKb4GFiZQbeo9oVmyF3m
kyleconroy
force-pushed
the
claude/magical-lamport-ckjxj8
branch
from
September 9, 2026 06:14
6c75a73 to
8a6f99d
Compare
This file contains hidden or bidirectional Unicode text that may be interpreted or compiled differently than what appears below. To review, open the file in an editor that reveals hidden Unicode characters.
Learn more about bidirectional Unicode characters
Sign up for free
to join this conversation on GitHub.
Already have an account?
Sign in to comment
Add this suggestion to a batch that can be applied as a single commit.This suggestion is invalid because no changes were made to the code.Suggestions cannot be applied while the pull request is closed.Suggestions cannot be applied while viewing a subset of changes.Only one suggestion per line can be applied in a batch.Add this suggestion to a batch that can be applied as a single commit.Applying suggestions on deleted lines is not supported.You must change the existing code in this line in order to create a valid suggestion.Outdated suggestions cannot be applied.This suggestion has been applied or marked resolved.Suggestions cannot be applied from pending reviews.Suggestions cannot be applied on multi-line comments.Suggestions cannot be applied while the pull request is queued to merge.Suggestion cannot be applied right now. Please check back later.
Three fixes from a triage of every
internal/endtoendreplay case that passes as committed but fails underSQLCEXPERIMENT=coreanalyzer. Together they take the core context from 347 failing cases to 281, with no case regressing and the base context still fully green. Each commit stands on its own.Enums absent from models (50 cases, 45 fixed)
The core catalog created an enum type on
CREATE TYPE ... AS ENUMbut kept none of its labels, and the dump that hands the catalog to codegen carried relations only. Every enum was missing frommodels.go, PostgreSQL enum columns were typedanyand MySQL ENUM columnsstring.sql_enum_labelstores an enum's labels, modeled onpg_enum.ALTER TYPE ADD VALUE(withBEFORE/AFTERandIF NOT EXISTS),RENAME VALUE,RENAME TO,SET SCHEMAandDROP TYPE.<table>_<column>as the legacy catalog names it. It follows the column and the table through renames, is replaced onMODIFY, and goes with a dropped column or table.TypeNameitself and drop a spelled-outpublic., sofoo.moodandDROP TYPE public.statusresolve the way their column references do.The five leftovers are blocked by other buckets (
varchartypedany, MySQL BOOLEAN,sqlc.embed).Views absent from models (10 cases, 8 fixed)
The catalog dump listed kind
rrelations only, so views, materialized views andCREATE TABLE AShad no model, and a query selecting all of one got a row struct of its own. The listing now covers the relations a query selects rows from the same way. The two leftovers are the anonymous-column naming bucket (SELECT 1as a view) andCREATE SCHEMA.Placeholders the analyzer walked past (17 cases, 14 fixed)
INSERT ... SELECT: the engines report the source query with an empty VALUES list rather than none, so the analyzer took the VALUES branch and walked nothing. A placeholder selected directly now takes the type of the column it lands in.LIMITonUPDATE,DELETE, and onUNION/INTERSECT/EXCEPTwas never looked at.ON DUPLICATE KEY UPDATEassignments bind the waySETdoes.x IN (SELECT ...)on MySQL arrives wrapped in a sublink, which the IN node now looks through.x COLLATE c: SQLite puts the expression in the node's other field, so the placeholder underneath was neither found nor typed.CALL: the compiler now sends it through the core,CREATE PROCEDUREis recorded with a void pseudo type as its result, and a call types each placeholder from the declared parameter, by position or byname =>. The AST gainsIsProcedure, set by both parsers, since a function with only OUT parameters also declares no return type.The three leftovers are MySQL BOOLEAN and LIMIT parameter naming. I tried naming
LIMIT/OFFSETplaceholders in the core and backed it out: it changedanalyzeoutput for SQLite and ClickHouse, where the database reports no name, so that convention belongs in the compiler bridge rather than the analysis.Notes for review
sqlc analyzewith the synthetic<table>_<column>type name rather thanenum. That is what codegen needs and what the legacy compiler always did, but it is not what MySQL itself reports. goldeneye has no MySQL analyze check today.TestReplay/base(all green) andSQLC_TEST_CORE=1 TestReplay/core(347 → 281) before and after each commit.internal/core/catalogdbis regenerated from the catalog schema and query changes.🤖 Generated with Claude Code
https://claude.ai/code/session_01XZcKb4GFiZQbeo9oVmyF3m