GeezerVison is showing github.com — core: carry enums, views and missing placeholders through the analysis core by kyleconroy · Pull Request #4614 · sqlc-dev/sqlc
Conversation
kyleconroy
commented
Sep 9, 2026
•
edited
Loading
Uh oh!
There was an error while loading. Please reload this page.
Three fixes from a triage of every internal/endtoend replay case that passes as committed but fails under SQLCEXPERIMENT=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 ENUM but kept none of its labels, and the dump that hands the catalog to codegen carried relations only. Every enum was missing from models.go, PostgreSQL enum columns were typed any and MySQL ENUM columns string.
sql_enum_label stores an enum's labels, modeled on pg_enum.
- The schema package applies
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.
- Type names keep the schema an engine reports on the
TypeName itself and drop a spelled-out public., so foo.mood and DROP TYPE public.status resolve the way their column references do.
The five leftovers are blocked by other buckets (varchar typed any, MySQL BOOLEAN, sqlc.embed).
Views absent from models (10 cases, 8 fixed)
The catalog dump listed kind r relations only, so views, materialized views and CREATE TABLE AS had 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 1 as a view) and CREATE 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.
LIMIT on UPDATE, DELETE, and on UNION/INTERSECT/EXCEPT was never looked at.
ON DUPLICATE KEY UPDATE assignments bind the way SET does.
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 PROCEDURE is recorded with a void pseudo type as its result, and a call types each placeholder from the declared parameter, by position or by name =>. The AST gains IsProcedure, set by both parsers, 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 three leftovers are MySQL BOOLEAN and LIMIT parameter naming. I tried naming LIMIT/OFFSET placeholders in the core and backed it out: it changed analyze output 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
- One judgement call: a MySQL ENUM column is now reported by
sqlc analyze with the synthetic <table>_<column> type name rather than enum. 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.
- No test cases were added; the existing corpus covers the changes. Verified by running
TestReplay/base (all green) and SQLC_TEST_CORE=1 TestReplay/core (347 → 281) before and after each commit.
internal/core/catalogdb is regenerated from the catalog schema and query changes.
🤖 Generated with Claude Code
https://claude.ai/code/session_01XZcKb4GFiZQbeo9oVmyF3m
Sorry, something went wrong.
Uh oh!
There was an error while loading. Please reload this page.
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 <[email protected]>
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 <[email protected]>
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 <[email protected]>
Claude-Session: https://claude.ai/code/session_01XZcKb4GFiZQbeo9oVmyF3m
kyleconroy
changed the title
core: carry enums, unsigned, views and missing placeholders through the analysis core
core: carry enums, views and missing placeholders through the analysis core
Sep 9, 2026
Uh oh!
There was an error while loading. Please reload this page.
Assignees
No one assigned
Milestone
No milestone
Development
Successfully merging this pull request may close these issues.
Uh oh!
There was an error while loading. Please reload this page.
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.
|