diff options
| author | Tom Lane <tgl@sss.pgh.pa.us> | 2004-12-11 23:26:51 +0000 |
|---|---|---|
| committer | Tom Lane <tgl@sss.pgh.pa.us> | 2004-12-11 23:26:51 +0000 |
| commit | 12b1b5d837b5ce1c07ee3535e74e4cc3039063d6 (patch) | |
| tree | 1ef0ecc2ccfba9a8a33f0b20ef31533b499cbdba /src/backend/optimizer | |
| parent | fd536dd257b12a8b1abf8d744d8a3688e1db126b (diff) | |
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.
Diffstat (limited to 'src/backend/optimizer')
| -rw-r--r-- | src/backend/optimizer/prep/prepjointree.c | 9 | ||||
| -rw-r--r-- | src/backend/optimizer/prep/prepunion.c | 68 | ||||
| -rw-r--r-- | src/backend/optimizer/util/clauses.c | 29 |
3 files changed, 54 insertions, 52 deletions
diff --git a/src/backend/optimizer/prep/prepjointree.c b/src/backend/optimizer/prep/prepjointree.c index af53c4592cc..cd461d237f3 100644 --- a/src/backend/optimizer/prep/prepjointree.c +++ b/src/backend/optimizer/prep/prepjointree.c @@ -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; diff --git a/src/backend/optimizer/prep/prepunion.c b/src/backend/optimizer/prep/prepunion.c index ba1de1b8860..1f4753aa604 100644 --- a/src/backend/optimizer/prep/prepunion.c +++ b/src/backend/optimizer/prep/prepunion.c @@ -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 */ } diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 6bf9990ccf5..39a8c8c56fb 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -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; |
