diff --git a/src/backend/rewrite/rewriteHandler.c b/src/backend/rewrite/rewriteHandler.c index 593c533b44..d769ccecb5 100644 --- a/src/backend/rewrite/rewriteHandler.c +++ b/src/backend/rewrite/rewriteHandler.c @@ -1461,7 +1461,6 @@ rewriteValuesRTEToNulls(Query *parsetree, RangeTblEntry *rte) List *newValues; ListCell *lc; - Assert(rte->rtekind == RTE_VALUES); newValues = NIL; foreach(lc, rte->values_lists) { @@ -3747,12 +3746,39 @@ RewriteQuery(Query *parsetree, List *rewrite_events, int orig_rt_length) /* * Each product query has its own copy of the VALUES RTE at the * same index in the rangetable, so we must finalize each one. + * + * Note that if the product query is an INSERT ... SELECT, then + * the VALUES RTE will be at the same index in the SELECT part of + * the product query rather than the top-level product query + * itself. */ foreach(n, product_queries) { Query *pt = (Query *) lfirst(n); - RangeTblEntry *values_rte = rt_fetch(values_rte_index, - pt->rtable); + RangeTblEntry *values_rte; + + if (pt->commandType == CMD_INSERT && + pt->jointree && IsA(pt->jointree, FromExpr) && + list_length(pt->jointree->fromlist) == 1) + { + Node *jtnode = (Node *) linitial(pt->jointree->fromlist); + + if (IsA(jtnode, RangeTblRef)) + { + int rtindex = ((RangeTblRef *) jtnode)->rtindex; + RangeTblEntry *src_rte = rt_fetch(rtindex, pt->rtable); + + if (src_rte->rtekind == RTE_SUBQUERY && + src_rte->subquery && + IsA(src_rte->subquery, Query) && + src_rte->subquery->commandType == CMD_SELECT) + pt = src_rte->subquery; + } + } + + values_rte = rt_fetch(values_rte_index, pt->rtable); + if (values_rte->rtekind != RTE_VALUES) + elog(ERROR, "failed to find VALUES RTE in product query"); rewriteValuesRTEToNulls(pt, values_rte); } diff --git a/src/backend/rewrite/rewriteManip.c b/src/backend/rewrite/rewriteManip.c index a727f41bde..506959b7b6 100644 --- a/src/backend/rewrite/rewriteManip.c +++ b/src/backend/rewrite/rewriteManip.c @@ -951,12 +951,15 @@ getInsertSelectQuery(Query *parsetree, Query ***subquery_ptr) if (list_length(parsetree->jointree->fromlist) != 1) elog(ERROR, "expected to find SELECT subquery"); rtr = (RangeTblRef *) linitial(parsetree->jointree->fromlist); - Assert(IsA(rtr, RangeTblRef)); - selectrte = rt_fetch(rtr->rtindex, parsetree->rtable); - selectquery = selectrte->subquery; - if (!(selectquery && IsA(selectquery, Query) && - selectquery->commandType == CMD_SELECT)) + if (!IsA(rtr, RangeTblRef)) elog(ERROR, "expected to find SELECT subquery"); + selectrte = rt_fetch(rtr->rtindex, parsetree->rtable); + if (!(selectrte->rtekind == RTE_SUBQUERY && + selectrte->subquery && + IsA(selectrte->subquery, Query) && + selectrte->subquery->commandType == CMD_SELECT)) + elog(ERROR, "expected to find SELECT subquery"); + selectquery = selectrte->subquery; if (list_length(selectquery->rtable) >= 2 && strcmp(rt_fetch(PRS2_OLD_VARNO, selectquery->rtable)->eref->aliasname, "old") == 0 && diff --git a/src/test/regress/expected/updatable_views.out b/src/test/regress/expected/updatable_views.out index 06f1e64d42..bb8c238964 100644 --- a/src/test/regress/expected/updatable_views.out +++ b/src/test/regress/expected/updatable_views.out @@ -3074,6 +3074,25 @@ select * from base_tab_def order by a, c NULLS LAST; | View default | | View default | (22 rows) +-- Test a DO ALSO INSERT ... SELECT rule +drop rule base_tab_def_view_ins_rule on base_tab_def_view; +create rule base_tab_def_view_ins_rule as on insert to base_tab_def_view + do also insert into base_tab_def (a, b, e) select new.a, new.b, 'xxx'; +truncate base_tab_def; +insert into base_tab_def_view values (1, default, default, default, default); +insert into base_tab_def_view values (2, default, default, default, default), + (3, default, default, default, default); +select * from base_tab_def order by a, e nulls first; + a | b | c | d | e +---+--------------+---------------+--------------+----- + 1 | View default | Table default | View default | + 1 | View default | Table default | | xxx + 2 | View default | Table default | View default | + 2 | View default | Table default | | xxx + 3 | View default | Table default | View default | + 3 | View default | Table default | | xxx +(6 rows) + drop view base_tab_def_view; drop table base_tab_def; -- Test defaults with array assignments diff --git a/src/test/regress/sql/updatable_views.sql b/src/test/regress/sql/updatable_views.sql index cc441b9c92..b3c09e890e 100644 --- a/src/test/regress/sql/updatable_views.sql +++ b/src/test/regress/sql/updatable_views.sql @@ -1537,6 +1537,16 @@ insert into base_tab_def_view values (15, default, default, default, default), insert into base_tab_def_view values (17), (default); select * from base_tab_def order by a, c NULLS LAST; +-- Test a DO ALSO INSERT ... SELECT rule +drop rule base_tab_def_view_ins_rule on base_tab_def_view; +create rule base_tab_def_view_ins_rule as on insert to base_tab_def_view + do also insert into base_tab_def (a, b, e) select new.a, new.b, 'xxx'; +truncate base_tab_def; +insert into base_tab_def_view values (1, default, default, default, default); +insert into base_tab_def_view values (2, default, default, default, default), + (3, default, default, default, default); +select * from base_tab_def order by a, e nulls first; + drop view base_tab_def_view; drop table base_tab_def;