Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit 6432bfe

Browse files
committed
Don't set a fast default for anything but a plain table
The fast default code added in Release 11 omitted to check that the table a fast default was being added to was a plain table. Thus one could be added to a foreign table, which predicably blows up. Here we perform that check. In addition, on the back branches, since some of these might have escaped into the wild, if we encounter a missing value for an attribute of something other than a plain table we ignore it. Fixes bug #17056 Backpatch to release 11, Reviewed by: Andres Freund, Álvaro Herrera and Tom Lane
1 parent 70293e9 commit 6432bfe

File tree

5 files changed

+63
-4
lines changed

5 files changed

+63
-4
lines changed

src/backend/catalog/heap.c

Lines changed: 9 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -2120,6 +2120,13 @@ SetAttrMissing(Oid relid, char *attname, char *value)
21202120
/* lock the table the attribute belongs to */
21212121
tablerel = table_open(relid, AccessExclusiveLock);
21222122

2123+
/* Don't do anything unless it's a plain table */
2124+
if (tablerel->rd_rel->relkind != RELKIND_RELATION)
2125+
{
2126+
table_close(tablerel, AccessExclusiveLock);
2127+
return;
2128+
}
2129+
21232130
/* Lock the attribute row and get the data */
21242131
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
21252132
atttup = SearchSysCacheAttName(relid, attname);
@@ -2246,7 +2253,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
22462253
valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
22472254
replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
22482255

2249-
if (add_column_mode && !attgenerated)
2256+
if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
2257+
!attgenerated)
22502258
{
22512259
expr2 = expression_planner(expr2);
22522260
estate = CreateExecutorState();

src/backend/commands/tablecmds.c

Lines changed: 3 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -11313,9 +11313,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
1131311313
/*
1131411314
* Here we go --- change the recorded column type and collation. (Note
1131511315
* heapTup is a copy of the syscache entry, so okay to scribble on.) First
11316-
* fix up the missing value if any.
11316+
* fix up the missing value if any. There shouldn't be any missing values
11317+
* for anything except plain tables, but if there are, ignore them.
1131711318
*/
11318-
if (attTup->atthasmissing)
11319+
if (rel->rd_rel->relkind == RELKIND_RELATION && attTup->atthasmissing)
1131911320
{
1132011321
Datum missingval;
1132111322
bool missingNull;

src/backend/utils/cache/relcache.c

Lines changed: 18 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -552,6 +552,7 @@ RelationBuildTupleDesc(Relation relation)
552552
{
553553
Form_pg_attribute attp;
554554
int attnum;
555+
bool atthasmissing;
555556

556557
attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
557558

@@ -565,6 +566,22 @@ RelationBuildTupleDesc(Relation relation)
565566
attp,
566567
ATTRIBUTE_FIXED_PART_SIZE);
567568

569+
/*
570+
* Fix atthasmissing flag - it's only for plain tables. Others
571+
* should not have missing values set, but there may be some left from
572+
* before when we placed that check, so this code defensively ignores
573+
* such values.
574+
*/
575+
atthasmissing = attp->atthasmissing;
576+
if (relation->rd_rel->relkind != RELKIND_RELATION && atthasmissing)
577+
{
578+
Form_pg_attribute nattp;
579+
580+
atthasmissing = false;
581+
nattp = TupleDescAttr(relation->rd_att, attnum - 1);
582+
nattp->atthasmissing = false;
583+
}
584+
568585
/* Update constraint/default info */
569586
if (attp->attnotnull)
570587
constr->has_not_null = true;
@@ -586,7 +603,7 @@ RelationBuildTupleDesc(Relation relation)
586603
}
587604

588605
/* Likewise for a missing value */
589-
if (attp->atthasmissing)
606+
if (atthasmissing)
590607
{
591608
Datum missingval;
592609
bool missingNull;

src/test/regress/expected/fast_default.out

Lines changed: 19 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -797,7 +797,26 @@ SELECT * FROM t WHERE a IS NULL;
797797
(1 row)
798798

799799
ROLLBACK;
800+
-- verify that a default set on a non-plain table doesn't set a missing
801+
-- value on the attribute
802+
CREATE FOREIGN DATA WRAPPER dummy;
803+
CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
804+
CREATE FOREIGN TABLE ft1 (c1 integer NOT NULL) SERVER s0;
805+
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer DEFAULT 0;
806+
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
807+
SELECT count(*)
808+
FROM pg_attribute
809+
WHERE attrelid = 'ft1'::regclass AND
810+
(attmissingval IS NOT NULL OR atthasmissing);
811+
count
812+
-------
813+
0
814+
(1 row)
815+
800816
-- cleanup
817+
DROP FOREIGN TABLE ft1;
818+
DROP SERVER s0;
819+
DROP FOREIGN DATA WRAPPER dummy;
801820
DROP TABLE vtype;
802821
DROP TABLE vtype2;
803822
DROP TABLE follower;

src/test/regress/sql/fast_default.sql

Lines changed: 14 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -524,8 +524,22 @@ SET LOCAL enable_seqscan = false;
524524
SELECT * FROM t WHERE a IS NULL;
525525
ROLLBACK;
526526

527+
-- verify that a default set on a non-plain table doesn't set a missing
528+
-- value on the attribute
529+
CREATE FOREIGN DATA WRAPPER dummy;
530+
CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
531+
CREATE FOREIGN TABLE ft1 (c1 integer NOT NULL) SERVER s0;
532+
ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer DEFAULT 0;
533+
ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
534+
SELECT count(*)
535+
FROM pg_attribute
536+
WHERE attrelid = 'ft1'::regclass AND
537+
(attmissingval IS NOT NULL OR atthasmissing);
527538

528539
-- cleanup
540+
DROP FOREIGN TABLE ft1;
541+
DROP SERVER s0;
542+
DROP FOREIGN DATA WRAPPER dummy;
529543
DROP TABLE vtype;
530544
DROP TABLE vtype2;
531545
DROP TABLE follower;

0 commit comments

Comments
 (0)