mirror of
https://github.com/postgres/postgres.git
synced 2025-11-07 19:06:32 +03:00
Instead of supposing (wrongly, in the general case) that the rowtype
of an inheritance child table is binary-compatible with the rowtype of its parent, invent an expression node type that does the conversion correctly. Fixes the new bug exhibited by Kris Shannon as well as a lot of old bugs that would only show up when using multiple inheritance or after altering the parent table.
This commit is contained in:
@@ -16,7 +16,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.23 2004/08/29 05:06:44 momjian Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepjointree.c,v 1.24 2004/12/11 23:26:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -839,6 +839,13 @@ find_nonnullable_rels(Node *node, bool top_level)
|
||||
|
||||
result = find_nonnullable_rels((Node *) expr->arg, top_level);
|
||||
}
|
||||
else if (IsA(node, ConvertRowtypeExpr))
|
||||
{
|
||||
/* not clear this is useful, but it can't hurt */
|
||||
ConvertRowtypeExpr *expr = (ConvertRowtypeExpr *) node;
|
||||
|
||||
result = find_nonnullable_rels((Node *) expr->arg, top_level);
|
||||
}
|
||||
else if (IsA(node, NullTest))
|
||||
{
|
||||
NullTest *expr = (NullTest *) node;
|
||||
|
||||
@@ -14,7 +14,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.117 2004/10/02 22:39:47 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/prep/prepunion.c,v 1.118 2004/12/11 23:26:37 tgl Exp $
|
||||
*
|
||||
*-------------------------------------------------------------------------
|
||||
*/
|
||||
@@ -40,6 +40,8 @@ typedef struct
|
||||
{
|
||||
Index old_rt_index;
|
||||
Index new_rt_index;
|
||||
Oid old_rel_type;
|
||||
Oid new_rel_type;
|
||||
TupleDesc old_tupdesc;
|
||||
TupleDesc new_tupdesc;
|
||||
char *old_rel_name;
|
||||
@@ -826,6 +828,8 @@ adjust_inherited_attrs(Node *node,
|
||||
|
||||
context.old_rt_index = old_rt_index;
|
||||
context.new_rt_index = new_rt_index;
|
||||
context.old_rel_type = oldrelation->rd_rel->reltype;
|
||||
context.new_rel_type = newrelation->rd_rel->reltype;
|
||||
context.old_tupdesc = RelationGetDescr(oldrelation);
|
||||
context.new_tupdesc = RelationGetDescr(newrelation);
|
||||
context.old_rel_name = RelationGetRelationName(oldrelation);
|
||||
@@ -910,50 +914,6 @@ translate_inherited_attnum(AttrNumber old_attno,
|
||||
return 0; /* keep compiler quiet */
|
||||
}
|
||||
|
||||
/*
|
||||
* Translate a whole-row Var to be correct for a child table.
|
||||
*
|
||||
* In general the child will not have a suitable field layout to be used
|
||||
* directly, so we translate the simple whole-row Var into a ROW() construct.
|
||||
*/
|
||||
static Node *
|
||||
generate_whole_row(Var *var,
|
||||
adjust_inherited_attrs_context *context)
|
||||
{
|
||||
RowExpr *rowexpr;
|
||||
List *fields = NIL;
|
||||
int oldnatts = context->old_tupdesc->natts;
|
||||
int i;
|
||||
|
||||
for (i = 0; i < oldnatts; i++)
|
||||
{
|
||||
Form_pg_attribute att = context->old_tupdesc->attrs[i];
|
||||
Var *newvar;
|
||||
|
||||
if (att->attisdropped)
|
||||
{
|
||||
/*
|
||||
* can't use atttypid here, but it doesn't really matter what
|
||||
* type the Const claims to be.
|
||||
*/
|
||||
newvar = (Var *) makeNullConst(INT4OID);
|
||||
}
|
||||
else
|
||||
newvar = makeVar(context->new_rt_index,
|
||||
translate_inherited_attnum(i + 1, context),
|
||||
att->atttypid,
|
||||
att->atttypmod,
|
||||
0);
|
||||
fields = lappend(fields, newvar);
|
||||
}
|
||||
rowexpr = makeNode(RowExpr);
|
||||
rowexpr->args = fields;
|
||||
rowexpr->row_typeid = var->vartype; /* report parent's rowtype */
|
||||
rowexpr->row_format = COERCE_IMPLICIT_CAST;
|
||||
|
||||
return (Node *) rowexpr;
|
||||
}
|
||||
|
||||
static Node *
|
||||
adjust_inherited_attrs_mutator(Node *node,
|
||||
adjust_inherited_attrs_context *context)
|
||||
@@ -977,8 +937,22 @@ adjust_inherited_attrs_mutator(Node *node,
|
||||
}
|
||||
else if (var->varattno == 0)
|
||||
{
|
||||
/* expand whole-row reference into a ROW() construct */
|
||||
return generate_whole_row(var, context);
|
||||
/*
|
||||
* Whole-row Var: we need to insert a coercion step to convert
|
||||
* the tuple layout to the parent's rowtype.
|
||||
*/
|
||||
if (context->old_rel_type != context->new_rel_type)
|
||||
{
|
||||
ConvertRowtypeExpr *r = makeNode(ConvertRowtypeExpr);
|
||||
|
||||
r->arg = (Expr *) var;
|
||||
r->resulttype = context->old_rel_type;
|
||||
r->convertformat = COERCE_IMPLICIT_CAST;
|
||||
/* Make sure the Var node has the right type ID, too */
|
||||
Assert(var->vartype == context->old_rel_type);
|
||||
var->vartype = context->new_rel_type;
|
||||
return (Node *) r;
|
||||
}
|
||||
}
|
||||
/* system attributes don't need any translation */
|
||||
}
|
||||
|
||||
@@ -8,7 +8,7 @@
|
||||
*
|
||||
*
|
||||
* IDENTIFICATION
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.184 2004/11/09 21:42:53 tgl Exp $
|
||||
* $PostgreSQL: pgsql/src/backend/optimizer/util/clauses.c,v 1.185 2004/12/11 23:26:39 tgl Exp $
|
||||
*
|
||||
* HISTORY
|
||||
* AUTHOR DATE MAJOR EVENT
|
||||
@@ -1047,6 +1047,13 @@ strip_implicit_coercions(Node *node)
|
||||
if (r->relabelformat == COERCE_IMPLICIT_CAST)
|
||||
return strip_implicit_coercions((Node *) r->arg);
|
||||
}
|
||||
else if (IsA(node, ConvertRowtypeExpr))
|
||||
{
|
||||
ConvertRowtypeExpr *c = (ConvertRowtypeExpr *) node;
|
||||
|
||||
if (c->convertformat == COERCE_IMPLICIT_CAST)
|
||||
return strip_implicit_coercions((Node *) c->arg);
|
||||
}
|
||||
else if (IsA(node, CoerceToDomain))
|
||||
{
|
||||
CoerceToDomain *c = (CoerceToDomain *) node;
|
||||
@@ -1082,11 +1089,13 @@ set_coercionform_dontcare_walker(Node *node, void *context)
|
||||
return false;
|
||||
if (IsA(node, FuncExpr))
|
||||
((FuncExpr *) node)->funcformat = COERCE_DONTCARE;
|
||||
if (IsA(node, RelabelType))
|
||||
else if (IsA(node, RelabelType))
|
||||
((RelabelType *) node)->relabelformat = COERCE_DONTCARE;
|
||||
if (IsA(node, RowExpr))
|
||||
else if (IsA(node, ConvertRowtypeExpr))
|
||||
((ConvertRowtypeExpr *) node)->convertformat = COERCE_DONTCARE;
|
||||
else if (IsA(node, RowExpr))
|
||||
((RowExpr *) node)->row_format = COERCE_DONTCARE;
|
||||
if (IsA(node, CoerceToDomain))
|
||||
else if (IsA(node, CoerceToDomain))
|
||||
((CoerceToDomain *) node)->coercionformat = COERCE_DONTCARE;
|
||||
return expression_tree_walker(node, set_coercionform_dontcare_walker,
|
||||
context);
|
||||
@@ -2647,6 +2656,8 @@ expression_tree_walker(Node *node,
|
||||
break;
|
||||
case T_RelabelType:
|
||||
return walker(((RelabelType *) node)->arg, context);
|
||||
case T_ConvertRowtypeExpr:
|
||||
return walker(((ConvertRowtypeExpr *) node)->arg, context);
|
||||
case T_CaseExpr:
|
||||
{
|
||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||
@@ -3057,6 +3068,16 @@ expression_tree_mutator(Node *node,
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_ConvertRowtypeExpr:
|
||||
{
|
||||
ConvertRowtypeExpr *convexpr = (ConvertRowtypeExpr *) node;
|
||||
ConvertRowtypeExpr *newnode;
|
||||
|
||||
FLATCOPY(newnode, convexpr, ConvertRowtypeExpr);
|
||||
MUTATE(newnode->arg, convexpr->arg, Expr *);
|
||||
return (Node *) newnode;
|
||||
}
|
||||
break;
|
||||
case T_CaseExpr:
|
||||
{
|
||||
CaseExpr *caseexpr = (CaseExpr *) node;
|
||||
|
||||
Reference in New Issue
Block a user