Fix check for child column generation status matching parent.

In commit 8bf6ec3ba, I mistakenly supposed that MergeAttributes'
loop over saved_schema was reprocessing column definitions that
had already been checked earlier: there is a variant syntax for
creating a child partition in which that's not true.  So we need
to duplicate the full check appearing further up.

(Actually, I believe that the "if (restdef->identity)" part is
not reachable, because we reject identity on partitions earlier.
But it seems wise to keep the check, in case that's ever relaxed,
and to keep this code in sync with the other instance.)

Per report from Alexander Lakhin.

Discussion: https://postgr.es/m/4a8200ca-8378-653e-38ed-b2e1f1611aa6@gmail.com
This commit is contained in:
Tom Lane 2023-02-16 18:51:55 -05:00
parent afa7930462
commit a0fa18cc0d
3 changed files with 55 additions and 10 deletions

View File

@ -3015,17 +3015,34 @@ MergeAttributes(List *schema, List *supers, char relpersistence,
coldef->is_not_null |= restdef->is_not_null;
/*
* As above, reject generated columns in partitions that
* are not generated in the parent.
* Check for conflicts related to generated columns.
*
* Same rules as above: generated-ness has to match the
* parent, but the contents of the generation expression
* can be different.
*/
if (restdef->generated && !coldef->generated)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
errmsg("child column \"%s\" specifies generation expression",
restdef->colname),
errhint("A child table column cannot be generated unless its parent column is.")));
/* Other way around should have been dealt with above */
Assert(!(coldef->generated && !restdef->generated));
if (coldef->generated)
{
if (restdef->raw_default && !restdef->generated)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
errmsg("column \"%s\" inherits from generated column but specifies default",
restdef->colname)));
if (restdef->identity)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
errmsg("column \"%s\" inherits from generated column but specifies identity",
restdef->colname)));
}
else
{
if (restdef->generated)
ereport(ERROR,
(errcode(ERRCODE_INVALID_COLUMN_DEFINITION),
errmsg("child column \"%s\" specifies generation expression",
restdef->colname),
errhint("A child table column cannot be generated unless its parent column is.")));
}
/*
* Override the parent's default value for this column

View File

@ -730,10 +730,26 @@ CREATE TABLE gtest_child PARTITION OF gtest_parent
CREATE TABLE gtest_child2 PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS (f2 * 22) STORED -- overrides gen expr
) FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
CREATE TABLE gtest_child3 PARTITION OF gtest_parent (
f3 DEFAULT 42 -- error
) FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
ERROR: column "f3" inherits from generated column but specifies default
CREATE TABLE gtest_child3 PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS IDENTITY -- error
) FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
ERROR: identity columns are not supported on partitions
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01'); -- error
ERROR: column "f3" in child table must be a generated column
DROP TABLE gtest_child3;
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint DEFAULT 42);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01'); -- error
ERROR: column "f3" in child table must be a generated column
DROP TABLE gtest_child3;
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS IDENTITY);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01'); -- error
ERROR: column "f3" in child table must be a generated column
DROP TABLE gtest_child3;
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 33) STORED);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
\d gtest_child

View File

@ -390,9 +390,21 @@ CREATE TABLE gtest_child PARTITION OF gtest_parent
CREATE TABLE gtest_child2 PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS (f2 * 22) STORED -- overrides gen expr
) FOR VALUES FROM ('2016-08-01') TO ('2016-09-01');
CREATE TABLE gtest_child3 PARTITION OF gtest_parent (
f3 DEFAULT 42 -- error
) FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
CREATE TABLE gtest_child3 PARTITION OF gtest_parent (
f3 WITH OPTIONS GENERATED ALWAYS AS IDENTITY -- error
) FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01'); -- error
DROP TABLE gtest_child3;
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint DEFAULT 42);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01'); -- error
DROP TABLE gtest_child3;
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS IDENTITY);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01'); -- error
DROP TABLE gtest_child3;
CREATE TABLE gtest_child3 (f1 date NOT NULL, f2 bigint, f3 bigint GENERATED ALWAYS AS (f2 * 33) STORED);
ALTER TABLE gtest_parent ATTACH PARTITION gtest_child3 FOR VALUES FROM ('2016-09-01') TO ('2016-10-01');
\d gtest_child