Description
rowid resolves in a WHERE clause but not in a result list:
SELECT rowid, v FROM t -> cannot compile statement: unknown column "rowid"
UPDATE t SET v = ? WHERE rowid = 1 -> works
DELETE FROM t WHERE rowid = 1 -> works
So the compiler knows what rowid means in one expression position and not in
another. is_rowid_reference (src/codegen/stmt/update.rs, and the
equivalent in delete.rs) special-cases it for the seek path, but
Scope::resolve — which every projection column goes through — has no
knowledge of it and reports it as an unknown column.
_rowid_ and oid, SQLite's other two spellings, are presumably in the same
position.
Why it matters
Reported by the SQE consumer. It was the obvious workaround for the
bind-ordering defect (fixed separately): read the rowid, then address the row
by it with a single parameter. Not being able to select it closed that door.
More generally a consumer cannot round-trip a row it just inserted —
last_insert_rowid() gives the value, but nothing can read it back alongside
the row's columns, so "insert then fetch what I inserted" needs a unique key
the table may not have.
Scope
Scope::resolve learns rowid/_rowid_/oid as a pseudo-column on a
rowid table, compiling to the cursor's rowid rather than a record field.
- The SQLite shadowing rule applies and must be respected: if the table
declares a real column with that name, the declared column wins. INTEGER PRIMARY KEY is the reverse case — the declared column is the rowid, which
the schema layer already tracks as a rowid alias.
WITHOUT ROWID tables must report the same error stock sqlite3 does, not
silently produce a number.
Non-goals
- Writing to
rowid in an UPDATE ... SET rowid = ... (SQLite allows it;
nothing has asked and it interacts with index maintenance).
SELECT * expanding to include rowid — it does not in SQLite either.
Acceptance Criteria
Complexity
Estimate: small-medium
Reasoning: One resolver gains one pseudo-column, and the cursor already
knows its rowid, so there is no new opcode. The care is entirely in the
shadowing rules — declared column wins, INTEGER PRIMARY KEY is the alias,
WITHOUT ROWID has none — and each of those is an oracle-diffable case rather
than a judgement call.
Refs: 013/Req-3, #705
Description
rowidresolves in aWHEREclause but not in a result list:So the compiler knows what
rowidmeans in one expression position and not inanother.
is_rowid_reference(src/codegen/stmt/update.rs, and theequivalent in
delete.rs) special-cases it for the seek path, butScope::resolve— which every projection column goes through — has noknowledge of it and reports it as an unknown column.
_rowid_andoid, SQLite's other two spellings, are presumably in the sameposition.
Why it matters
Reported by the SQE consumer. It was the obvious workaround for the
bind-ordering defect (fixed separately): read the rowid, then address the row
by it with a single parameter. Not being able to select it closed that door.
More generally a consumer cannot round-trip a row it just inserted —
last_insert_rowid()gives the value, but nothing can read it back alongsidethe row's columns, so "insert then fetch what I inserted" needs a unique key
the table may not have.
Scope
Scope::resolvelearnsrowid/_rowid_/oidas a pseudo-column on arowid table, compiling to the cursor's rowid rather than a record field.
declares a real column with that name, the declared column wins.
INTEGER PRIMARY KEYis the reverse case — the declared column is the rowid, whichthe schema layer already tracks as a rowid alias.
WITHOUT ROWIDtables must report the same error stock sqlite3 does, notsilently produce a number.
Non-goals
rowidin anUPDATE ... SET rowid = ...(SQLite allows it;nothing has asked and it interacts with index maintenance).
SELECT *expanding to includerowid— it does not in SQLite either.Acceptance Criteria
SELECT rowid, <cols> FROM tmatches the pinned 3.53.4 oracle row forrow, including after deletes have left gaps in the sequence
_rowid_andoidbehave identicallyrowidresolves to the declaredcolumn, matching the oracle
INTEGER PRIMARY KEYtable,rowidand the alias column agreeWITHOUT ROWIDtable the error matches the oracle'srowidworks inWHERE,ORDER BYand a projection in the samestatement
Complexity
Estimate: small-medium
Reasoning: One resolver gains one pseudo-column, and the cursor already
knows its rowid, so there is no new opcode. The care is entirely in the
shadowing rules — declared column wins,
INTEGER PRIMARY KEYis the alias,WITHOUT ROWIDhas none — and each of those is an oracle-diffable case ratherthan a judgement call.
Refs: 013/Req-3, #705