Skip to content

Commit 58ebe27

Browse files
committed
fix: handle named params in SQLite upsert ON CONFLICT DO UPDATE SET
The convertInsert_stmtContext function was not converting the upsert clause, leaving @param and sqlc.arg()/sqlc.narg() references unrewritten in ON CONFLICT DO UPDATE SET assignments. Add convertUpsert_clauseContext to properly build the OnConflictClause AST node, including: - Infer clause from ON CONFLICT (col, ...) target columns - TargetList with properly converted param expressions - Optional WHERE clause support - DO NOTHING support Fixes #3508
1 parent 054bc91 commit 58ebe27

7 files changed

Lines changed: 175 additions & 0 deletions

File tree

internal/endtoend/testdata/upsert_named_params/sqlite/go/db.go

Lines changed: 31 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/upsert_named_params/sqlite/go/models.go

Lines changed: 15 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.

internal/endtoend/testdata/upsert_named_params/sqlite/go/query.sql.go

Lines changed: 39 additions & 0 deletions
Some generated files are not rendered by default. Learn more about customizing how changed files appear on GitHub.
Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,13 @@
1+
-- name: UpsertAuthor :one
2+
INSERT INTO authors (
3+
id,
4+
name,
5+
bio
6+
) VALUES (
7+
@id,
8+
@name,
9+
sqlc.narg('bio')
10+
) ON CONFLICT(id) DO UPDATE SET
11+
name = @name,
12+
bio = sqlc.narg('bio')
13+
RETURNING *;
Lines changed: 5 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,5 @@
1+
CREATE TABLE authors (
2+
id text primary key,
3+
name text not null,
4+
bio text
5+
);
Lines changed: 12 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,12 @@
1+
{
2+
"version": "1",
3+
"packages": [
4+
{
5+
"engine": "sqlite",
6+
"path": "go",
7+
"name": "querytest",
8+
"schema": "schema.sql",
9+
"queries": "query.sql"
10+
}
11+
]
12+
}

internal/engine/sqlite/convert.go

Lines changed: 60 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1031,9 +1031,69 @@ func (c *cc) convertInsert_stmtContext(n *parser.Insert_stmtContext) ast.Node {
10311031
}
10321032
}
10331033

1034+
insert.OnConflictClause = c.convertUpsert_clauseContext(n.Upsert_clause())
1035+
10341036
return insert
10351037
}
10361038

1039+
func (c *cc) convertUpsert_clauseContext(n parser.IUpsert_clauseContext) *ast.OnConflictClause {
1040+
if n == nil {
1041+
return nil
1042+
}
1043+
1044+
// ON CONFLICT DO NOTHING
1045+
if n.NOTHING_() != nil {
1046+
return &ast.OnConflictClause{
1047+
Action: ast.OnConflictActionNothing,
1048+
}
1049+
}
1050+
1051+
// Build Infer clause from ON CONFLICT (col, ...) target columns
1052+
var infer *ast.InferClause
1053+
indexCols := n.AllIndexed_column()
1054+
if len(indexCols) > 0 {
1055+
indexElems := &ast.List{}
1056+
for _, col := range indexCols {
1057+
name := identifier(col.GetText())
1058+
indexElems.Items = append(indexElems.Items, &ast.IndexElem{
1059+
Name: &name,
1060+
})
1061+
}
1062+
infer = &ast.InferClause{
1063+
IndexElems: indexElems,
1064+
}
1065+
}
1066+
1067+
// Build DO UPDATE SET col = expr target list
1068+
targetList := &ast.List{}
1069+
cols := n.AllColumn_name()
1070+
exprs := n.AllExpr()
1071+
for i, col := range cols {
1072+
if i >= len(exprs) {
1073+
break
1074+
}
1075+
colName := identifier(col.GetText())
1076+
target := &ast.ResTarget{
1077+
Name: &colName,
1078+
Val: c.convert(exprs[i]),
1079+
}
1080+
targetList.Items = append(targetList.Items, target)
1081+
}
1082+
1083+
// Handle optional WHERE clause
1084+
var whereClause ast.Node
1085+
if n.WHERE_(0) != nil && len(exprs) > len(cols) {
1086+
whereClause = c.convert(exprs[len(exprs)-1])
1087+
}
1088+
1089+
return &ast.OnConflictClause{
1090+
Action: ast.OnConflictActionUpdate,
1091+
Infer: infer,
1092+
TargetList: targetList,
1093+
WhereClause: whereClause,
1094+
}
1095+
}
1096+
10371097
func (c *cc) convertColumnNames(cols []parser.IColumn_nameContext) *ast.List {
10381098
list := &ast.List{Items: []ast.Node{}}
10391099
for _, c := range cols {

0 commit comments

Comments
 (0)