Skip to content

Column names in ON CONFLICT DO UPDATE SET clause not validated #4291

@nikolayk812

Description

@nikolayk812

Version

1.30.0

What happened?

Bug: sqlc does not validate column names in ON CONFLICT DO UPDATE SET clause

Description

sqlc fails to validate column names in ON CONFLICT ... DO UPDATE SET clauses against the table schema. This allows invalid queries to be generated that will only fail at runtime when executed against the database.

Steps to Reproduce

  1. Create a schema file (migrations/schema.sql):
CREATE TABLE IF NOT EXISTS cart_items
(
    owner_id       VARCHAR(255)                        NOT NULL,
    product_id     UUID                                NOT NULL,
    price_amount   DECIMAL                             NOT NULL,
    price_currency VARCHAR(3)                          NOT NULL,
    created_at     TIMESTAMP DEFAULT CURRENT_TIMESTAMP NOT NULL,
    PRIMARY KEY (owner_id, product_id)
);

CREATE INDEX idx_cart_items_owner ON cart_items (owner_id);

2. Create a query file (query.sql) with an invalid column name in the SET clause:
-- name: AddItem :exec
INSERT INTO cart_items (owner_id, product_id, price_amount, price_currency)
VALUES ($1, $2, $3, $4)
ON CONFLICT (owner_id, product_id) DO UPDATE
    SET price_amount1 = EXCLUDED.price_amount1, price_currency = EXCLUDED.price_currency;

Note: The column is price_amount (exists), but the query references price_amount1 (does not exist)

3. Create sqlc.yaml:
version: "2"
sql:
  - engine: "postgresql"
    schema: "migrations/schema.sql"
    queries: "query.sql"
    gen:
      go:
        package: "querytest"
        out: "generated"

4. Run sqlc generate

Expected Behavior

sqlc should report an error similar to:
query.sql:5:15: column "price_amount1" of relation "cart_items" does not exist

This matches the behavior when running the same query through PostgreSQL directly.

Actual Behavior

sqlc generates code successfully without any errors, embedding the invalid SQL:
const addItem = `... SET price_amount1 = EXCLUDED.price_amount1 ...`

The generated Go code compiles successfully, but the query will fail at runtime with a database error.

Root Cause

sqlc does not validate column names in ON CONFLICT ... DO UPDATE SET clauses against the table schema. The validation code path is missing:

- OnConflictClause is parsed correctly by the PostgreSQL engine
- But it's never validated in the compiler phase
- Column validation happens in internal/compiler/output_columns.go for SELECT/WHERE clauses, but not for ON CONFLICT clauses
- The validate.InsertStmt() function in internal/sql/validate/insert_stmt.go only validates column count vs value count, not SET clause columns

Files Affected

- internal/compiler/analyze.go - No validation for ON CONFLICT
- internal/sql/validate/insert_stmt.go - Missing ON CONFLICT SET column validation
- internal/compiler/output_columns.go - Missing ON CONFLICT SET clause handling

Workaround

Until this is fixed, ensure column names in ON CONFLICT DO UPDATE SET clauses are manually verified against the schema.

Environment

- sqlc version: v1.30.0 (confirmed on latest main)
- Database engine: PostgreSQL
- Go version: 1.25.0+

### Relevant log output

```shell

Database schema

SQL queries

Configuration

Playground URL

No response

What operating system are you using?

macOS

What database engines are you using?

PostgreSQL

What type of code are you generating?

Go

Metadata

Metadata

Assignees

No one assigned

    Type

    No type

    Projects

    No projects

    Milestone

    No milestone

    Relationships

    None yet

    Development

    No branches or pull requests

    Issue actions