@@ -7,6 +7,30 @@ import (
77 "github.com/sqlc-dev/sqlc/internal/sql/astutils"
88)
99
10+ // paramRefForAssignment returns the ParamRef assigned to a single UPDATE SET
11+ // target, handling both `col = $1` and the multi-column form
12+ // `(a, b) = ($1, $2)`, where each column is a separate ResTarget carrying a
13+ // MultiAssignRef with its own Colno pointing into a shared RowExpr source.
14+ func paramRefForAssignment (target * ast.ResTarget ) (* ast.ParamRef , bool ) {
15+ switch val := target .Val .(type ) {
16+ case * ast.ParamRef :
17+ return val , true
18+ case * ast.MultiAssignRef :
19+ row , ok := val .Source .(* ast.RowExpr )
20+ if ! ok || row .Args == nil {
21+ return nil , false
22+ }
23+ idx := val .Colno - 1
24+ if idx < 0 || idx >= len (row .Args .Items ) {
25+ return nil , false
26+ }
27+ if ref , ok := row .Args .Items [idx ].(* ast.ParamRef ); ok {
28+ return ref , true
29+ }
30+ }
31+ return nil , false
32+ }
33+
1034func findParameters (root ast.Node ) ([]paramRef , []error ) {
1135 refs := make ([]paramRef , 0 )
1236 errors := make ([]error , 0 )
@@ -110,6 +134,66 @@ func (p paramSearch) Visit(node ast.Node) astutils.Visitor {
110134 }
111135 }
112136
137+ case * ast.MergeStmt :
138+ if n .MergeWhenClauses == nil {
139+ break
140+ }
141+ for _ , item := range n .MergeWhenClauses .Items {
142+ clause , ok := item .(* ast.MergeWhenClause )
143+ if ! ok {
144+ continue
145+ }
146+ switch clause .CommandType {
147+ case ast .CmdTypeUpdate :
148+ // WHEN MATCHED THEN UPDATE SET col = $1
149+ if clause .TargetList == nil {
150+ continue
151+ }
152+ for _ , item := range clause .TargetList .Items {
153+ target , ok := item .(* ast.ResTarget )
154+ if ! ok {
155+ continue
156+ }
157+ ref , ok := paramRefForAssignment (target )
158+ if ! ok {
159+ continue
160+ }
161+ * p .refs = append (* p .refs , paramRef {parent : target , ref : ref , rv : n .Relation })
162+ p .seen [ref .Location ] = struct {}{}
163+ }
164+ case ast .CmdTypeInsert :
165+ // WHEN NOT MATCHED THEN INSERT (a, b) VALUES ($1, $2)
166+ if clause .Values == nil {
167+ continue
168+ }
169+ if clause .TargetList == nil || len (clause .TargetList .Items ) == 0 {
170+ // Without an explicit column list sqlc cannot map the
171+ // positional VALUES parameters to target columns.
172+ params := astutils .Search (clause .Values , func (node ast.Node ) bool {
173+ _ , ok := node .(* ast.ParamRef )
174+ return ok
175+ })
176+ if len (params .Items ) > 0 {
177+ * p .errs = append (* p .errs , fmt .Errorf ("MERGE INSERT with parameters requires an explicit column list" ))
178+ return p
179+ }
180+ continue
181+ }
182+ for i , v := range clause .Values .Items {
183+ ref , ok := v .(* ast.ParamRef )
184+ if ! ok {
185+ continue
186+ }
187+ if len (clause .TargetList .Items ) <= i {
188+ * p .errs = append (* p .errs , fmt .Errorf ("MERGE INSERT has more expressions than target columns" ))
189+ return p
190+ }
191+ * p .refs = append (* p .refs , paramRef {parent : clause .TargetList .Items [i ], ref : ref , rv : n .Relation })
192+ p .seen [ref .Location ] = struct {}{}
193+ }
194+ }
195+ }
196+
113197 case * ast.UpdateStmt :
114198 for _ , item := range n .TargetList .Items {
115199 target , ok := item .(* ast.ResTarget )
0 commit comments