@@ -594,6 +594,10 @@ extension StmtTypeChecker {
594594 if !skipInputUnification {
595595 inferenceState. unify ( inputType, with: resultColumns. type, at: insert. location)
596596 }
597+
598+ if let upsertClause = values. upsertClause {
599+ typeCheck ( upsertClause: upsertClause, table: table)
600+ }
597601 } else {
598602 // TODO: Using 'DEFALUT VALUES' make sure all columns
599603 // TODO: actually have default values or null
@@ -608,6 +612,55 @@ extension StmtTypeChecker {
608612 return resultColumns
609613 }
610614
615+ mutating func typeCheck( upsertClause: UpsertClauseSyntax , table: Table ) {
616+ if let conflictTarget = upsertClause. confictTarget {
617+ // Make sure all columns exist
618+ for column in conflictTarget. columns {
619+ guard let name = column. columnName,
620+ table. columns [ name. value] . isEmpty else { continue }
621+ diagnostics. add ( . columnDoesNotExist( name) )
622+ }
623+ }
624+
625+ // In new env since we are inserting excluded
626+ inNewEnvironment ( extendCurrentEnv: true ) { typeChecker in
627+ // Insert the table aliased to `excluded` to allow access
628+ // like `SET foo = excluded.foo`.
629+ let excluded = table. aliased ( to: " excluded " )
630+ typeChecker. importTable ( excluded)
631+
632+ switch upsertClause. doAction {
633+ case . nothing:
634+ break
635+ case . updateSet( let sets, let `where`) :
636+ for set in sets {
637+ let ( _, name) = typeChecker. typeCheck ( set. expr)
638+
639+ switch set. column {
640+ case . single( let column) :
641+ // Single column being set, suggest the name for the param
642+ // if it is one.
643+ typeChecker. nameInferrer. suggest ( name: column. value, for: name)
644+
645+ if table. columns [ column. value] . isEmpty {
646+ typeChecker. diagnostics. add ( . columnDoesNotExist( column) )
647+ }
648+ case . list( let columns) :
649+ for column in columns {
650+ if table. columns [ column. value] . isEmpty {
651+ typeChecker. diagnostics. add ( . columnDoesNotExist( column) )
652+ }
653+ }
654+ }
655+ }
656+
657+ if let `where` {
658+ _ = typeChecker. typeCheck ( `where`)
659+ }
660+ }
661+ }
662+ }
663+
611664 mutating func typeCheck( update: UpdateStmtSyntax ) -> ResultColumns {
612665 typeCheck ( with: update. with)
613666
@@ -1079,7 +1132,9 @@ extension StmtTypeChecker {
10791132 ) {
10801133 // Insert real name not alias. These are used later for observation tracking
10811134 // so an alias is no good since it will always be the actual table name.
1082- usedTableNames. insert ( table. name. name)
1135+ if table. name. schema == . main {
1136+ usedTableNames. insert ( table. name. name)
1137+ }
10831138
10841139 // Table is always accessible by it's name even if aliased
10851140 env. import (
0 commit comments