mirror of
https://github.com/postgres/postgres.git
synced 2025-07-02 09:02:37 +03:00
Fix ALTER TABLE / INHERIT with generated columns
When running ALTER TABLE t2 INHERIT t1, we must check that columns in t2 that correspond to a generated column in t1 are also generated and have the same generation expression. Otherwise, this would allow creating setups that a normal CREATE TABLE sequence would not allow. Discussion: https://www.postgresql.org/message-id/22de27f6-7096-8d96-4619-7b882932ca25@2ndquadrant.com
This commit is contained in:
@ -14381,6 +14381,66 @@ MergeAttributesIntoExisting(Relation child_rel, Relation parent_rel)
|
||||
errmsg("column \"%s\" in child table must be marked NOT NULL",
|
||||
attributeName)));
|
||||
|
||||
/*
|
||||
* If parent column is generated, child column must be, too.
|
||||
*/
|
||||
if (attribute->attgenerated && !childatt->attgenerated)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("column \"%s\" in child table must be a generated column",
|
||||
attributeName)));
|
||||
|
||||
/*
|
||||
* Check that both generation expressions match.
|
||||
*
|
||||
* The test we apply is to see whether they reverse-compile to the
|
||||
* same source string. This insulates us from issues like whether
|
||||
* attributes have the same physical column numbers in parent and
|
||||
* child relations. (See also constraints_equivalent().)
|
||||
*/
|
||||
if (attribute->attgenerated && childatt->attgenerated)
|
||||
{
|
||||
TupleConstr *child_constr = child_rel->rd_att->constr;
|
||||
TupleConstr *parent_constr = parent_rel->rd_att->constr;
|
||||
char *child_expr = NULL;
|
||||
char *parent_expr = NULL;
|
||||
|
||||
Assert(child_constr != NULL);
|
||||
Assert(parent_constr != NULL);
|
||||
|
||||
for (int i = 0; i < child_constr->num_defval; i++)
|
||||
{
|
||||
if (child_constr->defval[i].adnum == childatt->attnum)
|
||||
{
|
||||
child_expr =
|
||||
TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
|
||||
CStringGetTextDatum(child_constr->defval[i].adbin),
|
||||
ObjectIdGetDatum(child_rel->rd_id)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert(child_expr != NULL);
|
||||
|
||||
for (int i = 0; i < parent_constr->num_defval; i++)
|
||||
{
|
||||
if (parent_constr->defval[i].adnum == attribute->attnum)
|
||||
{
|
||||
parent_expr =
|
||||
TextDatumGetCString(DirectFunctionCall2(pg_get_expr,
|
||||
CStringGetTextDatum(parent_constr->defval[i].adbin),
|
||||
ObjectIdGetDatum(parent_rel->rd_id)));
|
||||
break;
|
||||
}
|
||||
}
|
||||
Assert(parent_expr != NULL);
|
||||
|
||||
if (strcmp(child_expr, parent_expr) != 0)
|
||||
ereport(ERROR,
|
||||
(errcode(ERRCODE_DATATYPE_MISMATCH),
|
||||
errmsg("column \"%s\" in child table has a conflicting generation expression",
|
||||
attributeName)));
|
||||
}
|
||||
|
||||
/*
|
||||
* OK, bump the child column's inheritance count. (If we fail
|
||||
* later on, this change will just roll back.)
|
||||
|
Reference in New Issue
Block a user