Search code examples
sqlpostgresqlgosqlc

Error scanning NULL columns in SQLC generated code with LEFT joins in the query


I have just modified a table in PostgreSQL to be NULLABLE like this:

CREATE TABLE a {
    a_name varchar NOT NULL
    b_id BIGINT <-- was previously NOT NULL with no problems 
}

CREATE TABLE b {
    id BIGSERIAL,
    b_name varchar NOT NULL
}

There is a foreign key constraint on a.b_id > b.id.

I have a number of queries that JOIN these tables and return b.name similar to this:

-- name: List :many
SELECT
   a_name,
   b_name
FROM a
LEFT JOIN b ON b.id = a.bid <-- produces NULL columns in results

The return type from the query for b_name can be NULL due to the LEFT JOIN. Any rows in a.b_id that are NULL will return NULL for b_name. Obvs.

In reality the queries are much more complex with multiple nullable parameters being sent in the WHERE clause but intuitively I am not feeling like this is the problem. Surely SQLC configures its row structs from the SELECT portion of the query...?

SQLC is gererating Row structs similar to this:

type ListRow struct {
   AName string `json:"a_name"'
   BName string `json:"b_name"'
}

BName should be nullable (I am using various gobuffalo nulls overrides in config) but is not in the struct so is causing scan errors along the lines of:

"sql: Scan error on column index 1, name \"b_name\": converting NULL to string is unsupported"

I am clearly missing something obvious in the documentation as this must be a regular operation. I have not had any problems to date using SQLC with fairly complex queries with INNER JOIN tables or have nullable column return types.

Not sure how active the SO community is for SQLC, grateful for any feedback however intuitive or vague.


Solution

  • Suggestion - replace b_name with coalesce(b_name, '** Attention **') in the query in order to see what might be happening.

    SELECT
       a_name,
       coalesce(b_name, '** Attention **')
    FROM a LEFT JOIN b ON b.id = a.bid;
    

    Or or replace it with coalesce(b_name, '') if this is acceptable and makes sense.

    SELECT
       a_name,
       coalesce(b_name, '')
    FROM a LEFT JOIN b ON b.id = a.bid;
    

    Or filter results for which b_name is null

    SELECT a_name, b_name
    FROM a LEFT JOIN b ON b.id = a.bid
    where b_name is not null;