Skip to content

fix(core): resolve a struct field through its column - #4661

Open
xen0l wants to merge 1 commit into
sqlc-dev:mainfrom
xen0l:duckdb-struct-field
Open

xen0l wants to merge 1 commit into
sqlc-dev:mainfrom
xen0l:duckdb-struct-field

Conversation

@xen0l

@xen0l xen0l commented Oct 24, 2026

Copy link
Copy Markdown

Fixes #4655

Problem

typeColumnRef read only the first two parts of a column reference.

  • For i.info.label it resolved the column info and dropped label, so the result had the type of the whole struct.
  • For info.label it looked for a relation named info, found none, and reported an unknown column.

Change

  • Keep the parts after relation.column as a field path.
  • If the first part is not a relation, resolve it as a column and use the rest as the field path.
  • Walk the path through the struct's TypeExpr (structField). A field is nullable and has no source column. A field name is matched without regard to case. An unknown field is an error.

Tests

New end-to-end case: duckdb_struct_field/duckdb (sqlc generate, output committed). It covers info.label, i.info.label, a parameter compared with a field, and a field name in a different case. The case fails without the change (unknown column "info"."label") and passes with it.

go test ./internal/endtoend -run TestReplay/base: 971 pass, 58 skip, 0 fail before; 972 pass, 58 skip, 0 fail after. The only difference is the new case.
go test ./internal/engine/... ./internal/core/... ./internal/compiler/... ./internal/codegen/... ./internal/cmd/... ./internal/metadata/... ./internal/sql/...: all ok.

I also ran the generated Go on DuckDB v1.5.6 (duckdb-go/v2 v2.10506.0). Each query returned the right rows, and a row whose struct is NULL scans as an invalid sql.NullString.

Not run: the managed-db context, --tags=examples, and the internal/goldeneye checks. They need databases or a DuckDB CLI.

Not changed

struct_extract(info, 'label') is still typed as struct, and info['label'] is still untyped. They go through function and subscript typing.
The check is Name == "struct", so a struct column of another engine that uses the core analyzer takes the same path. The existing suite shows no change for them.

typeColumnRef read only the first two parts of a column reference. For
i.info.label it resolved the column info and dropped label, so the result
had the type of the whole struct. For info.label it looked for a relation
named info and reported an unknown column.

Resolve the first part as a column when it is not a relation, then walk
the remaining parts as fields of the column's struct type. A field is
nullable and has no source column. An unknown field is an error.

Adds the duckdb_struct_field end-to-end case.
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.

duckdb: col.field of a STRUCT column does not resolve, and alias.col.field is typed as the whole struct

1 participant