Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commita3c9d35

Browse files
committed
Reject attempts to alter composite types used in indexes.
find_composite_type_dependencies() ignored indexes, which is a poordecision because an expression index could have a stored column ofa composite (or other container) type even when the underlying tabledoes not. Teach it to detect such cases and error out. We have towork a bit harder than for other relations because the pg_depend entrywon't identify the specific index column of concern, but it's not muchnew code.This does not address bug #17872's original complaint that droppinga column in such a type might lead to violations of the uniquenessproperty that a unique index is supposed to ensure. That seems ofmuch less concern to me because it won't lead to crashes.Per bug #17872 from Alexander Lakhin. Back-patch to all supportedbranches.Discussion:https://postgr.es/m/17872-d0fbb799dc3fd85d@postgresql.org
1 parentc87aff0 commita3c9d35

File tree

3 files changed

+67
-10
lines changed

3 files changed

+67
-10
lines changed

‎src/backend/commands/tablecmds.c

Lines changed: 48 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -6508,6 +6508,7 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
65086508
{
65096509
Form_pg_depend pg_depend = (Form_pg_depend) GETSTRUCT(depTup);
65106510
Relationrel;
6511+
TupleDesctupleDesc;
65116512
Form_pg_attribute att;
65126513

65136514
/* Check for directly dependent types */
@@ -6524,18 +6525,57 @@ find_composite_type_dependencies(Oid typeOid, Relation origRelation,
65246525
continue;
65256526
}
65266527

6527-
/* Else, ignore dependees that aren't user columns of relations */
6528-
/* (we assume system columns are never of interesting types) */
6529-
if (pg_depend->classid != RelationRelationId ||
6530-
pg_depend->objsubid <= 0)
6528+
/* Else, ignore dependees that aren't relations */
6529+
if (pg_depend->classid != RelationRelationId)
65316530
continue;
65326531

65336532
rel = relation_open(pg_depend->objid, AccessShareLock);
6534-
att =TupleDescAttr(rel->rd_att, pg_depend->objsubid - 1);
6533+
tupleDesc =RelationGetDescr(rel);
65356534

6536-
if (rel->rd_rel->relkind == RELKIND_RELATION ||
6537-
rel->rd_rel->relkind == RELKIND_MATVIEW ||
6538-
rel->rd_rel->relkind == RELKIND_PARTITIONED_TABLE)
6535+
/*
6536+
* If objsubid identifies a specific column, refer to that in error
6537+
* messages. Otherwise, search to see if there's a user column of the
6538+
* type. (We assume system columns are never of interesting types.)
6539+
* The search is needed because an index containing an expression
6540+
* column of the target type will just be recorded as a whole-relation
6541+
* dependency. If we do not find a column of the type, the dependency
6542+
* must indicate that the type is transiently referenced in an index
6543+
* expression but not stored on disk, which we assume is OK, just as
6544+
* we do for references in views. (It could also be that the target
6545+
* type is embedded in some container type that is stored in an index
6546+
* column, but the previous recursion should catch such cases.)
6547+
*/
6548+
if (pg_depend->objsubid > 0 && pg_depend->objsubid <= tupleDesc->natts)
6549+
att = TupleDescAttr(tupleDesc, pg_depend->objsubid - 1);
6550+
else
6551+
{
6552+
att = NULL;
6553+
for (int attno = 1; attno <= tupleDesc->natts; attno++)
6554+
{
6555+
att = TupleDescAttr(tupleDesc, attno - 1);
6556+
if (att->atttypid == typeOid && !att->attisdropped)
6557+
break;
6558+
att = NULL;
6559+
}
6560+
if (att == NULL)
6561+
{
6562+
/* No such column, so assume OK */
6563+
relation_close(rel, AccessShareLock);
6564+
continue;
6565+
}
6566+
}
6567+
6568+
/*
6569+
* We definitely should reject if the relation has storage. If it's
6570+
* partitioned, then perhaps we don't have to reject: if there are
6571+
* partitions then we'll fail when we find one, else there is no
6572+
* stored data to worry about. However, it's possible that the type
6573+
* change would affect conclusions about whether the type is sortable
6574+
* or hashable and thus (if it's a partitioning column) break the
6575+
* partitioning rule. For now, reject for partitioned rels too.
6576+
*/
6577+
if (RELKIND_HAS_STORAGE(rel->rd_rel->relkind) ||
6578+
RELKIND_HAS_PARTITIONS(rel->rd_rel->relkind))
65396579
{
65406580
if (origTypeName)
65416581
ereport(ERROR,

‎src/test/regress/expected/alter_table.out

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -3097,6 +3097,13 @@ CREATE TYPE test_type1 AS (a int, b text);
30973097
CREATE TABLE test_tbl1 (x int, y test_type1);
30983098
ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
30993099
ERROR: cannot alter type "test_type1" because column "test_tbl1.y" uses it
3100+
DROP TABLE test_tbl1;
3101+
CREATE TABLE test_tbl1 (x int, y text);
3102+
CREATE INDEX test_tbl1_idx ON test_tbl1((row(x,y)::test_type1));
3103+
ALTER TYPE test_type1 ALTER ATTRIBUTE b TYPE varchar; -- fails
3104+
ERROR: cannot alter type "test_type1" because column "test_tbl1_idx.row" uses it
3105+
DROP TABLE test_tbl1;
3106+
DROP TYPE test_type1;
31003107
CREATE TYPE test_type2 AS (a int, b text);
31013108
CREATE TABLE test_tbl2 OF test_type2;
31023109
CREATE TABLE test_tbl2_subclass () INHERITS (test_tbl2);
@@ -3208,7 +3215,8 @@ Typed table of type: test_type2
32083215
c | text | | |
32093216
Inherits: test_tbl2
32103217

3211-
DROP TABLE test_tbl2_subclass;
3218+
DROP TABLE test_tbl2_subclass, test_tbl2;
3219+
DROP TYPE test_type2;
32123220
CREATE TYPE test_typex AS (a int, b text);
32133221
CREATE TABLE test_tblx (x int, y test_typex check ((y).a > 0));
32143222
ALTER TYPE test_typex DROP ATTRIBUTE a; -- fails

‎src/test/regress/sql/alter_table.sql

Lines changed: 10 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1983,6 +1983,14 @@ CREATE TYPE test_type1 AS (a int, b text);
19831983
CREATETABLEtest_tbl1 (xint, y test_type1);
19841984
ALTERTYPE test_type1 ALTER ATTRIBUTE b TYPEvarchar;-- fails
19851985

1986+
DROPTABLE test_tbl1;
1987+
CREATETABLEtest_tbl1 (xint, ytext);
1988+
CREATEINDEXtest_tbl1_idxON test_tbl1((row(x,y)::test_type1));
1989+
ALTERTYPE test_type1 ALTER ATTRIBUTE b TYPEvarchar;-- fails
1990+
1991+
DROPTABLE test_tbl1;
1992+
DROPTYPE test_type1;
1993+
19861994
CREATETYPEtest_type2AS (aint, btext);
19871995
CREATETABLEtest_tbl2 OF test_type2;
19881996
CREATETABLEtest_tbl2_subclass () INHERITS (test_tbl2);
@@ -2010,7 +2018,8 @@ ALTER TYPE test_type2 RENAME ATTRIBUTE a TO aa CASCADE;
20102018
\d test_tbl2
20112019
\d test_tbl2_subclass
20122020

2013-
DROPTABLE test_tbl2_subclass;
2021+
DROPTABLE test_tbl2_subclass, test_tbl2;
2022+
DROPTYPE test_type2;
20142023

20152024
CREATETYPEtest_typexAS (aint, btext);
20162025
CREATETABLEtest_tblx (xint, y test_typexcheck ((y).a>0));

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp