Thanks to visit codestin.com
Credit goes to github.com

Skip to content

PostgreSQL arrays can have NULL items #185

New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

Open
kyleconroy opened this issue Dec 16, 2019 · 2 comments
Open

PostgreSQL arrays can have NULL items #185

kyleconroy opened this issue Dec 16, 2019 · 2 comments
Labels

Comments

@kyleconroy
Copy link
Collaborator

Given the following schema and query:

CREATE TABLE foo (
        id text NOT NULL,
        tags text[]
);

-- name: ListFoo :many
SELECT * FROM foo;

sqlc will generate the following code:

// Code generated by sqlc. DO NOT EDIT.

package main

import (
	"context"
	"database/sql"

	"github.com/lib/pq"
)

type Foo struct {
	ID   sql.NullString
	Tags []string
}

const listFoo = `-- name: ListFoo :many
SELECT id, tags FROM foo
`

func (q *Queries) ListFoo(ctx context.Context) ([]Foo, error) {
	rows, err := q.db.QueryContext(ctx, listFoo)
	if err != nil {
		return nil, err
	}
	defer rows.Close()
	var items []Foo
	for rows.Next() {
		var i Foo
		if err := rows.Scan(&i.ID, pq.Array(&i.Tags)); err != nil {
			return nil, err
		}
		items = append(items, i)
	}
	if err := rows.Close(); err != nil {
		return nil, err
	}
	if err := rows.Err(); err != nil {
		return nil, err
	}
	return items, nil
}

type DBTX interface {
	ExecContext(context.Context, string, ...interface{}) (sql.Result, error)
	PrepareContext(context.Context, string) (*sql.Stmt, error)
	QueryContext(context.Context, string, ...interface{}) (*sql.Rows, error)
	QueryRowContext(context.Context, string, ...interface{}) *sql.Row
}

func New(db DBTX) *Queries {
	return &Queries{db: db}
}

type Queries struct {
	db DBTX
}

func (q *Queries) WithTx(tx *sql.Tx) *Queries {
	return &Queries{
		db: tx,
	}
}

With the following two records inserted into the foo table, a call ListFoos succeeds.

INSERT INTO foo (id, tags) VALUES ('one', NULL);
INSERT INTO foo (id, tags) VALUES ('two', array['tag']);

However, if a NULL item exists in the tags array, an error will be returned.

INSERT INTO foo (id, tags) VALUES ('one', array[NULL]);
sql: Scan error on column index 1, name "tags": pq: parsing array element index 0: cannot convert nil to string

That's not a problem, right? We'll just mark the tags column as not null. Sadly, that just means that the column must contain an array value. The array itself can still contain NULL values. It does not appear to be easy to prevent NULL values in arrays. This was the [only solution](Declare a column of type 'not-null-string' array in postgresql - Stack Overflow) I could find, and it's pretty gross.

Note that pq.StringArray also does not support NULL array values.

@kyleconroy kyleconroy added the bug Something isn't working label Dec 16, 2019
@kyleconroy
Copy link
Collaborator Author

A sql.NullString slice, paired with pq.Array works correctly.

type Foo struct {
	ID   sql.NullString
	Tags []sql.NullString
}

@dimmerz92
Copy link

I don't know if this is helpful for anyone. I was also struggling with arrays containing only NULL values.
If you don't need to retain the NULL in your arrays, I found the below to be a decent work around by essentially just omitting NULL values.

This would work for POSTGRES, filtering out NULLs and casting the array type.

SELECT
  e.id,
  e.name,
  e.description,
  e.datetime,
  e.status,
  e.datetime < NOW() AS elapsed,
  ARRAY_AGG(c.id) FILTER (WHERE c.id IS NOT NULL)::int[] AS category_id,
  ARRAY_AGG(c.name) FILTER (WHERE c.id IS NOT NULL)::text[] AS category_name
FROM
  events AS e
  LEFT JOIN category_links AS l ON e.id = l.event_id
  LEFT JOIN categories AS c ON l.category_id = c.id
GROUP BY
  e.id,
  e.name,
  e.description,
  e.datetime,
  e.status;

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
Projects
None yet
Development

No branches or pull requests

2 participants