diff --git a/src/backend/optimizer/util/clauses.c b/src/backend/optimizer/util/clauses.c index 21bf5dea9c3..8df369315bf 100644 --- a/src/backend/optimizer/util/clauses.c +++ b/src/backend/optimizer/util/clauses.c @@ -3716,6 +3716,52 @@ eval_const_expressions_mutator(Node *node, context); } break; + case T_ConvertRowtypeExpr: + { + ConvertRowtypeExpr *cre = castNode(ConvertRowtypeExpr, node); + Node *arg; + ConvertRowtypeExpr *newcre; + + arg = eval_const_expressions_mutator((Node *) cre->arg, + context); + + newcre = makeNode(ConvertRowtypeExpr); + newcre->resulttype = cre->resulttype; + newcre->convertformat = cre->convertformat; + newcre->location = cre->location; + + /* + * In case of a nested ConvertRowtypeExpr, we can convert the + * leaf row directly to the topmost row format without any + * intermediate conversions. (This works because + * ConvertRowtypeExpr is used only for child->parent + * conversion in inheritance trees, which works by exact match + * of column name, and a column absent in an intermediate + * result can't be present in the final result.) + * + * No need to check more than one level deep, because the + * above recursion will have flattened anything else. + */ + if (arg != NULL && IsA(arg, ConvertRowtypeExpr)) + { + ConvertRowtypeExpr *argcre = (ConvertRowtypeExpr *) arg; + + arg = (Node *) argcre->arg; + + /* + * Make sure an outer implicit conversion can't hide an + * inner explicit one. + */ + if (newcre->convertformat == COERCE_IMPLICIT_CAST) + newcre->convertformat = argcre->convertformat; + } + + newcre->arg = (Expr *) arg; + + if (arg != NULL && IsA(arg, Const)) + return ece_evaluate_expr((Node *) newcre); + return (Node *) newcre; + } default: break; } diff --git a/src/test/regress/expected/inherit.out b/src/test/regress/expected/inherit.out index d768e5df2c0..1e00c849f38 100644 --- a/src/test/regress/expected/inherit.out +++ b/src/test/regress/expected/inherit.out @@ -764,6 +764,8 @@ NOTICE: drop cascades to table c1 -- tables. See the pgsql-hackers thread beginning Dec. 4/04 create table base (i integer); create table derived () inherits (base); +create table more_derived (like derived, b int) inherits (derived); +NOTICE: merging column "i" with inherited definition insert into derived (i) values (0); select derived::base from derived; derived @@ -777,6 +779,22 @@ select NULL::derived::base; (1 row) +-- remove redundant conversions. +explain (verbose on, costs off) select row(i, b)::more_derived::derived::base from more_derived; + QUERY PLAN +------------------------------------------- + Seq Scan on public.more_derived + Output: (ROW(i, b)::more_derived)::base +(2 rows) + +explain (verbose on, costs off) select (1, 2)::more_derived::derived::base; + QUERY PLAN +----------------------- + Result + Output: '(1)'::base +(2 rows) + +drop table more_derived; drop table derived; drop table base; create table p1(ff1 int); diff --git a/src/test/regress/sql/inherit.sql b/src/test/regress/sql/inherit.sql index e8b6448f3c8..afc72f47bc8 100644 --- a/src/test/regress/sql/inherit.sql +++ b/src/test/regress/sql/inherit.sql @@ -237,9 +237,14 @@ drop table p1 cascade; -- tables. See the pgsql-hackers thread beginning Dec. 4/04 create table base (i integer); create table derived () inherits (base); +create table more_derived (like derived, b int) inherits (derived); insert into derived (i) values (0); select derived::base from derived; select NULL::derived::base; +-- remove redundant conversions. +explain (verbose on, costs off) select row(i, b)::more_derived::derived::base from more_derived; +explain (verbose on, costs off) select (1, 2)::more_derived::derived::base; +drop table more_derived; drop table derived; drop table base;