11package compiler
22
33import (
4- "fmt"
54 "sort"
65
76 analyzer "github.com/sqlc-dev/sqlc/internal/analysis"
87 "github.com/sqlc-dev/sqlc/internal/config"
9- "github.com/sqlc-dev/sqlc/internal/engine/postgresql"
108 "github.com/sqlc-dev/sqlc/internal/source"
119 "github.com/sqlc-dev/sqlc/internal/sql/ast"
1210 "github.com/sqlc-dev/sqlc/internal/sql/named"
@@ -189,7 +187,7 @@ func (c *Compiler) _analyzeQuery(raw *ast.RawStmt, query string, failfast bool)
189187 return nil , err
190188 }
191189 if n , ok := raw .Stmt .(* ast.InsertStmt ); ok {
192- if err := check (c .validateOnConflictClause (n , params )); err != nil {
190+ if err := check (c .validateOnConflictClause (n )); err != nil {
193191 return nil , err
194192 }
195193 }
@@ -227,34 +225,35 @@ func (c *Compiler) _analyzeQuery(raw *ast.RawStmt, query string, failfast bool)
227225// - ON CONFLICT (col, ...) conflict target columns exist
228226// - DO UPDATE SET col = ... assignment target columns exist
229227// - EXCLUDED.col references exist
230- // - For PostgreSQL: $N param and EXCLUDED.col type compatibility with SET target
231- func (c * Compiler ) validateOnConflictClause (n * ast.InsertStmt , params []Parameter ) error {
228+ func (c * Compiler ) validateOnConflictClause (n * ast.InsertStmt ) error {
232229 if n .OnConflictClause == nil || n .OnConflictClause .Action != ast .OnConflictActionUpdate {
233230 return nil
234231 }
232+
235233 fqn , err := ParseTableName (n .Relation )
236234 if err != nil {
237235 return err
238236 }
237+
239238 table , err := c .catalog .GetTable (fqn )
240239 if err != nil {
241240 return err
242241 }
243242
244- // Build column name → DataType from catalog for existence and type checks.
245- colDataTypes := make (map [string ]string , len (table .Columns ))
243+ // Build set of column names for existence checks.
244+ colNames := make (map [string ]struct {} , len (table .Columns ))
246245 for _ , col := range table .Columns {
247- colDataTypes [col .Name ] = dataType ( & col . Type )
246+ colNames [col .Name ] = struct {}{}
248247 }
249248
250249 // Validate ON CONFLICT (col, ...) conflict target columns.
251- if n .OnConflictClause .Infer != nil {
250+ if n .OnConflictClause .Infer != nil && n . OnConflictClause . Infer . IndexElems != nil {
252251 for _ , item := range n .OnConflictClause .Infer .IndexElems .Items {
253252 elem , ok := item .(* ast.IndexElem )
254253 if ! ok || elem .Name == nil {
255254 continue
256255 }
257- if _ , exists := colDataTypes [* elem .Name ]; ! exists {
256+ if _ , exists := colNames [* elem .Name ]; ! exists {
258257 e := sqlerr .ColumnNotFound (table .Rel .Name , * elem .Name )
259258 e .Location = n .OnConflictClause .Infer .Location
260259 return e
@@ -263,89 +262,29 @@ func (c *Compiler) validateOnConflictClause(n *ast.InsertStmt, params []Paramete
263262 }
264263
265264 // Validate DO UPDATE SET col = ... assignment target columns and EXCLUDED.col references.
265+ if n .OnConflictClause .TargetList == nil {
266+ return nil
267+ }
266268 for _ , item := range n .OnConflictClause .TargetList .Items {
267269 target , ok := item .(* ast.ResTarget )
268270 if ! ok || target .Name == nil {
269271 continue
270272 }
271- if _ , exists := colDataTypes [* target .Name ]; ! exists {
273+ if _ , exists := colNames [* target .Name ]; ! exists {
272274 e := sqlerr .ColumnNotFound (table .Rel .Name , * target .Name )
273275 e .Location = target .Location
274276 return e
275277 }
276278 if ref , ok := target .Val .(* ast.ColumnRef ); ok {
277279 if excludedCol , ok := excludedColumn (ref ); ok {
278- if _ , exists := colDataTypes [excludedCol ]; ! exists {
280+ if _ , exists := colNames [excludedCol ]; ! exists {
279281 e := sqlerr .ColumnNotFound (table .Rel .Name , excludedCol )
280282 e .Location = ref .Location
281283 return e
282284 }
283285 }
284286 }
285287 }
286-
287- // Type compatibility checks (PostgreSQL only).
288- // To remove type checking: delete this block and validateOnConflictSetTypes.
289- if c .conf .Engine == config .EnginePostgreSQL {
290- if err := c .validateOnConflictSetTypes (n , params , colDataTypes ); err != nil {
291- return err
292- }
293- }
294-
295- return nil
296- }
297-
298- // validateOnConflictSetTypes checks that values in DO UPDATE SET assignments
299- // are type-compatible with their target columns (PostgreSQL only).
300- // It handles $N params (typed from INSERT VALUES) and EXCLUDED.col references.
301- func (c * Compiler ) validateOnConflictSetTypes (n * ast.InsertStmt , params []Parameter , colDataTypes map [string ]string ) error {
302- // Build param number → resolved DataType from already-resolved params.
303- // Skips params with "any" type (unresolved).
304- paramDataTypes := make (map [int ]string , len (params ))
305- for i := range params {
306- if params [i ].Column != nil && params [i ].Column .DataType != "any" {
307- paramDataTypes [params [i ].Number ] = params [i ].Column .DataType
308- }
309- }
310-
311- for _ , item := range n .OnConflictClause .TargetList .Items {
312- target , ok := item .(* ast.ResTarget )
313- if ! ok || target .Name == nil {
314- continue
315- }
316- colDT , ok := colDataTypes [* target .Name ]
317- if ! ok {
318- continue
319- }
320- switch val := target .Val .(type ) {
321- case * ast.ParamRef :
322- paramDT , ok := paramDataTypes [val .Number ]
323- if ! ok {
324- continue
325- }
326- if postgresql .TypeFamily (paramDT ) != postgresql .TypeFamily (colDT ) {
327- return & sqlerr.Error {
328- Message : fmt .Sprintf ("parameter $%d has type %q but column %q has type %q" , val .Number , paramDT , * target .Name , colDT ),
329- Location : val .Location ,
330- }
331- }
332- case * ast.ColumnRef :
333- excludedCol , ok := excludedColumn (val )
334- if ! ok {
335- continue
336- }
337- excludedDT , ok := colDataTypes [excludedCol ]
338- if ! ok {
339- continue
340- }
341- if postgresql .TypeFamily (excludedDT ) != postgresql .TypeFamily (colDT ) {
342- return & sqlerr.Error {
343- Message : fmt .Sprintf ("EXCLUDED.%s has type %q but column %q has type %q" , excludedCol , excludedDT , * target .Name , colDT ),
344- Location : val .Location ,
345- }
346- }
347- }
348- }
349288 return nil
350289}
351290
0 commit comments