Skip to content

Commit b2ad4a6

Browse files
committed
sql: fix sequence dependencies for IDENTITY columns in pg_depend
Release note (bug fix): pg_class.pg_depend now contains entries with deptype='i' (internal) for identity columns that own sequences. These previously had deptype='a' (auto).
1 parent 43d1bd4 commit b2ad4a6

File tree

4 files changed

+119
-23
lines changed

4 files changed

+119
-23
lines changed

pkg/sql/logictest/testdata/logic_test/orms

Lines changed: 68 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -435,3 +435,71 @@ and traint.conparentid = 0 ORDER BY traint.conrelid, traint.conname
435435
----
436436
public b public a false b_a_id_fkey {"(a_id,id)"} false
437437
public src public dst false src_d_fkey {"(d,a)"} false
438+
439+
# Test for issue #108439: EFCore introspection query for IDENTITY columns
440+
# needs pg_depend entries with deptype 'i'.
441+
442+
statement ok
443+
CREATE TABLE efcore_identity_test (
444+
id INT8 NOT NULL GENERATED BY DEFAULT AS IDENTITY,
445+
CONSTRAINT pk_testtable PRIMARY KEY (id ASC)
446+
)
447+
448+
query TTTTTTTBTTTTTTTBTTIIIIBI colnames
449+
SELECT
450+
nspname,
451+
cls.relname,
452+
typ.typname,
453+
basetyp.typname AS basetypname,
454+
attname,
455+
description,
456+
collname,
457+
attisdropped,
458+
attidentity::TEXT,
459+
attgenerated::TEXT,
460+
''::text as attcompression,
461+
format_type(typ.oid, atttypmod) AS formatted_typname,
462+
format_type(basetyp.oid, typ.typtypmod) AS formatted_basetypname,
463+
CASE
464+
WHEN pg_proc.proname = 'array_recv' THEN 'a'
465+
ELSE typ.typtype
466+
END AS typtype,
467+
CASE WHEN pg_proc.proname='array_recv' THEN elemtyp.typname END AS elemtypname,
468+
NOT (attnotnull OR typ.typnotnull) AS nullable,
469+
CASE
470+
WHEN atthasdef THEN (SELECT pg_get_expr(adbin, cls.oid) FROM pg_attrdef WHERE adrelid = cls.oid AND adnum = attr.attnum)
471+
END AS default,
472+
-- Sequence options for identity columns
473+
format_type(seqtypid, 0) AS seqtype, seqstart, seqmin, seqmax, seqincrement, seqcycle, seqcache
474+
FROM pg_class AS cls
475+
JOIN pg_namespace AS ns ON ns.oid = cls.relnamespace
476+
LEFT JOIN pg_attribute AS attr ON attrelid = cls.oid
477+
LEFT JOIN pg_type AS typ ON attr.atttypid = typ.oid
478+
LEFT JOIN pg_proc ON pg_proc.oid = typ.typreceive
479+
LEFT JOIN pg_type AS elemtyp ON (elemtyp.oid = typ.typelem)
480+
LEFT JOIN pg_type AS basetyp ON (basetyp.oid = typ.typbasetype)
481+
LEFT JOIN pg_description AS des ON des.objoid = cls.oid AND des.objsubid = attnum
482+
LEFT JOIN pg_collation as coll ON coll.oid = attr.attcollation
483+
-- Bring in identity sequences the depend on this column.
484+
LEFT JOIN pg_depend AS dep ON dep.refobjid = cls.oid AND dep.refobjsubid = attr.attnum AND dep.deptype = 'i'
485+
LEFT JOIN pg_sequence AS seq ON seq.seqrelid = dep.objid
486+
WHERE
487+
cls.relkind IN ('r', 'v', 'm', 'f') AND
488+
nspname NOT IN ('pg_catalog', 'information_schema', 'crdb_internal') AND
489+
attnum > 0 AND
490+
cls.relname = 'efcore_identity_test' AND
491+
NOT EXISTS (
492+
SELECT 1 FROM pg_depend WHERE
493+
classid=(
494+
SELECT cls.oid
495+
FROM pg_class AS cls
496+
JOIN pg_namespace AS ns ON ns.oid = cls.relnamespace
497+
WHERE relname='pg_class' AND ns.nspname='pg_catalog'
498+
) AND
499+
objid=cls.oid AND
500+
deptype IN ('e', 'x')
501+
)
502+
ORDER BY attnum;
503+
----
504+
nspname relname typname basetypname attname description collname attisdropped attidentity attgenerated attcompression formatted_typname formatted_basetypname typtype elemtypname nullable default seqtype seqstart seqmin seqmax seqincrement seqcycle seqcache
505+
public efcore_identity_test int8 NULL id NULL NULL false d · · bigint NULL b NULL false nextval('public.efcore_identity_test_id_seq'::REGCLASS) bigint 1 1 9223372036854775807 1 false 1

pkg/sql/logictest/testdata/logic_test/pg_catalog

Lines changed: 15 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1740,8 +1740,8 @@ FROM pg_catalog.pg_depend
17401740
ORDER BY objid, refobjid, refobjsubid
17411741
----
17421742
classid objid objsubid refclassid refobjid refobjsubid deptype
1743-
4294967082 111 0 4294967082 110 14 a
1744-
4294967082 112 0 4294967082 110 15 a
1743+
4294967082 111 0 4294967082 110 14 i
1744+
4294967082 112 0 4294967082 110 15 i
17451745
4294967036 842401391 0 4294967082 110 1 n
17461746
4294967036 842401391 0 4294967082 110 2 n
17471747
4294967036 842401391 0 4294967082 110 3 n
@@ -1776,6 +1776,19 @@ WHERE seq.oid = dep.objid
17761776
attname nspname relname
17771777
a public t_with_pk_seq_a_seq
17781778

1779+
# Test for issue #108439: IDENTITY columns should have deptype 'i' dependencies.
1780+
query TTT colnames
1781+
SELECT seq_cls.relname AS sequence_name, attr.attname AS column_name, dep.deptype
1782+
FROM pg_depend dep
1783+
JOIN pg_class seq_cls ON seq_cls.oid = dep.objid
1784+
JOIN pg_attribute attr ON attr.attrelid = dep.refobjid AND attr.attnum = dep.refobjsubid
1785+
WHERE dep.refobjid = 't_with_pk_seq'::regclass
1786+
AND dep.deptype = 'i'
1787+
ORDER BY dep.deptype
1788+
----
1789+
sequence_name column_name deptype
1790+
t_with_pk_seq_a_seq a i
1791+
17791792
# Some entries in pg_depend are dependency links from the pg_constraint system
17801793
# table to the pg_class system table. Other entries are links to pg_class when it is
17811794
# a table-view dependency.

pkg/sql/logictest/testdata/logic_test/sequences

Lines changed: 1 addition & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1091,7 +1091,7 @@ FROM pg_class AS seqclass
10911091
AND attrib.attrelid = dep.refobjid
10921092
WHERE seqclass.relkind = 'S';
10931093
----
1094-
owned_seq owner owner_col
1094+
owned_seq owner owner_col
10951095

10961096
# Sequence owner can be removed
10971097

pkg/sql/pg_catalog.go

Lines changed: 35 additions & 20 deletions
Original file line numberDiff line numberDiff line change
@@ -1674,32 +1674,17 @@ https://www.postgresql.org/docs/9.5/catalog-pg-depend.html`,
16741674
}
16751675
pgProcDesc, err := vt.getVirtualTableDesc(&pgProcTableName, p)
16761676
if err != nil {
1677-
return errors.New("could not find pg_catalog.pg_rewrite")
1677+
return errors.New("could not find pg_catalog.pg_proc")
16781678
}
16791679
h := makeOidHasher()
1680+
pgConstraintTableOid := tableOid(pgConstraintsDesc.GetID())
1681+
pgClassTableOid := tableOid(pgClassDesc.GetID())
1682+
pgRewriteTableOid := tableOid(pgRewriteDesc.GetID())
1683+
16801684
opts := forEachTableDescOptions{virtualOpts: hideVirtual} /*virtual tables have no constraints*/
16811685
err = forEachTableDesc(ctx, p, dbContext, opts, func(
16821686
ctx context.Context, descCtx tableDescContext) error {
16831687
db, sc, table, tableLookup := descCtx.database, descCtx.schema, descCtx.table, descCtx.tableLookup
1684-
pgConstraintTableOid := tableOid(pgConstraintsDesc.GetID())
1685-
pgClassTableOid := tableOid(pgClassDesc.GetID())
1686-
pgRewriteTableOid := tableOid(pgRewriteDesc.GetID())
1687-
if table.IsSequence() &&
1688-
!table.GetSequenceOpts().SequenceOwner.Equal(descpb.TableDescriptor_SequenceOpts_SequenceOwner{}) {
1689-
refObjID := tableOid(table.GetSequenceOpts().SequenceOwner.OwnerTableID)
1690-
refObjSubID := tree.NewDInt(tree.DInt(table.GetSequenceOpts().SequenceOwner.OwnerColumnID))
1691-
objID := tableOid(table.GetID())
1692-
return addRow(
1693-
pgClassTableOid, // classid
1694-
objID, // objid
1695-
zeroVal, // objsubid
1696-
pgClassTableOid, // refclassid
1697-
refObjID, // refobjid
1698-
refObjSubID, // refobjsubid
1699-
depTypeAuto, // deptype
1700-
)
1701-
}
1702-
17031688
// In the case of table/view relationship, In PostgreSQL pg_depend.objid refers to
17041689
// pg_rewrite.oid, then pg_rewrite ev_class refers to the dependent object.
17051690
reportViewDependency := func(dep *descpb.TableDescriptor_Reference) error {
@@ -1757,6 +1742,36 @@ https://www.postgresql.org/docs/9.5/catalog-pg-depend.html`,
17571742
return err
17581743
}
17591744
}
1745+
1746+
// Add dependencies for columns that use sequences. This creates pg_depend
1747+
// entries with deptype 'a' (auto) for regular sequences and 'i'
1748+
// (internal) for IDENTITY columns.
1749+
if table.IsTable() {
1750+
for _, column := range table.AllColumns() {
1751+
for i := 0; i < column.NumOwnsSequences(); i++ {
1752+
seqID := column.GetOwnsSequenceID(i)
1753+
seqObjID := tableOid(seqID)
1754+
tableObjID := tableOid(table.GetID())
1755+
columnSubID := tree.NewDInt(tree.DInt(column.GetPGAttributeNum()))
1756+
depType := depTypeAuto
1757+
if column.IsGeneratedAsIdentity() {
1758+
depType = depTypeInternal
1759+
}
1760+
1761+
if err := addRow(
1762+
pgClassTableOid, // classid
1763+
seqObjID, // objid
1764+
zeroVal, // objsubid
1765+
pgClassTableOid, // refclassid
1766+
tableObjID, // refobjid
1767+
columnSubID, // refobjsubid
1768+
depType, // deptype
1769+
); err != nil {
1770+
return err
1771+
}
1772+
}
1773+
}
1774+
}
17601775
return nil
17611776
})
17621777
if err != nil {

0 commit comments

Comments
 (0)