Skip to content

fix(sqlite): Keep RETURNING aliases in generated column names - #4682

Open
manuelschoene wants to merge 2 commits into
sqlc-dev:mainfrom
manuelschoene:fix/sqlite-returning-aliases
Open

manuelschoene wants to merge 2 commits into
sqlc-dev:mainfrom
manuelschoene:fix/sqlite-returning-aliases

Conversation

@manuelschoene

Copy link
Copy Markdown

Fixes #4680

On the SQLite engine, aliases in a RETURNING clause were ignored when naming result columns. sqlc named the generated row fields after the underlying column, or ColumnN for an expression:

INSERT INTO t (name, score) VALUES (?, ?)
RETURNING id AS new_id, score * 2 AS doubled;
 type InsertReturningAliasRow struct {
-	ID      int64
-	Column2 int64
+	NewID   int64
+	Doubled int64
 }

SQLite itself reports these columns as new_id and doubled. The bug affected INSERT, INSERT … ON CONFLICT DO UPDATE, UPDATE and DELETE on both analysis paths (default and SQLCEXPERIMENT=coreanalyzer).

Commits

  • fix(sqlite): Keep RETURNING alias as column name
  • test(sqlite): Added RETURNING alias end-to-end test

Cause and fix

convertReturning (internal/engine/sqlite/convert.go) built an ast.ResTarget for each meyer.ResultColumn but only converted Expr, so ResTarget.Name stayed nil. Both analyzers prefer ResTarget.Name when they name an output column: outputColumns in internal/compiler/output_columns.go, and targetName in internal/core/analyzer/projection.go. Without it they fell back to the column name, the function name, or a positional ColumnN / ?column?.

The fix sets Name from col.Alias, the same way convertResultColumns already does for SELECT:

if col.Alias != nil {
	name := identifier(col.Alias)
	target.Name = &name
}

identifier() folds the name the way SQLite resolves it. An unquoted alias is lower-cased, and a quoted alias ("newId", [label]) keeps its spelling. RETURNING aliases now behave exactly like SELECT aliases. All three callers (INSERT, UPDATE, DELETE) share convertReturning, so a single change covers them, and no changes to the compiler or the core analyzer are needed. Columns without an alias are unaffected.

Tests

New end-to-end case internal/endtoend/testdata/returning_alias/sqlite/, one query per variant:

Query Variant Before After
InsertReturningAlias alias on a column and an expression ID, Column2 (core: Column) NewID, Doubled
InsertReturningAliasNoAs alias without AS ID, Column2 NewID, Doubled
InsertReturningQuotedAlias "newId", [label] ID, Name NewId, Label
InsertReturningSingleAlias single column, :one var id int64 var new_id int64
InsertReturningStarAndAlias * plus an alias …, Column5 …, Doubled
InsertReturningSameColumnTwice same column under two aliases ID, ID_2 OldID, RowID
UpsertReturningAlias ON CONFLICT … DO UPDATE … RETURNING ID, Score NewID, Total
UpdateReturningAlias UPDATE, :many ID, Column2 UpdatedID, Previous
DeleteReturningAlias DELETE, function call ID, Upper DeletedID, Shout

What I ran:

  • The quoted-alias query checked against sqlite3 3.54.0, which accepts it. sqlite3 -header on the first query prints the column names new_id|doubled.
  • go test ./internal/endtoend -run 'TestReplay/base/returning_alias': fails on main with the field names shown in the "Before" column, passes with the fix.
  • SQLC_TEST_CORE=1 go test ./internal/endtoend -run 'TestReplay/core/returning_alias': fails on main, passes with the fix. The core path generates byte-identical output to the default path, so a single set of goldens covers both.
  • go test ./internal/endtoend -run 'TestReplay|TestFormat|TestExamplesVet|TestJsonSchema' over the whole corpus: no failures, and no existing golden changes.
  • gofmt -l and go vet ./internal/engine/sqlite: clean.

Not run locally: the managed-db context of TestReplay and TestValidSchema against live PostgreSQL/MySQL, since no database servers were running. This change only touches the SQLite converter.

Note on #4681

#4681 was opened shortly after the issue and proposes the same change. This PR's test case was written before the issue was filed, which is why the issue already refers to it. I'm opening this PR anyway for the fuller write-up above. Feel free to close whichever one you don't need.

@manuelschoene

Copy link
Copy Markdown
Author

Note on the failing CI: The sqlc-test-setup script could not install the libossp-uuid16 dependency. Therefore, no tests could be run.

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.

sqlite: aliases in RETURNING are ignored when naming result columns

1 participant