From 2e83572eb15e43fb4b98f09756f5bb5cfc95efcf Mon Sep 17 00:00:00 2001 From: Dhruv Bhoot Date: Thu, 25 Apr 2024 01:58:37 -0700 Subject: [PATCH 1/2] Fix table inheritance --- .../postgresql/pgx/v4/go/db.go | 32 +++++ .../postgresql/pgx/v4/go/models.go | 95 +++++++++++++++ .../postgresql/pgx/v4/go/query.sql.go | 103 ++++++++++++++++ .../postgresql/pgx/v4/query.sql | 8 ++ .../postgresql/pgx/v4/schema.sql | 33 ++++++ .../postgresql/pgx/v4/sqlc.json | 13 ++ .../postgresql/pgx/v5/go/db.go | 32 +++++ .../postgresql/pgx/v5/go/models.go | 94 +++++++++++++++ .../postgresql/pgx/v5/go/query.sql.go | 103 ++++++++++++++++ .../postgresql/pgx/v5/query.sql | 8 ++ .../postgresql/pgx/v5/schema.sql | 33 ++++++ .../postgresql/pgx/v5/sqlc.json | 13 ++ .../postgresql/stdlib/go/db.go | 31 +++++ .../postgresql/stdlib/go/models.go | 95 +++++++++++++++ .../postgresql/stdlib/go/query.sql.go | 112 ++++++++++++++++++ .../postgresql/stdlib/query.sql | 8 ++ .../postgresql/stdlib/schema.sql | 33 ++++++ .../postgresql/stdlib/sqlc.json | 12 ++ .../postgresql/pgx/v4/go/models.go | 2 +- .../postgresql/pgx/v5/go/models.go | 2 +- .../postgresql/stdlib/go/models.go | 2 +- internal/sql/catalog/table.go | 105 +++++++++++++--- 22 files changed, 950 insertions(+), 19 deletions(-) create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/sqlc.json create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/db.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/models.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/schema.sql create mode 100644 internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/sqlc.json diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/db.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/db.go new file mode 100644 index 0000000000..22d3fba6ba --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 + +package querytest + +import ( + "context" + + "github.com/jackc/pgconn" + "github.com/jackc/pgx/v4" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/models.go new file mode 100644 index 0000000000..30421cdd0a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/models.go @@ -0,0 +1,95 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" + + "github.com/google/uuid" +) + +type PartyRank string + +const ( + PartyRankEnsign PartyRank = "ensign" + PartyRankLieutenant PartyRank = "lieutenant" + PartyRankCommander PartyRank = "commander" + PartyRankCaptain PartyRank = "captain" + PartyRankAdmiral PartyRank = "admiral" +) + +func (e *PartyRank) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PartyRank(s) + case string: + *e = PartyRank(s) + default: + return fmt.Errorf("unsupported scan type for PartyRank: %T", src) + } + return nil +} + +type NullPartyRank struct { + PartyRank PartyRank + Valid bool // Valid is true if PartyRank is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPartyRank) Scan(value interface{}) error { + if value == nil { + ns.PartyRank, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PartyRank.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPartyRank) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PartyRank), nil +} + +type Llc struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + LegalName string + IncorporationDate sql.NullTime + Region sql.NullString +} + +type Organisation struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + LegalName sql.NullString + Region sql.NullString +} + +type Party struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + Region sql.NullString +} + +type Person struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + FirstName string + LastName string + Region sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go new file mode 100644 index 0000000000..fc5f995f36 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go @@ -0,0 +1,103 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAllOrganisations = `-- name: GetAllOrganisations :many +SELECT party_id, name, joined_on, rank, legal_name, region FROM organisation +` + +func (q *Queries) GetAllOrganisations(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.Query(ctx, getAllOrganisations) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.LegalName, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllParties = `-- name: GetAllParties :many +SELECT party_id, name, joined_on, rank, region FROM party +` + +func (q *Queries) GetAllParties(ctx context.Context) ([]Party, error) { + rows, err := q.db.Query(ctx, getAllParties) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Party + for rows.Next() { + var i Party + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllPeople = `-- name: GetAllPeople :many +SELECT party_id, name, joined_on, rank, first_name, last_name, region FROM person +` + +func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { + rows, err := q.db.Query(ctx, getAllPeople) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Person + for rows.Next() { + var i Person + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.FirstName, + &i.LastName, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql new file mode 100644 index 0000000000..30adbd9aa1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql @@ -0,0 +1,8 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllPeople :many +SELECT * FROM person; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/schema.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/schema.sql new file mode 100644 index 0000000000..9a77350b37 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/schema.sql @@ -0,0 +1,33 @@ +CREATE TYPE party_rank AS ENUM('ensign', 'lieutenant', 'commander'); + +CREATE TABLE party ( + party_id uuid PRIMARY KEY, + name text NOT NULL, + joined_on timestamptz NOT NULL, + ronk party_rank, + unnecessary_column text +); + +CREATE TABLE person ( + first_name text NOT NULL, + last_name text NOT NULL +) INHERITS (party); + +CREATE TABLE organisation ( + legal_name text +) INHERITS (party); + +CREATE TABLE llc ( + incorporation_date timestamp, + legal_name text NOT NULL +) INHERITS (organisation); + + +ALTER TABLE party ALTER COLUMN ronk SET NOT NULL; +ALTER TABLE party RENAME COLUMN ronk TO rank; +ALTER TABLE party ALTER COLUMN joined_on DROP NOT NULL; +ALTER TABLE party DROP COLUMN unnecessary_column; +ALTER TABLE party ADD COLUMN region text; + +ALTER TYPE party_rank ADD VALUE 'captain'; +ALTER TYPE party_rank ADD VALUE 'admiral'; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/sqlc.json new file mode 100644 index 0000000000..d1244c9e7a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v4", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/db.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/db.go new file mode 100644 index 0000000000..7c111fd4e7 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/db.go @@ -0,0 +1,32 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 + +package querytest + +import ( + "context" + + "github.com/jackc/pgx/v5" + "github.com/jackc/pgx/v5/pgconn" +) + +type DBTX interface { + Exec(context.Context, string, ...interface{}) (pgconn.CommandTag, error) + Query(context.Context, string, ...interface{}) (pgx.Rows, error) + QueryRow(context.Context, string, ...interface{}) pgx.Row +} + +func New(db DBTX) *Queries { + return &Queries{db: db} +} + +type Queries struct { + db DBTX +} + +func (q *Queries) WithTx(tx pgx.Tx) *Queries { + return &Queries{ + db: tx, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/models.go new file mode 100644 index 0000000000..2b3af63483 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/models.go @@ -0,0 +1,94 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 + +package querytest + +import ( + "database/sql/driver" + "fmt" + + "github.com/jackc/pgx/v5/pgtype" +) + +type PartyRank string + +const ( + PartyRankEnsign PartyRank = "ensign" + PartyRankLieutenant PartyRank = "lieutenant" + PartyRankCommander PartyRank = "commander" + PartyRankCaptain PartyRank = "captain" + PartyRankAdmiral PartyRank = "admiral" +) + +func (e *PartyRank) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PartyRank(s) + case string: + *e = PartyRank(s) + default: + return fmt.Errorf("unsupported scan type for PartyRank: %T", src) + } + return nil +} + +type NullPartyRank struct { + PartyRank PartyRank + Valid bool // Valid is true if PartyRank is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPartyRank) Scan(value interface{}) error { + if value == nil { + ns.PartyRank, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PartyRank.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPartyRank) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PartyRank), nil +} + +type Llc struct { + PartyID pgtype.UUID + Name string + JoinedOn pgtype.Timestamptz + Rank PartyRank + LegalName string + IncorporationDate pgtype.Timestamp + Region pgtype.Text +} + +type Organisation struct { + PartyID pgtype.UUID + Name string + JoinedOn pgtype.Timestamptz + Rank PartyRank + LegalName pgtype.Text + Region pgtype.Text +} + +type Party struct { + PartyID pgtype.UUID + Name string + JoinedOn pgtype.Timestamptz + Rank PartyRank + Region pgtype.Text +} + +type Person struct { + PartyID pgtype.UUID + Name string + JoinedOn pgtype.Timestamptz + Rank PartyRank + FirstName string + LastName string + Region pgtype.Text +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go new file mode 100644 index 0000000000..fc5f995f36 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go @@ -0,0 +1,103 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAllOrganisations = `-- name: GetAllOrganisations :many +SELECT party_id, name, joined_on, rank, legal_name, region FROM organisation +` + +func (q *Queries) GetAllOrganisations(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.Query(ctx, getAllOrganisations) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.LegalName, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllParties = `-- name: GetAllParties :many +SELECT party_id, name, joined_on, rank, region FROM party +` + +func (q *Queries) GetAllParties(ctx context.Context) ([]Party, error) { + rows, err := q.db.Query(ctx, getAllParties) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Party + for rows.Next() { + var i Party + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} + +const getAllPeople = `-- name: GetAllPeople :many +SELECT party_id, name, joined_on, rank, first_name, last_name, region FROM person +` + +func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { + rows, err := q.db.Query(ctx, getAllPeople) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Person + for rows.Next() { + var i Person + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.FirstName, + &i.LastName, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql new file mode 100644 index 0000000000..30adbd9aa1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql @@ -0,0 +1,8 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllPeople :many +SELECT * FROM person; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/schema.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/schema.sql new file mode 100644 index 0000000000..9a77350b37 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/schema.sql @@ -0,0 +1,33 @@ +CREATE TYPE party_rank AS ENUM('ensign', 'lieutenant', 'commander'); + +CREATE TABLE party ( + party_id uuid PRIMARY KEY, + name text NOT NULL, + joined_on timestamptz NOT NULL, + ronk party_rank, + unnecessary_column text +); + +CREATE TABLE person ( + first_name text NOT NULL, + last_name text NOT NULL +) INHERITS (party); + +CREATE TABLE organisation ( + legal_name text +) INHERITS (party); + +CREATE TABLE llc ( + incorporation_date timestamp, + legal_name text NOT NULL +) INHERITS (organisation); + + +ALTER TABLE party ALTER COLUMN ronk SET NOT NULL; +ALTER TABLE party RENAME COLUMN ronk TO rank; +ALTER TABLE party ALTER COLUMN joined_on DROP NOT NULL; +ALTER TABLE party DROP COLUMN unnecessary_column; +ALTER TABLE party ADD COLUMN region text; + +ALTER TYPE party_rank ADD VALUE 'captain'; +ALTER TYPE party_rank ADD VALUE 'admiral'; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/sqlc.json new file mode 100644 index 0000000000..32ede07158 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/sqlc.json @@ -0,0 +1,13 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "sql_package": "pgx/v5", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/db.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/db.go new file mode 100644 index 0000000000..51c2e213bc --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/db.go @@ -0,0 +1,31 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 + +package querytest + +import ( + "context" + "database/sql" +) + +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, + } +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/models.go new file mode 100644 index 0000000000..30421cdd0a --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/models.go @@ -0,0 +1,95 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 + +package querytest + +import ( + "database/sql" + "database/sql/driver" + "fmt" + + "github.com/google/uuid" +) + +type PartyRank string + +const ( + PartyRankEnsign PartyRank = "ensign" + PartyRankLieutenant PartyRank = "lieutenant" + PartyRankCommander PartyRank = "commander" + PartyRankCaptain PartyRank = "captain" + PartyRankAdmiral PartyRank = "admiral" +) + +func (e *PartyRank) Scan(src interface{}) error { + switch s := src.(type) { + case []byte: + *e = PartyRank(s) + case string: + *e = PartyRank(s) + default: + return fmt.Errorf("unsupported scan type for PartyRank: %T", src) + } + return nil +} + +type NullPartyRank struct { + PartyRank PartyRank + Valid bool // Valid is true if PartyRank is not NULL +} + +// Scan implements the Scanner interface. +func (ns *NullPartyRank) Scan(value interface{}) error { + if value == nil { + ns.PartyRank, ns.Valid = "", false + return nil + } + ns.Valid = true + return ns.PartyRank.Scan(value) +} + +// Value implements the driver Valuer interface. +func (ns NullPartyRank) Value() (driver.Value, error) { + if !ns.Valid { + return nil, nil + } + return string(ns.PartyRank), nil +} + +type Llc struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + LegalName string + IncorporationDate sql.NullTime + Region sql.NullString +} + +type Organisation struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + LegalName sql.NullString + Region sql.NullString +} + +type Party struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + Region sql.NullString +} + +type Person struct { + PartyID uuid.UUID + Name string + JoinedOn sql.NullTime + Rank PartyRank + FirstName string + LastName string + Region sql.NullString +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go new file mode 100644 index 0000000000..5cea625d8b --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go @@ -0,0 +1,112 @@ +// Code generated by sqlc. DO NOT EDIT. +// versions: +// sqlc v1.26.0 +// source: query.sql + +package querytest + +import ( + "context" +) + +const getAllOrganisations = `-- name: GetAllOrganisations :many +SELECT party_id, name, joined_on, rank, legal_name, region FROM organisation +` + +func (q *Queries) GetAllOrganisations(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.QueryContext(ctx, getAllOrganisations) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.LegalName, + &i.Region, + ); 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 +} + +const getAllParties = `-- name: GetAllParties :many +SELECT party_id, name, joined_on, rank, region FROM party +` + +func (q *Queries) GetAllParties(ctx context.Context) ([]Party, error) { + rows, err := q.db.QueryContext(ctx, getAllParties) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Party + for rows.Next() { + var i Party + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.Region, + ); 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 +} + +const getAllPeople = `-- name: GetAllPeople :many +SELECT party_id, name, joined_on, rank, first_name, last_name, region FROM person +` + +func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { + rows, err := q.db.QueryContext(ctx, getAllPeople) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Person + for rows.Next() { + var i Person + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.FirstName, + &i.LastName, + &i.Region, + ); 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 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql new file mode 100644 index 0000000000..30adbd9aa1 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql @@ -0,0 +1,8 @@ +-- name: GetAllParties :many +SELECT * FROM party; + +-- name: GetAllPeople :many +SELECT * FROM person; + +-- name: GetAllOrganisations :many +SELECT * FROM organisation; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/schema.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/schema.sql new file mode 100644 index 0000000000..9a77350b37 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/schema.sql @@ -0,0 +1,33 @@ +CREATE TYPE party_rank AS ENUM('ensign', 'lieutenant', 'commander'); + +CREATE TABLE party ( + party_id uuid PRIMARY KEY, + name text NOT NULL, + joined_on timestamptz NOT NULL, + ronk party_rank, + unnecessary_column text +); + +CREATE TABLE person ( + first_name text NOT NULL, + last_name text NOT NULL +) INHERITS (party); + +CREATE TABLE organisation ( + legal_name text +) INHERITS (party); + +CREATE TABLE llc ( + incorporation_date timestamp, + legal_name text NOT NULL +) INHERITS (organisation); + + +ALTER TABLE party ALTER COLUMN ronk SET NOT NULL; +ALTER TABLE party RENAME COLUMN ronk TO rank; +ALTER TABLE party ALTER COLUMN joined_on DROP NOT NULL; +ALTER TABLE party DROP COLUMN unnecessary_column; +ALTER TABLE party ADD COLUMN region text; + +ALTER TYPE party_rank ADD VALUE 'captain'; +ALTER TYPE party_rank ADD VALUE 'admiral'; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/sqlc.json b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/sqlc.json new file mode 100644 index 0000000000..f717ca2e66 --- /dev/null +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/sqlc.json @@ -0,0 +1,12 @@ +{ + "version": "1", + "packages": [ + { + "path": "go", + "engine": "postgresql", + "name": "querytest", + "schema": "schema.sql", + "queries": "query.sql" + } + ] +} diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go index d2f0fff16c..c96981c383 100644 --- a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v4/go/models.go @@ -20,7 +20,7 @@ type Llc struct { type Organisation struct { PartyID uuid.UUID Name string - LegalName string + LegalName sql.NullString } type Party struct { diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go index 6f514e15cb..314cab4022 100644 --- a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/pgx/v5/go/models.go @@ -18,7 +18,7 @@ type Llc struct { type Organisation struct { PartyID pgtype.UUID Name string - LegalName string + LegalName pgtype.Text } type Party struct { diff --git a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go index d2f0fff16c..c96981c383 100644 --- a/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go +++ b/internal/endtoend/testdata/ddl_create_table_inherits/postgresql/stdlib/go/models.go @@ -20,7 +20,7 @@ type Llc struct { type Organisation struct { PartyID uuid.UUID Name string - LegalName string + LegalName sql.NullString } type Party struct { diff --git a/internal/sql/catalog/table.go b/internal/sql/catalog/table.go index dc30acfa1e..78c8149048 100644 --- a/internal/sql/catalog/table.go +++ b/internal/sql/catalog/table.go @@ -13,9 +13,10 @@ import ( // A database table is a collection of related data held in a table format within a database. // It consists of columns and rows. type Table struct { - Rel *ast.TableName - Columns []*Column - Comment string + Rel *ast.TableName + Columns []*Column + Comment string + ChildTables []*Table } func checkMissing(err error, missingOK bool) error { @@ -55,6 +56,13 @@ func (c *Catalog) addColumn(table *Table, cmd *ast.AlterTableCmd) error { return err } table.Columns = append(table.Columns, tc) + + for _, childTable := range table.ChildTables { + if err := c.addColumn(childTable, cmd); err != nil { + return err + } + } + return nil } @@ -68,6 +76,13 @@ func (table *Table) alterColumnType(cmd *ast.AlterTableCmd) error { table.Columns[index].IsArray = cmd.Def.IsArray table.Columns[index].ArrayDims = cmd.Def.ArrayDims } + + for _, childTable := range table.ChildTables { + if err := childTable.alterColumnType(cmd); err != nil { + return err + } + } + return nil } @@ -91,6 +106,13 @@ func (c *Catalog) dropColumn(table *Table, cmd *ast.AlterTableCmd) error { } } table.Columns = append(table.Columns[:index], table.Columns[index+1:]...) + + for _, childTable := range table.ChildTables { + if err := c.dropColumn(childTable, cmd); err != nil { + return err + } + } + return nil } @@ -102,6 +124,13 @@ func (table *Table) dropNotNull(cmd *ast.AlterTableCmd) error { if index >= 0 { table.Columns[index].IsNotNull = false } + + for _, childTable := range table.ChildTables { + if err := childTable.dropNotNull(cmd); err != nil { + return err + } + } + return nil } @@ -113,6 +142,13 @@ func (table *Table) setNotNull(cmd *ast.AlterTableCmd) error { if index >= 0 { table.Columns[index].IsNotNull = true } + + for _, childTable := range table.ChildTables { + if err := childTable.setNotNull(cmd); err != nil { + return err + } + } + return nil } @@ -244,6 +280,15 @@ func (c *Catalog) alterTableSetSchema(stmt *ast.AlterTableSetSchemaStmt) error { } oldSchema.Tables = append(oldSchema.Tables[:idx], oldSchema.Tables[idx+1:]...) newSchema.Tables = append(newSchema.Tables, tbl) + + for _, childTable := range tbl.ChildTables { + childStmt := *stmt + childStmt.Table = childTable.Rel + if err := c.alterTableSetSchema(&childStmt); err != nil { + return err + } + } + return nil } @@ -271,6 +316,7 @@ func (c *Catalog) createTable(stmt *ast.CreateTableStmt) error { if err != nil { return err } + t.ChildTables = append(t.ChildTables, &tbl) // check and ignore duplicate columns for _, col := range t.Columns { if notNull, ok := seen[col.Name]; ok { @@ -285,7 +331,8 @@ func (c *Catalog) createTable(stmt *ast.CreateTableStmt) error { seen[col.Name] = col.IsNotNull coltype[col.Name] = col.Type - tbl.Columns = append(tbl.Columns, col) + inheritedColumn := *col + tbl.Columns = append(tbl.Columns, &inheritedColumn) } } @@ -308,6 +355,7 @@ func (c *Catalog) createTable(stmt *ast.CreateTableStmt) error { return fmt.Errorf("column %q has a type conflict", col.Colname) } } + continue } tc, err := c.defineColumn(stmt.Name, col) @@ -394,6 +442,7 @@ func (c *Catalog) renameColumn(stmt *ast.RenameColumnStmt) error { if err != nil { return checkMissing(err, stmt.MissingOk) } + idx := -1 for i := range tbl.Columns { if tbl.Columns[i].Name == stmt.Col.Name { @@ -407,7 +456,6 @@ func (c *Catalog) renameColumn(stmt *ast.RenameColumnStmt) error { return sqlerr.ColumnNotFound(tbl.Rel.Name, stmt.Col.Name) } tbl.Columns[idx].Name = *stmt.NewName - if tbl.Columns[idx].linkedType { name := fmt.Sprintf("%s_%s", tbl.Rel.Name, *stmt.NewName) rename := &ast.RenameTypeStmt{ @@ -419,6 +467,40 @@ func (c *Catalog) renameColumn(stmt *ast.RenameColumnStmt) error { } } + for _, childTable := range tbl.ChildTables { + childStmt := *stmt + childStmt.Table = childTable.Rel + if err := c.renameColumn(&childStmt); err != nil { + return err + } + } + + return nil +} + +func (table *Table) handleColumnUpdateOnTableRename( + c *Catalog, + stmt *ast.RenameTableStmt, +) error { + for idx := range table.Columns { + if table.Columns[idx].linkedType { + name := fmt.Sprintf("%s_%s", *stmt.NewName, table.Columns[idx].Name) + rename := &ast.RenameTypeStmt{ + Type: &table.Columns[idx].Type, + NewName: &name, + } + if err := c.renameType(rename); err != nil { + return err + } + } + } + + for _, child := range table.ChildTables { + if err := child.handleColumnUpdateOnTableRename(c, stmt); err != nil { + return err + } + } + return nil } @@ -434,17 +516,8 @@ func (c *Catalog) renameTable(stmt *ast.RenameTableStmt) error { tbl.Rel.Name = *stmt.NewName } - for idx := range tbl.Columns { - if tbl.Columns[idx].linkedType { - name := fmt.Sprintf("%s_%s", *stmt.NewName, tbl.Columns[idx].Name) - rename := &ast.RenameTypeStmt{ - Type: &tbl.Columns[idx].Type, - NewName: &name, - } - if err := c.renameType(rename); err != nil { - return err - } - } + if err := tbl.handleColumnUpdateOnTableRename(c, stmt); err != nil { + return err } return nil From 0fa722099ff8b7aa983a36c2c62d6b28eeee4e0f Mon Sep 17 00:00:00 2001 From: Dhruv Bhoot Date: Thu, 25 Apr 2024 03:20:16 -0700 Subject: [PATCH 2/2] Update test query.sql to have conditions on altered columns --- .../postgresql/pgx/v4/go/query.sql.go | 35 +++++++++++++++++ .../postgresql/pgx/v4/query.sql | 7 ++++ .../postgresql/pgx/v5/go/query.sql.go | 35 +++++++++++++++++ .../postgresql/pgx/v5/query.sql | 7 ++++ .../postgresql/stdlib/go/query.sql.go | 38 +++++++++++++++++++ .../postgresql/stdlib/query.sql | 7 ++++ 6 files changed, 129 insertions(+) diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go index fc5f995f36..4cbbf55dc2 100644 --- a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/go/query.sql.go @@ -101,3 +101,38 @@ func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { } return items, nil } + +const getOrganizationsByRegion = `-- name: GetOrganizationsByRegion :many +SELECT party_id, name, joined_on, rank, legal_name, region +FROM organisation +WHERE + region = 'us' AND + rank = 'ensign' +` + +func (q *Queries) GetOrganizationsByRegion(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.Query(ctx, getOrganizationsByRegion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.LegalName, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql index 30adbd9aa1..296ecf756d 100644 --- a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v4/query.sql @@ -6,3 +6,10 @@ SELECT * FROM person; -- name: GetAllOrganisations :many SELECT * FROM organisation; + +-- name: GetOrganizationsByRegion :many +SELECT * +FROM organisation +WHERE + region = 'us' AND + rank = 'ensign'; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go index fc5f995f36..4cbbf55dc2 100644 --- a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/go/query.sql.go @@ -101,3 +101,38 @@ func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { } return items, nil } + +const getOrganizationsByRegion = `-- name: GetOrganizationsByRegion :many +SELECT party_id, name, joined_on, rank, legal_name, region +FROM organisation +WHERE + region = 'us' AND + rank = 'ensign' +` + +func (q *Queries) GetOrganizationsByRegion(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.Query(ctx, getOrganizationsByRegion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.LegalName, + &i.Region, + ); err != nil { + return nil, err + } + items = append(items, i) + } + if err := rows.Err(); err != nil { + return nil, err + } + return items, nil +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql index 30adbd9aa1..296ecf756d 100644 --- a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/pgx/v5/query.sql @@ -6,3 +6,10 @@ SELECT * FROM person; -- name: GetAllOrganisations :many SELECT * FROM organisation; + +-- name: GetOrganizationsByRegion :many +SELECT * +FROM organisation +WHERE + region = 'us' AND + rank = 'ensign'; diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go index 5cea625d8b..b2dc915797 100644 --- a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/go/query.sql.go @@ -110,3 +110,41 @@ func (q *Queries) GetAllPeople(ctx context.Context) ([]Person, error) { } return items, nil } + +const getOrganizationsByRegion = `-- name: GetOrganizationsByRegion :many +SELECT party_id, name, joined_on, rank, legal_name, region +FROM organisation +WHERE + region = 'us' AND + rank = 'ensign' +` + +func (q *Queries) GetOrganizationsByRegion(ctx context.Context) ([]Organisation, error) { + rows, err := q.db.QueryContext(ctx, getOrganizationsByRegion) + if err != nil { + return nil, err + } + defer rows.Close() + var items []Organisation + for rows.Next() { + var i Organisation + if err := rows.Scan( + &i.PartyID, + &i.Name, + &i.JoinedOn, + &i.Rank, + &i.LegalName, + &i.Region, + ); 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 +} diff --git a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql index 30adbd9aa1..296ecf756d 100644 --- a/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql +++ b/internal/endtoend/testdata/ddl_alter_table_inherits/postgresql/stdlib/query.sql @@ -6,3 +6,10 @@ SELECT * FROM person; -- name: GetAllOrganisations :many SELECT * FROM organisation; + +-- name: GetOrganizationsByRegion :many +SELECT * +FROM organisation +WHERE + region = 'us' AND + rank = 'ensign';