From 6dd34da6de14002f3a882b32c39f31e9a97f6797 Mon Sep 17 00:00:00 2001 From: amit Date: Tue, 12 Mar 2019 10:47:37 +0900 Subject: [PATCH v33 2/8] Add rowmark "junk" targetlist entries in query_planner We'd like to postpone adding inheritance children to query until query_planner has finished distributing quals to individual baserels, which means also delaying adding child row marks. As things stand today, which "junk" Vars to add to the targetlist for a given parent row mark is not clear until all the child row marks have been seen. So, we must delay adding "junk" Vars until the children are added. Since this changes the order in which expressions are added to the individual baserels' targetlists, so does the order of expressions in the Paths to scan them and Paths built on top of them. That is why there are regression test expected output changes. --- contrib/postgres_fdw/expected/postgres_fdw.out | 76 ++++++------- src/backend/optimizer/plan/planagg.c | 2 +- src/backend/optimizer/plan/planmain.c | 28 ++++- src/backend/optimizer/plan/planner.c | 21 ++-- src/backend/optimizer/prep/preptlist.c | 152 ++++++++++++++----------- src/include/optimizer/planmain.h | 2 +- src/include/optimizer/prep.h | 2 + src/test/regress/expected/with.out | 8 +- 8 files changed, 168 insertions(+), 123 deletions(-) diff --git a/contrib/postgres_fdw/expected/postgres_fdw.out b/contrib/postgres_fdw/expected/postgres_fdw.out index 42108bd3d4..c912e95fe1 100644 --- a/contrib/postgres_fdw/expected/postgres_fdw.out +++ b/contrib/postgres_fdw/expected/postgres_fdw.out @@ -5577,25 +5577,25 @@ UPDATE ft2 SET c3 = 'baz' Output: ft2.c1, ft2.c2, ft2.c3, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3 Remote SQL: UPDATE "S 1"."T 1" SET c3 = $2 WHERE ctid = $1 RETURNING "C 1", c2, c3, c4, c5, c6, c7, c8 -> Nested Loop - Output: ft2.c1, ft2.c2, NULL::integer, 'baz'::text, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.ctid, ft4.*, ft5.*, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3 + Output: ft2.c1, ft2.c2, NULL::integer, 'baz'::text, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.ctid, ft4.c1, ft4.c2, ft4.c3, ft5.c1, ft5.c2, ft5.c3, ft4.*, ft5.* Join Filter: (ft2.c2 === ft4.c1) -> Foreign Scan on public.ft2 Output: ft2.c1, ft2.c2, ft2.c4, ft2.c5, ft2.c6, ft2.c7, ft2.c8, ft2.ctid Remote SQL: SELECT "C 1", c2, c4, c5, c6, c7, c8, ctid FROM "S 1"."T 1" WHERE (("C 1" > 2000)) FOR UPDATE -> Foreign Scan - Output: ft4.*, ft4.c1, ft4.c2, ft4.c3, ft5.*, ft5.c1, ft5.c2, ft5.c3 + Output: ft4.c1, ft4.c2, ft4.c3, ft4.*, ft5.c1, ft5.c2, ft5.c3, ft5.* Relations: (public.ft4) INNER JOIN (public.ft5) - Remote SQL: SELECT CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2.c1, r2.c2, r2.c3) END, r2.c1, r2.c2, r2.c3, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END, r3.c1, r3.c2, r3.c3 FROM ("S 1"."T 3" r2 INNER JOIN "S 1"."T 4" r3 ON (((r2.c1 = r3.c1)))) + Remote SQL: SELECT r2.c1, r2.c2, r2.c3, CASE WHEN (r2.*)::text IS NOT NULL THEN ROW(r2.c1, r2.c2, r2.c3) END, r3.c1, r3.c2, r3.c3, CASE WHEN (r3.*)::text IS NOT NULL THEN ROW(r3.c1, r3.c2, r3.c3) END FROM ("S 1"."T 3" r2 INNER JOIN "S 1"."T 4" r3 ON (((r2.c1 = r3.c1)))) -> Hash Join - Output: ft4.*, ft4.c1, ft4.c2, ft4.c3, ft5.*, ft5.c1, ft5.c2, ft5.c3 + Output: ft4.c1, ft4.c2, ft4.c3, ft4.*, ft5.c1, ft5.c2, ft5.c3, ft5.* Hash Cond: (ft4.c1 = ft5.c1) -> Foreign Scan on public.ft4 - Output: ft4.*, ft4.c1, ft4.c2, ft4.c3 + Output: ft4.c1, ft4.c2, ft4.c3, ft4.* Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3" -> Hash - Output: ft5.*, ft5.c1, ft5.c2, ft5.c3 + Output: ft5.c1, ft5.c2, ft5.c3, ft5.* -> Foreign Scan on public.ft5 - Output: ft5.*, ft5.c1, ft5.c2, ft5.c3 + Output: ft5.c1, ft5.c2, ft5.c3, ft5.* Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4" (24 rows) @@ -5626,16 +5626,16 @@ DELETE FROM ft2 -> Nested Loop Output: ft2.ctid, ft4.*, ft5.*, ft4.c1, ft5.c1 -> Nested Loop - Output: ft2.ctid, ft4.*, ft4.c1 + Output: ft2.ctid, ft4.c1, ft4.* Join Filter: (ft2.c2 = ft4.c1) -> Foreign Scan on public.ft2 Output: ft2.ctid, ft2.c2 Remote SQL: SELECT c2, ctid FROM "S 1"."T 1" WHERE (("C 1" > 2000)) FOR UPDATE -> Foreign Scan on public.ft4 - Output: ft4.*, ft4.c1 + Output: ft4.c1, ft4.* Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 3" -> Foreign Scan on public.ft5 - Output: ft5.*, ft5.c1 + Output: ft5.c1, ft5.* Remote SQL: SELECT c1, c2, c3 FROM "S 1"."T 4" (22 rows) @@ -7128,15 +7128,15 @@ select * from bar where f1 in (select f1 from foo) for update; Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 (23 rows) @@ -7166,15 +7166,15 @@ select * from bar where f1 in (select f1 from foo) for share; Output: bar2.f1, bar2.f2, bar2.ctid, bar2.*, bar2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR SHARE -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 (23 rows) @@ -7203,15 +7203,15 @@ update bar set f2 = f2 + 100 where f1 in (select f1 from foo); -> Seq Scan on public.bar Output: bar.f1, bar.f2, bar.ctid -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 -> Hash Join Output: bar2.f1, (bar2.f2 + 100), bar2.f3, bar2.ctid, foo.ctid, foo.*, foo.tableoid @@ -7221,15 +7221,15 @@ update bar set f2 = f2 + 100 where f1 in (select f1 from foo); Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE -> Hash - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> HashAggregate - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid Group Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: foo.ctid, foo.*, foo.tableoid, foo.f1 + Output: foo.f1, foo.ctid, foo.*, foo.tableoid -> Foreign Scan on public.foo2 - Output: foo2.ctid, foo2.*, foo2.tableoid, foo2.f1 + Output: foo2.f1, foo2.ctid, foo2.*, foo2.tableoid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct1 (39 rows) @@ -7262,14 +7262,14 @@ where bar.f1 = ss.f1; Hash Cond: (foo.f1 = bar.f1) -> Append -> Seq Scan on public.foo - Output: ROW(foo.f1), foo.f1 + Output: foo.f1, ROW(foo.f1) -> Foreign Scan on public.foo2 - Output: ROW(foo2.f1), foo2.f1 + Output: foo2.f1, ROW(foo2.f1) Remote SQL: SELECT f1 FROM public.loct1 -> Seq Scan on public.foo foo_1 - Output: ROW((foo_1.f1 + 3)), (foo_1.f1 + 3) + Output: (foo_1.f1 + 3), ROW((foo_1.f1 + 3)) -> Foreign Scan on public.foo2 foo2_1 - Output: ROW((foo2_1.f1 + 3)), (foo2_1.f1 + 3) + Output: (foo2_1.f1 + 3), ROW((foo2_1.f1 + 3)) Remote SQL: SELECT f1 FROM public.loct1 -> Hash Output: bar.f1, bar.f2, bar.ctid @@ -7285,18 +7285,18 @@ where bar.f1 = ss.f1; Output: bar2.f1, bar2.f2, bar2.f3, bar2.ctid Remote SQL: SELECT f1, f2, f3, ctid FROM public.loct2 FOR UPDATE -> Sort - Output: (ROW(foo.f1)), foo.f1 + Output: foo.f1, (ROW(foo.f1)) Sort Key: foo.f1 -> Append -> Seq Scan on public.foo - Output: ROW(foo.f1), foo.f1 + Output: foo.f1, ROW(foo.f1) -> Foreign Scan on public.foo2 - Output: ROW(foo2.f1), foo2.f1 + Output: foo2.f1, ROW(foo2.f1) Remote SQL: SELECT f1 FROM public.loct1 -> Seq Scan on public.foo foo_1 - Output: ROW((foo_1.f1 + 3)), (foo_1.f1 + 3) + Output: (foo_1.f1 + 3), ROW((foo_1.f1 + 3)) -> Foreign Scan on public.foo2 foo2_1 - Output: ROW((foo2_1.f1 + 3)), (foo2_1.f1 + 3) + Output: (foo2_1.f1 + 3), ROW((foo2_1.f1 + 3)) Remote SQL: SELECT f1 FROM public.loct1 (45 rows) @@ -7559,12 +7559,12 @@ update parent set b = parent.b || remt2.b from remt2 where parent.a = remt2.a re Update on public.parent Foreign Update on public.remt1 -> Nested Loop - Output: parent.a, (parent.b || remt2.b), parent.ctid, remt2.*, remt2.a, remt2.b + Output: parent.a, (parent.b || remt2.b), parent.ctid, remt2.a, remt2.b, remt2.* Join Filter: (parent.a = remt2.a) -> Seq Scan on public.parent Output: parent.a, parent.b, parent.ctid -> Foreign Scan on public.remt2 - Output: remt2.b, remt2.*, remt2.a + Output: remt2.b, remt2.a, remt2.* Remote SQL: SELECT a, b FROM public.loct2 -> Foreign Update Remote SQL: UPDATE public.loct1 r4 SET b = (r4.b || r2.b) FROM public.loct2 r2 WHERE ((r4.a = r2.a)) RETURNING r4.a, r4.b, r2.a, r2.b @@ -7591,7 +7591,7 @@ delete from parent using remt2 where parent.a = remt2.a returning parent; -> Seq Scan on public.parent Output: parent.ctid, parent.a -> Foreign Scan on public.remt2 - Output: remt2.*, remt2.a + Output: remt2.a, remt2.* Remote SQL: SELECT a, b FROM public.loct2 -> Foreign Delete Remote SQL: DELETE FROM public.loct1 r4 USING public.loct2 r2 WHERE ((r4.a = r2.a)) RETURNING r4.a, r4.b diff --git a/src/backend/optimizer/plan/planagg.c b/src/backend/optimizer/plan/planagg.c index 86617099df..0e819a6e92 100644 --- a/src/backend/optimizer/plan/planagg.c +++ b/src/backend/optimizer/plan/planagg.c @@ -442,7 +442,7 @@ build_minmax_path(PlannerInfo *root, MinMaxAggInfo *mminfo, subroot->tuple_fraction = 1.0; subroot->limit_tuples = 1.0; - final_rel = query_planner(subroot, tlist, minmax_qp_callback, NULL); + final_rel = query_planner(subroot, &tlist, minmax_qp_callback, NULL); /* * Since we didn't go through subquery_planner() to handle the subquery, diff --git a/src/backend/optimizer/plan/planmain.c b/src/backend/optimizer/plan/planmain.c index 03c81772a3..42c2130096 100644 --- a/src/backend/optimizer/plan/planmain.c +++ b/src/backend/optimizer/plan/planmain.c @@ -29,6 +29,7 @@ #include "optimizer/paths.h" #include "optimizer/placeholder.h" #include "optimizer/planmain.h" +#include "optimizer/prep.h" /* @@ -42,7 +43,8 @@ * (grouping_planner) can choose among the surviving paths for the rel. * * root describes the query to plan - * tlist is the target list the query should produce + * *tlist is the target list the query should produce (passed in as an output + * variable, because more entries may be added to it) * (this is NOT necessarily root->parse->targetList!) * qp_callback is a function to compute query_pathkeys once it's safe to do so * qp_extra is optional extra data to pass to qp_callback @@ -54,7 +56,7 @@ * (We cannot construct canonical pathkeys until that's done.) */ RelOptInfo * -query_planner(PlannerInfo *root, List *tlist, +query_planner(PlannerInfo *root, List **tlist, query_pathkeys_callback qp_callback, void *qp_extra) { Query *parse = root->parse; @@ -179,7 +181,7 @@ query_planner(PlannerInfo *root, List *tlist, * restrictions. Finally, we form a target joinlist for make_one_rel() to * work from. */ - build_base_rel_tlists(root, tlist); + build_base_rel_tlists(root, *tlist); find_placeholders_in_jointree(root); @@ -211,6 +213,26 @@ query_planner(PlannerInfo *root, List *tlist, add_other_rels_to_query(root, (Node *) root->parse->jointree); /* + * root->rowMarks should contain all row marks at this point, including + * child row marks if any, so add "junk" Vars to the targetlist based on + * the "parent" row marks. + */ + if (root->rowMarks) + { + List *junk_vars; + + /* More entries will added to *tlist. */ + add_rowmark_junk_vars_to_targetlist(root, tlist, &junk_vars); + Assert(junk_vars != NIL); + + /* + * There can't be any PlaceHolderVars in junk_vars, so pass false for + * 'create_new_ph'. + */ + add_vars_to_targetlist(root, junk_vars, bms_make_singleton(0), false); + } + + /* * We have completed merging equivalence sets, so it's now possible to * generate pathkeys in canonical form; so compute query_pathkeys and * other pathkeys fields in PlannerInfo. diff --git a/src/backend/optimizer/plan/planner.c b/src/backend/optimizer/plan/planner.c index e408e77d6f..abac84bcaa 100644 --- a/src/backend/optimizer/plan/planner.c +++ b/src/backend/optimizer/plan/planner.c @@ -25,6 +25,7 @@ #include "access/table.h" #include "access/xact.h" #include "catalog/pg_constraint.h" +#include "catalog/pg_inherits.h" #include "catalog/pg_proc.h" #include "catalog/pg_type.h" #include "executor/executor.h" @@ -1835,15 +1836,6 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, tlist = preprocess_targetlist(root); /* - * We are now done hacking up the query's targetlist. Most of the - * remaining planning work will be done with the PathTarget - * representation of tlists, but save aside the full representation so - * that we can transfer its decoration (resnames etc) to the topmost - * tlist of the finished Plan. - */ - root->processed_tlist = tlist; - - /* * Collect statistics about aggregates for estimating costs, and mark * all the aggregates with resolved aggtranstypes. We must do this * before slicing and dicing the tlist into various pathtargets, else @@ -1921,10 +1913,19 @@ grouping_planner(PlannerInfo *root, bool inheritance_update, * We also generate (in standard_qp_callback) pathkey representations * of the query's sort clause, distinct clause, etc. */ - current_rel = query_planner(root, tlist, + current_rel = query_planner(root, &tlist, standard_qp_callback, &qp_extra); /* + * We are now done hacking up the query's targetlist. Most of the + * remaining planning work will be done with the PathTarget + * representation of tlists, but save aside the full representation so + * that we can transfer its decoration (resnames etc) to the topmost + * tlist of the finished Plan. + */ + root->processed_tlist = tlist; + + /* * Convert the query's result tlist into PathTarget format. * * Note: it's desirable to not do this till after query_planner(), diff --git a/src/backend/optimizer/prep/preptlist.c b/src/backend/optimizer/prep/preptlist.c index 5392d1a561..1165382e82 100644 --- a/src/backend/optimizer/prep/preptlist.c +++ b/src/backend/optimizer/prep/preptlist.c @@ -76,7 +76,6 @@ preprocess_targetlist(PlannerInfo *root) RangeTblEntry *target_rte = NULL; Relation target_relation = NULL; List *tlist; - ListCell *lc; /* * If there is a result relation, open it so we can look for missing @@ -119,71 +118,6 @@ preprocess_targetlist(PlannerInfo *root) result_relation, target_relation); /* - * Add necessary junk columns for rowmarked rels. These values are needed - * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual - * rechecking. See comments for PlanRowMark in plannodes.h. - */ - foreach(lc, root->rowMarks) - { - PlanRowMark *rc = (PlanRowMark *) lfirst(lc); - Var *var; - char resname[32]; - TargetEntry *tle; - - /* child rels use the same junk attrs as their parents */ - if (rc->rti != rc->prti) - continue; - - if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY)) - { - /* Need to fetch TID */ - var = makeVar(rc->rti, - SelfItemPointerAttributeNumber, - TIDOID, - -1, - InvalidOid, - 0); - snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId); - tle = makeTargetEntry((Expr *) var, - list_length(tlist) + 1, - pstrdup(resname), - true); - tlist = lappend(tlist, tle); - } - if (rc->allMarkTypes & (1 << ROW_MARK_COPY)) - { - /* Need the whole row as a junk var */ - var = makeWholeRowVar(rt_fetch(rc->rti, range_table), - rc->rti, - 0, - false); - snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId); - tle = makeTargetEntry((Expr *) var, - list_length(tlist) + 1, - pstrdup(resname), - true); - tlist = lappend(tlist, tle); - } - - /* If parent of inheritance tree, always fetch the tableoid too. */ - if (rc->isParent) - { - var = makeVar(rc->rti, - TableOidAttributeNumber, - OIDOID, - -1, - InvalidOid, - 0); - snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId); - tle = makeTargetEntry((Expr *) var, - list_length(tlist) + 1, - pstrdup(resname), - true); - tlist = lappend(tlist, tle); - } - } - - /* * If the query has a RETURNING list, add resjunk entries for any Vars * used in RETURNING that belong to other relations. We need to do this * to make these Vars available for the RETURNING calculation. Vars that @@ -434,3 +368,89 @@ get_plan_rowmark(List *rowmarks, Index rtindex) } return NULL; } + +/* + * add_rowmark_junk_vars_to_targetlist + * Add "junk" targetlist entries needed for applying row marks contained + * in root->rowMarks + * + * Vars that are added to the targetlist are also returned in *junk_vars for + * the caller's perusal. + */ +void +add_rowmark_junk_vars_to_targetlist(PlannerInfo *root, + List **tlist, List **junk_vars) +{ + List *range_table = root->parse->rtable; + ListCell *lc; + + *junk_vars = NIL; + + /* + * Add necessary junk columns for rowmarked rels. These values are needed + * for locking of rels selected FOR UPDATE/SHARE, and to do EvalPlanQual + * rechecking. See comments for PlanRowMark in plannodes.h. + */ + foreach(lc, root->rowMarks) + { + PlanRowMark *rc = (PlanRowMark *) lfirst(lc); + Var *var; + char resname[32]; + TargetEntry *tle; + + /* child rels use the same junk attrs as their parents */ + if (rc->rti != rc->prti) + continue; + + if (rc->allMarkTypes & ~(1 << ROW_MARK_COPY)) + { + /* Need to fetch TID */ + var = makeVar(rc->rti, + SelfItemPointerAttributeNumber, + TIDOID, + -1, + InvalidOid, + 0); + snprintf(resname, sizeof(resname), "ctid%u", rc->rowmarkId); + tle = makeTargetEntry((Expr *) var, + list_length(*tlist) + 1, + pstrdup(resname), + true); + *tlist = lappend(*tlist, tle); + *junk_vars = lappend(*junk_vars, var); + } + if (rc->allMarkTypes & (1 << ROW_MARK_COPY)) + { + /* Need the whole row as a junk var */ + var = makeWholeRowVar(rt_fetch(rc->rti, range_table), + rc->rti, + 0, + false); + snprintf(resname, sizeof(resname), "wholerow%u", rc->rowmarkId); + tle = makeTargetEntry((Expr *) var, + list_length(*tlist) + 1, + pstrdup(resname), + true); + *tlist = lappend(*tlist, tle); + *junk_vars = lappend(*junk_vars, var); + } + + /* For inheritance cases, always fetch the tableoid too. */ + if (rc->isParent) + { + var = makeVar(rc->rti, + TableOidAttributeNumber, + OIDOID, + -1, + InvalidOid, + 0); + snprintf(resname, sizeof(resname), "tableoid%u", rc->rowmarkId); + tle = makeTargetEntry((Expr *) var, + list_length(*tlist) + 1, + pstrdup(resname), + true); + *tlist = lappend(*tlist, tle); + *junk_vars = lappend(*junk_vars, var); + } + } +} diff --git a/src/include/optimizer/planmain.h b/src/include/optimizer/planmain.h index 035caac500..a21783192c 100644 --- a/src/include/optimizer/planmain.h +++ b/src/include/optimizer/planmain.h @@ -27,7 +27,7 @@ typedef void (*query_pathkeys_callback) (PlannerInfo *root, void *extra); /* * prototypes for plan/planmain.c */ -extern RelOptInfo *query_planner(PlannerInfo *root, List *tlist, +extern RelOptInfo *query_planner(PlannerInfo *root, List **tlist, query_pathkeys_callback qp_callback, void *qp_extra); /* diff --git a/src/include/optimizer/prep.h b/src/include/optimizer/prep.h index a9b2c9026c..cf7b3a9d06 100644 --- a/src/include/optimizer/prep.h +++ b/src/include/optimizer/prep.h @@ -37,6 +37,8 @@ extern Relids get_relids_for_join(Query *query, int joinrelid); extern List *preprocess_targetlist(PlannerInfo *root); extern PlanRowMark *get_plan_rowmark(List *rowmarks, Index rtindex); +extern void add_rowmark_junk_vars_to_targetlist(PlannerInfo *root, + List **tlist, List **junk_vars); /* * prototypes for prepunion.c diff --git a/src/test/regress/expected/with.out b/src/test/regress/expected/with.out index 2a2085556b..4f0a13dd0d 100644 --- a/src/test/regress/expected/with.out +++ b/src/test/regress/expected/with.out @@ -2199,28 +2199,28 @@ DELETE FROM a USING wcte WHERE aa = q2; -> Seq Scan on public.a Output: a.ctid, a.aa -> CTE Scan on wcte - Output: wcte.*, wcte.q2 + Output: wcte.q2, wcte.* -> Nested Loop Output: b.ctid, wcte.* Join Filter: (b.aa = wcte.q2) -> Seq Scan on public.b Output: b.ctid, b.aa -> CTE Scan on wcte - Output: wcte.*, wcte.q2 + Output: wcte.q2, wcte.* -> Nested Loop Output: c.ctid, wcte.* Join Filter: (c.aa = wcte.q2) -> Seq Scan on public.c Output: c.ctid, c.aa -> CTE Scan on wcte - Output: wcte.*, wcte.q2 + Output: wcte.q2, wcte.* -> Nested Loop Output: d.ctid, wcte.* Join Filter: (d.aa = wcte.q2) -> Seq Scan on public.d Output: d.ctid, d.aa -> CTE Scan on wcte - Output: wcte.*, wcte.q2 + Output: wcte.q2, wcte.* (38 rows) -- error cases -- 2.11.0