Description
Row::get_by_name only works on single-table selects. For a join or a
compound, result_column_names yields positional placeholders:
SELECT a.x, b.y FROM a JOIN b ON ... -> column names: ["column1", "column2"]
SELECT x FROM a UNION SELECT y FROM b -> column names: ["column1"]
So get_by_name("x") fails with ColumnNotFound on exactly the queries where
positional access is hardest to get right — the ones with columns from more
than one source.
Spec 013 Requirement 3 currently scopes around this ("by-name access is
scoped to single-table selects") rather than treating it as a defect, which
was the honest thing to do while shipping but is not where it should stay.
What the names should be
SQLite's rule, as .headers on prints it: the alias if there is one,
otherwise the column name for a bare column reference, otherwise the
expression text. For a compound, the names come from the left-most arm.
That is the behaviour to diff against, and it is fully specified by the oracle
rather than by preference.
Why it matters
Requirement 6's own acceptance list for the embedding API includes a UNION,
so the spec contradicts itself slightly today: the acceptance workload
contains a query shape whose columns cannot be addressed by name.
The SQE consumer's current statements are all single-table, so this is not
blocking them — but it will bite the first join they add, and "use positional
access on joins, names elsewhere" is not a rule an API should ask a consumer
to remember.
Scope
result_column_names derives real names for joins and compounds.
- Qualified forms: SQLite reports
x for SELECT a.x, not a.x. Match it.
- Duplicate names are legal and must stay positional-addressable —
SELECT a.x, b.x yields two columns both named x, and get_by_name
should resolve to the first, as sqlite3_column_name does.
Non-goals
PRAGMA full_column_names / short_column_names (legacy, V7).
- Changing
get(index), which is correct today.
Acceptance Criteria
Complexity
Estimate: medium
Reasoning: The rule is fully specified by the oracle, so there is no design
question, and a corpus diff over a handful of shapes is the whole test. The
work is that result_column_names sits after the point where a join's
per-source schemas are still distinguishable, so the naming may need to be
derived earlier in the pipeline and threaded through rather than recovered
afterwards.
Refs: 013/Req-3, 013/Req-6, #705
Description
Row::get_by_nameonly works on single-table selects. For a join or acompound,
result_column_namesyields positional placeholders:So
get_by_name("x")fails withColumnNotFoundon exactly the queries wherepositional access is hardest to get right — the ones with columns from more
than one source.
Spec 013 Requirement 3 currently scopes around this ("by-name access is
scoped to single-table selects") rather than treating it as a defect, which
was the honest thing to do while shipping but is not where it should stay.
What the names should be
SQLite's rule, as
.headers onprints it: the alias if there is one,otherwise the column name for a bare column reference, otherwise the
expression text. For a compound, the names come from the left-most arm.
That is the behaviour to diff against, and it is fully specified by the oracle
rather than by preference.
Why it matters
Requirement 6's own acceptance list for the embedding API includes a
UNION,so the spec contradicts itself slightly today: the acceptance workload
contains a query shape whose columns cannot be addressed by name.
The SQE consumer's current statements are all single-table, so this is not
blocking them — but it will bite the first join they add, and "use positional
access on joins, names elsewhere" is not a rule an API should ask a consumer
to remember.
Scope
result_column_namesderives real names for joins and compounds.xforSELECT a.x, nota.x. Match it.SELECT a.x, b.xyields two columns both namedx, andget_by_nameshould resolve to the first, as
sqlite3_column_namedoes.Non-goals
PRAGMA full_column_names/short_column_names(legacy, V7).get(index), which is correct today.Acceptance Criteria
UNION, aUNION ALLand a subquery-in-FROM all match whatsqlite3 -headerprints for the same statementSELECT a.x AS renamedreportsrenamedSELECT a.xreportsx, nota.xSELECT a.x, b.xyields two columns namedxandget_by_name("x")resolves to the first
tests/unit/api_statement_test.rs::joins_and_compounds_report_positional_column_names— which currently asserts the defect — is inverted
Complexity
Estimate: medium
Reasoning: The rule is fully specified by the oracle, so there is no design
question, and a corpus diff over a handful of shapes is the whole test. The
work is that
result_column_namessits after the point where a join'sper-source schemas are still distinguishable, so the naming may need to be
derived earlier in the pipeline and threaded through rather than recovered
afterwards.
Refs: 013/Req-3, 013/Req-6, #705