Movatterモバイル変換


[0]ホーム

URL:


Skip to content

Navigation Menu

Sign in
Appearance settings

Search code, repositories, users, issues, pull requests...

Provide feedback

We read every piece of feedback, and take your input very seriously.

Saved searches

Use saved searches to filter your results more quickly

Sign up
Appearance settings

Commit64387c5

Browse files
author
Etsuro Fujita
committed
postgres_fdw: Avoid 'variable not found in subplan target list' error.
The tlist of the EvalPlanQual outer plan for a ForeignScan node isadjusted to produce a tuple whose descriptor matches the scan tuple slotfor the ForeignScan node. But in the case where the outer plan containsan extra Sort node, if the new tlist contained columns required only forevaluating PlaceHolderVars or columns required only for evaluating localconditions, this would cause setrefs.c to fail with the error.The cause of this is that when creating the outer plan by injecting theSort node into an alternative local join plan that could emit such extracolumns as well, we fail to arrange for the outer plan to propagate themup through the Sort node, causing setrefs.c to fail to match up them inthe new tlist to what is available from the outer plan. Repair.Per report from Alexander Pyhalov.Richard Guo and Etsuro Fujita, reviewed by Alexander Pyhalov and Tom Lane.Backpatch to all supported versions.Discussion:http://postgr.es/m/cfb17bf6dfdf876467bd5ef533852d18%40postgrespro.ru
1 parentb3c630c commit64387c5

File tree

3 files changed

+141
-0
lines changed

3 files changed

+141
-0
lines changed

‎contrib/postgres_fdw/expected/postgres_fdw.out

Lines changed: 79 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -2451,6 +2451,85 @@ SELECT * FROM ft1, ft2, ft4, ft5, local_tbl WHERE ft1.c1 = ft2.c1 AND ft1.c2 = f
24512451

24522452
RESET enable_nestloop;
24532453
RESET enable_hashjoin;
2454+
-- test that add_paths_with_pathkeys_for_rel() arranges for the epq_path to
2455+
-- return columns needed by the parent ForeignScan node
2456+
EXPLAIN (VERBOSE, COSTS OFF)
2457+
SELECT * FROM local_tbl LEFT JOIN (SELECT ft1.*, COALESCE(ft1.c3 || ft2.c3, 'foobar') FROM ft1 INNER JOIN ft2 ON (ft1.c1 = ft2.c1 AND ft1.c1 < 100)) ss ON (local_tbl.c1 = ss.c1) ORDER BY local_tbl.c1 FOR UPDATE OF local_tbl;
2458+
QUERY PLAN
2459+
----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2460+
LockRows
2461+
Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)), local_tbl.ctid, ft1.*, ft2.*
2462+
-> Merge Left Join
2463+
Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)), local_tbl.ctid, ft1.*, ft2.*
2464+
Merge Cond: (local_tbl.c1 = ft1.c1)
2465+
-> Index Scan using local_tbl_pkey on public.local_tbl
2466+
Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2467+
-> Materialize
2468+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text))
2469+
-> Foreign Scan
2470+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)
2471+
Relations: (public.ft1) INNER JOIN (public.ft2)
2472+
Remote SQL: SELECT r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8) END, CASE WHEN (r5.*)::text IS NOT NULL THEN ROW(r5."C 1", r5.c2, r5.c3, r5.c4, r5.c5, r5.c6, r5.c7, r5.c8) END, r5.c3 FROM ("S 1"."T 1" r4 INNER JOIN "S 1"."T 1" r5 ON (((r4."C 1" = r5."C 1")) AND ((r4."C 1" < 100)))) ORDER BY r4."C 1" ASC NULLS LAST
2473+
-> Result
2474+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c3
2475+
-> Sort
2476+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, (COALESCE((ft1.c3 || ft2.c3), 'foobar'::text)), ft2.c3
2477+
Sort Key: ft1.c1
2478+
-> Hash Join
2479+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, COALESCE((ft1.c3 || ft2.c3), 'foobar'::text), ft2.c3
2480+
Hash Cond: (ft1.c1 = ft2.c1)
2481+
-> Foreign Scan on public.ft1
2482+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2483+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100))
2484+
-> Hash
2485+
Output: ft2.*, ft2.c1, ft2.c3
2486+
-> Foreign Scan on public.ft2
2487+
Output: ft2.*, ft2.c1, ft2.c3
2488+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1"
2489+
(29 rows)
2490+
2491+
ALTER SERVER loopback OPTIONS (DROP extensions);
2492+
ALTER SERVER loopback OPTIONS (ADD fdw_startup_cost '10000.0');
2493+
EXPLAIN (VERBOSE, COSTS OFF)
2494+
SELECT * FROM local_tbl LEFT JOIN (SELECT ft1.* FROM ft1 INNER JOIN ft2 ON (ft1.c1 = ft2.c1 AND ft1.c1 < 100 AND ft1.c1 = postgres_fdw_abs(ft2.c2))) ss ON (local_tbl.c3 = ss.c3) ORDER BY local_tbl.c1 FOR UPDATE OF local_tbl;
2495+
QUERY PLAN
2496+
-------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
2497+
LockRows
2498+
Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, local_tbl.ctid, ft1.*, ft2.*
2499+
-> Nested Loop Left Join
2500+
Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, local_tbl.ctid, ft1.*, ft2.*
2501+
Join Filter: (local_tbl.c3 = ft1.c3)
2502+
-> Index Scan using local_tbl_pkey on public.local_tbl
2503+
Output: local_tbl.c1, local_tbl.c2, local_tbl.c3, local_tbl.ctid
2504+
-> Materialize
2505+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*
2506+
-> Foreign Scan
2507+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*
2508+
Filter: (ft1.c1 = postgres_fdw_abs(ft2.c2))
2509+
Relations: (public.ft1) INNER JOIN (public.ft2)
2510+
Remote SQL: SELECT r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8, CASE WHEN (r4.*)::text IS NOT NULL THEN ROW(r4."C 1", r4.c2, r4.c3, r4.c4, r4.c5, r4.c6, r4.c7, r4.c8) END, CASE WHEN (r5.*)::text IS NOT NULL THEN ROW(r5."C 1", r5.c2, r5.c3, r5.c4, r5.c5, r5.c6, r5.c7, r5.c8) END, r5.c2 FROM ("S 1"."T 1" r4 INNER JOIN "S 1"."T 1" r5 ON (((r4."C 1" = r5."C 1")) AND ((r4."C 1" < 100)))) ORDER BY r4.c3 ASC NULLS LAST
2511+
-> Sort
2512+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c2
2513+
Sort Key: ft1.c3
2514+
-> Merge Join
2515+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*, ft2.*, ft2.c2
2516+
Merge Cond: ((ft1.c1 = (postgres_fdw_abs(ft2.c2))) AND (ft1.c1 = ft2.c1))
2517+
-> Sort
2518+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2519+
Sort Key: ft1.c1
2520+
-> Foreign Scan on public.ft1
2521+
Output: ft1.c1, ft1.c2, ft1.c3, ft1.c4, ft1.c5, ft1.c6, ft1.c7, ft1.c8, ft1.*
2522+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" WHERE (("C 1" < 100))
2523+
-> Sort
2524+
Output: ft2.*, ft2.c1, ft2.c2, (postgres_fdw_abs(ft2.c2))
2525+
Sort Key: (postgres_fdw_abs(ft2.c2)), ft2.c1
2526+
-> Foreign Scan on public.ft2
2527+
Output: ft2.*, ft2.c1, ft2.c2, postgres_fdw_abs(ft2.c2)
2528+
Remote SQL: SELECT "C 1", c2, c3, c4, c5, c6, c7, c8 FROM "S 1"."T 1" ORDER BY "C 1" ASC NULLS LAST
2529+
(32 rows)
2530+
2531+
ALTER SERVER loopback OPTIONS (DROP fdw_startup_cost);
2532+
ALTER SERVER loopback OPTIONS (ADD extensions 'postgres_fdw');
24542533
DROP TABLE local_tbl;
24552534
-- check join pushdown in situations where multiple userids are involved
24562535
CREATE ROLE regress_view_owner SUPERUSER;

‎contrib/postgres_fdw/postgres_fdw.c

Lines changed: 49 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -5792,6 +5792,55 @@ add_paths_with_pathkeys_for_rel(PlannerInfo *root, RelOptInfo *rel,
57925792

57935793
useful_pathkeys_list=get_useful_pathkeys_for_relation(root,rel);
57945794

5795+
/*
5796+
* Before creating sorted paths, arrange for the passed-in EPQ path, if
5797+
* any, to return columns needed by the parent ForeignScan node so that
5798+
* they will propagate up through Sort nodes injected below, if necessary.
5799+
*/
5800+
if (epq_path!=NULL&&useful_pathkeys_list!=NIL)
5801+
{
5802+
PgFdwRelationInfo*fpinfo= (PgFdwRelationInfo*)rel->fdw_private;
5803+
PathTarget*target=copy_pathtarget(epq_path->pathtarget);
5804+
5805+
/* Include columns required for evaluating PHVs in the tlist. */
5806+
add_new_columns_to_pathtarget(target,
5807+
pull_var_clause((Node*)target->exprs,
5808+
PVC_RECURSE_PLACEHOLDERS));
5809+
5810+
/* Include columns required for evaluating the local conditions. */
5811+
foreach(lc,fpinfo->local_conds)
5812+
{
5813+
RestrictInfo*rinfo=lfirst_node(RestrictInfo,lc);
5814+
5815+
add_new_columns_to_pathtarget(target,
5816+
pull_var_clause((Node*)rinfo->clause,
5817+
PVC_RECURSE_PLACEHOLDERS));
5818+
}
5819+
5820+
/*
5821+
* If we have added any new columns, adjust the tlist of the EPQ path.
5822+
*
5823+
* Note: the plan created using this path will only be used to execute
5824+
* EPQ checks, where accuracy of the plan cost and width estimates
5825+
* would not be important, so we do not do set_pathtarget_cost_width()
5826+
* for the new pathtarget here. See also postgresGetForeignPlan().
5827+
*/
5828+
if (list_length(target->exprs)>list_length(epq_path->pathtarget->exprs))
5829+
{
5830+
/* The EPQ path is a join path, so it is projection-capable. */
5831+
Assert(is_projection_capable_path(epq_path));
5832+
5833+
/*
5834+
* Use create_projection_path() here, so as to avoid modifying it
5835+
* in place.
5836+
*/
5837+
epq_path= (Path*)create_projection_path(root,
5838+
rel,
5839+
epq_path,
5840+
target);
5841+
}
5842+
}
5843+
57955844
/* Create one path for each set of pathkeys we found above. */
57965845
foreach(lc,useful_pathkeys_list)
57975846
{

‎contrib/postgres_fdw/sql/postgres_fdw.sql

Lines changed: 13 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -662,6 +662,19 @@ SELECT * FROM ft1, ft2, ft4, ft5, local_tbl WHERE ft1.c1 = ft2.c1 AND ft1.c2 = f
662662
ANDft1.c2=ft5.c1ANDft1.c2=local_tbl.c1ANDft1.c1<100ANDft2.c1<100 FORUPDATE;
663663
RESET enable_nestloop;
664664
RESET enable_hashjoin;
665+
666+
-- test that add_paths_with_pathkeys_for_rel() arranges for the epq_path to
667+
-- return columns needed by the parent ForeignScan node
668+
EXPLAIN (VERBOSE, COSTS OFF)
669+
SELECT*FROM local_tblLEFT JOIN (SELECT ft1.*, COALESCE(ft1.c3||ft2.c3,'foobar')FROM ft1INNER JOIN ft2ON (ft1.c1=ft2.c1ANDft1.c1<100)) ssON (local_tbl.c1=ss.c1)ORDER BYlocal_tbl.c1 FORUPDATE OF local_tbl;
670+
671+
ALTER SERVER loopback OPTIONS (DROP extensions);
672+
ALTER SERVER loopback OPTIONS (ADD fdw_startup_cost'10000.0');
673+
EXPLAIN (VERBOSE, COSTS OFF)
674+
SELECT*FROM local_tblLEFT JOIN (SELECT ft1.*FROM ft1INNER JOIN ft2ON (ft1.c1=ft2.c1ANDft1.c1<100ANDft1.c1= postgres_fdw_abs(ft2.c2))) ssON (local_tbl.c3=ss.c3)ORDER BYlocal_tbl.c1 FORUPDATE OF local_tbl;
675+
ALTER SERVER loopback OPTIONS (DROP fdw_startup_cost);
676+
ALTER SERVER loopback OPTIONS (ADD extensions'postgres_fdw');
677+
665678
DROPTABLE local_tbl;
666679

667680
-- check join pushdown in situations where multiple userids are involved

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp