aboutsummaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorAndrew Dunstan <andrew@dunslane.net>2021-06-18 07:44:58 -0400
committerAndrew Dunstan <andrew@dunslane.net>2021-06-18 07:44:58 -0400
commit5b6b5e5ee598ced2dc8e1d08a34d499860a4d15b (patch)
treeec4a5035a1fc9532ea86b1ccf0a7dac8238cf58a
parent357cb8f07f95665ea533ff534821c22c35b01288 (diff)
downloadpostgresql-5b6b5e5ee598ced2dc8e1d08a34d499860a4d15b.tar.gz
postgresql-5b6b5e5ee598ced2dc8e1d08a34d499860a4d15b.zip
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
-rw-r--r--src/backend/catalog/heap.c10
-rw-r--r--src/backend/commands/tablecmds.c5
-rw-r--r--src/backend/utils/cache/relcache.c19
-rw-r--r--src/test/regress/expected/fast_default.out19
-rw-r--r--src/test/regress/sql/fast_default.sql14
5 files changed, 63 insertions, 4 deletions
diff --git a/src/backend/catalog/heap.c b/src/backend/catalog/heap.c
index b34b8b94b3a..a42070fd925 100644
--- a/src/backend/catalog/heap.c
+++ b/src/backend/catalog/heap.c
@@ -2120,6 +2120,13 @@ SetAttrMissing(Oid relid, char *attname, char *value)
/* lock the table the attribute belongs to */
tablerel = table_open(relid, AccessExclusiveLock);
+ /* Don't do anything unless it's a plain table */
+ if (tablerel->rd_rel->relkind != RELKIND_RELATION)
+ {
+ table_close(tablerel, AccessExclusiveLock);
+ return;
+ }
+
/* Lock the attribute row and get the data */
attrrel = table_open(AttributeRelationId, RowExclusiveLock);
atttup = SearchSysCacheAttName(relid, attname);
@@ -2246,7 +2253,8 @@ StoreAttrDefault(Relation rel, AttrNumber attnum,
valuesAtt[Anum_pg_attribute_atthasdef - 1] = true;
replacesAtt[Anum_pg_attribute_atthasdef - 1] = true;
- if (add_column_mode && !attgenerated)
+ if (rel->rd_rel->relkind == RELKIND_RELATION && add_column_mode &&
+ !attgenerated)
{
expr2 = expression_planner(expr2);
estate = CreateExecutorState();
diff --git a/src/backend/commands/tablecmds.c b/src/backend/commands/tablecmds.c
index 70337c7c072..135fa469817 100644
--- a/src/backend/commands/tablecmds.c
+++ b/src/backend/commands/tablecmds.c
@@ -11774,9 +11774,10 @@ ATExecAlterColumnType(AlteredTableInfo *tab, Relation rel,
/*
* Here we go --- change the recorded column type and collation. (Note
* heapTup is a copy of the syscache entry, so okay to scribble on.) First
- * fix up the missing value if any.
+ * fix up the missing value if any. There shouldn't be any missing values
+ * for anything except plain tables, but if there are, ignore them.
*/
- if (attTup->atthasmissing)
+ if (rel->rd_rel->relkind == RELKIND_RELATION && attTup->atthasmissing)
{
Datum missingval;
bool missingNull;
diff --git a/src/backend/utils/cache/relcache.c b/src/backend/utils/cache/relcache.c
index b53d92b4dae..23405711d1d 100644
--- a/src/backend/utils/cache/relcache.c
+++ b/src/backend/utils/cache/relcache.c
@@ -550,6 +550,7 @@ RelationBuildTupleDesc(Relation relation)
{
Form_pg_attribute attp;
int attnum;
+ bool atthasmissing;
attp = (Form_pg_attribute) GETSTRUCT(pg_attribute_tuple);
@@ -563,6 +564,22 @@ RelationBuildTupleDesc(Relation relation)
attp,
ATTRIBUTE_FIXED_PART_SIZE);
+ /*
+ * Fix atthasmissing flag - it's only for plain tables. Others
+ * should not have missing values set, but there may be some left from
+ * before when we placed that check, so this code defensively ignores
+ * such values.
+ */
+ atthasmissing = attp->atthasmissing;
+ if (relation->rd_rel->relkind != RELKIND_RELATION && atthasmissing)
+ {
+ Form_pg_attribute nattp;
+
+ atthasmissing = false;
+ nattp = TupleDescAttr(relation->rd_att, attnum - 1);
+ nattp->atthasmissing = false;
+ }
+
/* Update constraint/default info */
if (attp->attnotnull)
constr->has_not_null = true;
@@ -584,7 +601,7 @@ RelationBuildTupleDesc(Relation relation)
}
/* Likewise for a missing value */
- if (attp->atthasmissing)
+ if (atthasmissing)
{
Datum missingval;
bool missingNull;
diff --git a/src/test/regress/expected/fast_default.out b/src/test/regress/expected/fast_default.out
index 10bc5ff757c..91f25717b5a 100644
--- a/src/test/regress/expected/fast_default.out
+++ b/src/test/regress/expected/fast_default.out
@@ -797,7 +797,26 @@ SELECT * FROM t WHERE a IS NULL;
(1 row)
ROLLBACK;
+-- verify that a default set on a non-plain table doesn't set a missing
+-- value on the attribute
+CREATE FOREIGN DATA WRAPPER dummy;
+CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
+CREATE FOREIGN TABLE ft1 (c1 integer NOT NULL) SERVER s0;
+ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer DEFAULT 0;
+ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
+SELECT count(*)
+ FROM pg_attribute
+ WHERE attrelid = 'ft1'::regclass AND
+ (attmissingval IS NOT NULL OR atthasmissing);
+ count
+-------
+ 0
+(1 row)
+
-- cleanup
+DROP FOREIGN TABLE ft1;
+DROP SERVER s0;
+DROP FOREIGN DATA WRAPPER dummy;
DROP TABLE vtype;
DROP TABLE vtype2;
DROP TABLE follower;
diff --git a/src/test/regress/sql/fast_default.sql b/src/test/regress/sql/fast_default.sql
index 4589b9e58d1..16a3b7ca51d 100644
--- a/src/test/regress/sql/fast_default.sql
+++ b/src/test/regress/sql/fast_default.sql
@@ -524,8 +524,22 @@ SET LOCAL enable_seqscan = false;
SELECT * FROM t WHERE a IS NULL;
ROLLBACK;
+-- verify that a default set on a non-plain table doesn't set a missing
+-- value on the attribute
+CREATE FOREIGN DATA WRAPPER dummy;
+CREATE SERVER s0 FOREIGN DATA WRAPPER dummy;
+CREATE FOREIGN TABLE ft1 (c1 integer NOT NULL) SERVER s0;
+ALTER FOREIGN TABLE ft1 ADD COLUMN c8 integer DEFAULT 0;
+ALTER FOREIGN TABLE ft1 ALTER COLUMN c8 TYPE char(10);
+SELECT count(*)
+ FROM pg_attribute
+ WHERE attrelid = 'ft1'::regclass AND
+ (attmissingval IS NOT NULL OR atthasmissing);
-- cleanup
+DROP FOREIGN TABLE ft1;
+DROP SERVER s0;
+DROP FOREIGN DATA WRAPPER dummy;
DROP TABLE vtype;
DROP TABLE vtype2;
DROP TABLE follower;