Skip to content

Commit 2266cff

Browse files
committed
[SHRDM-762] extract info from foreign join
1 parent 53b3910 commit 2266cff

File tree

3 files changed

+126
-11
lines changed

3 files changed

+126
-11
lines changed

expected/aqo_fdw.out

Lines changed: 52 additions & 7 deletions
Original file line numberDiff line numberDiff line change
@@ -57,11 +57,6 @@ SELECT x FROM frgn;
5757
(5 rows)
5858

5959
-- Push down base filters. Use verbose mode to see filters.
60-
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE))
61-
SELECT x FROM frgn WHERE x < 10;
62-
ERROR: syntax error at or near ")"
63-
LINE 1: ...LAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE))
64-
^
6560
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
6661
SELECT x FROM frgn WHERE x < 10;
6762
QUERY PLAN
@@ -75,6 +70,19 @@ SELECT x FROM frgn WHERE x < 10;
7570
JOINS: 0
7671
(7 rows)
7772

73+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
74+
SELECT x FROM frgn WHERE x < 10;
75+
QUERY PLAN
76+
-----------------------------------------------------------
77+
Foreign Scan on public.frgn (actual rows=1 loops=1)
78+
AQO: rows=1, error=0%
79+
Output: x
80+
Remote SQL: SELECT x FROM public.local WHERE ((x < 10))
81+
Using aqo: true
82+
AQO mode: LEARN
83+
JOINS: 0
84+
(7 rows)
85+
7886
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
7987
SELECT x FROM frgn WHERE x < -10; -- AQO ignores constants
8088
QUERY PLAN
@@ -125,6 +133,39 @@ SELECT * FROM frgn AS a, frgn AS b WHERE a.x=b.x;
125133
JOINS: 0
126134
(8 rows)
127135

136+
CREATE TABLE local_a(aid int primary key, aval text);
137+
CREATE TABLE local_b(bid int primary key, aid int references local_a(aid), bval text);
138+
INSERT INTO local_a SELECT i, 'val_' || i FROM generate_series(1,100) i;
139+
INSERT INTO local_b SELECT i, mod((i+random()*10)::numeric, 10) + 1, 'val_' || i FROM generate_series(1,1000) i;
140+
ANALYZE local_a, local_b;
141+
CREATE FOREIGN TABLE frgn_a(aid int, aval text) SERVER loopback OPTIONS (table_name 'local_a');
142+
CREATE FOREIGN TABLE frgn_b(bid int, aid int, bval text) SERVER loopback OPTIONS (table_name 'local_b');
143+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
144+
SELECT * from frgn_a AS a, frgn_b AS b
145+
WHERE a.aid = b.aid AND b.bval like 'val%';
146+
QUERY PLAN
147+
-----------------------------------------------
148+
Foreign Scan (actual rows=1000 loops=1)
149+
AQO not used
150+
Relations: (frgn_a a) INNER JOIN (frgn_b b)
151+
Using aqo: true
152+
AQO mode: LEARN
153+
JOINS: 0
154+
(6 rows)
155+
156+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
157+
SELECT * from frgn_a AS a, frgn_b AS b
158+
WHERE a.aid = b.aid AND b.bval like 'val%';
159+
QUERY PLAN
160+
-----------------------------------------------
161+
Foreign Scan (actual rows=1000 loops=1)
162+
AQO: rows=1000, error=0%
163+
Relations: (frgn_a a) INNER JOIN (frgn_b b)
164+
Using aqo: true
165+
AQO mode: LEARN
166+
JOINS: 0
167+
(6 rows)
168+
128169
-- TODO: Non-mergejoinable join condition.
129170
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
130171
SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
@@ -143,7 +184,7 @@ SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
143184
QUERY PLAN
144185
--------------------------------------------------------------------------------------------------------
145186
Foreign Scan (actual rows=0 loops=1)
146-
AQO not used
187+
AQO: rows=1, error=100%
147188
Output: a.x, b.x
148189
Relations: (public.frgn a) INNER JOIN (public.frgn b)
149190
Remote SQL: SELECT r1.x, r2.x FROM (public.local r1 INNER JOIN public.local r2 ON (((r1.x < r2.x))))
@@ -154,8 +195,12 @@ SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
154195

155196
DROP EXTENSION aqo CASCADE;
156197
DROP EXTENSION postgres_fdw CASCADE;
157-
NOTICE: drop cascades to 3 other objects
198+
NOTICE: drop cascades to 5 other objects
158199
DETAIL: drop cascades to server loopback
159200
drop cascades to user mapping for public on server loopback
160201
drop cascades to foreign table frgn
202+
drop cascades to foreign table frgn_a
203+
drop cascades to foreign table frgn_b
161204
DROP TABLE local;
205+
DROP TABLE local_b;
206+
DROP TABLE local_a;

path_utils.c

Lines changed: 54 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -21,6 +21,7 @@
2121
#include "aqo.h"
2222
#include "hash.h"
2323

24+
#include "postgres_fdw.h"
2425

2526
/*
2627
* Hook on creation of a plan node. We need to store AQO-specific data to
@@ -56,6 +57,31 @@ create_aqo_plan_node()
5657
return node;
5758
}
5859

60+
61+
/* Ensure that it's postgres_fdw's foreign server oid */
62+
static bool
63+
is_postgres_fdw_server(Oid serverid)
64+
{
65+
ForeignServer *server;
66+
ForeignDataWrapper *fdw;
67+
68+
if (!OidIsValid(serverid))
69+
return false;
70+
71+
server = GetForeignServerExtended(serverid, FSV_MISSING_OK);
72+
if (!server)
73+
return false;
74+
75+
fdw = GetForeignDataWrapperExtended(server->fdwid, FDW_MISSING_OK);
76+
if (!fdw || !fdw->fdwname)
77+
return false;
78+
79+
if (strcmp(fdw->fdwname, "postgres_fdw") != 0)
80+
return false;
81+
82+
return true;
83+
}
84+
5985
/*
6086
* Extract an AQO node from the plan private field.
6187
* If no one node was found, return pointer to the default value or allocate new
@@ -415,7 +441,8 @@ aqo_create_plan_hook(PlannerInfo *root, Path *src, Plan **dest)
415441
return;
416442

417443
is_join_path = (src->type == T_NestPath || src->type == T_MergePath ||
418-
src->type == T_HashPath);
444+
src->type == T_HashPath ||
445+
(src->type == T_ForeignPath && IS_JOIN_REL(src->parent)));
419446

420447
node = get_aqo_plan_node(plan, true);
421448

@@ -431,8 +458,32 @@ aqo_create_plan_hook(PlannerInfo *root, Path *src, Plan **dest)
431458

432459
if (is_join_path)
433460
{
434-
node->clauses = aqo_get_clauses(root, ((JoinPath *) src)->joinrestrictinfo);
435-
node->jointype = ((JoinPath *) src)->jointype;
461+
if (IsA(src, ForeignPath))
462+
{
463+
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) src->parent->fdw_private;
464+
List *restrictclauses = NIL;
465+
466+
if (!fpinfo)
467+
return;
468+
469+
/* We have to ensure that this is postgres_fdw ForeignPath */
470+
if (!is_postgres_fdw_server(src->parent->serverid))
471+
return;
472+
473+
restrictclauses = list_concat(restrictclauses, fpinfo->joinclauses);
474+
restrictclauses = list_concat(restrictclauses, fpinfo->remote_conds);
475+
restrictclauses = list_concat(restrictclauses, fpinfo->local_conds);
476+
477+
node->clauses = aqo_get_clauses(root, restrictclauses);
478+
node->jointype = fpinfo->jointype;
479+
480+
list_free(restrictclauses);
481+
}
482+
else
483+
{
484+
node->clauses = aqo_get_clauses(root, ((JoinPath *) src)->joinrestrictinfo);
485+
node->jointype = ((JoinPath *) src)->jointype;
486+
}
436487
}
437488
else if (IsA(src, AggPath))
438489
/* Aggregation node must store grouping clauses. */

sql/aqo_fdw.sql

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -47,7 +47,7 @@ EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
4747
SELECT x FROM frgn;
4848

4949
-- Push down base filters. Use verbose mode to see filters.
50-
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE))
50+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
5151
SELECT x FROM frgn WHERE x < 10;
5252
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
5353
SELECT x FROM frgn WHERE x < 10;
@@ -62,6 +62,23 @@ SELECT * FROM frgn AS a, frgn AS b WHERE a.x=b.x;
6262
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
6363
SELECT * FROM frgn AS a, frgn AS b WHERE a.x=b.x;
6464

65+
CREATE TABLE local_a(aid int primary key, aval text);
66+
CREATE TABLE local_b(bid int primary key, aid int references local_a(aid), bval text);
67+
INSERT INTO local_a SELECT i, 'val_' || i FROM generate_series(1,100) i;
68+
INSERT INTO local_b SELECT i, mod((i+random()*10)::numeric, 10) + 1, 'val_' || i FROM generate_series(1,1000) i;
69+
ANALYZE local_a, local_b;
70+
71+
CREATE FOREIGN TABLE frgn_a(aid int, aval text) SERVER loopback OPTIONS (table_name 'local_a');
72+
CREATE FOREIGN TABLE frgn_b(bid int, aid int, bval text) SERVER loopback OPTIONS (table_name 'local_b');
73+
74+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
75+
SELECT * from frgn_a AS a, frgn_b AS b
76+
WHERE a.aid = b.aid AND b.bval like 'val%';
77+
78+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
79+
SELECT * from frgn_a AS a, frgn_b AS b
80+
WHERE a.aid = b.aid AND b.bval like 'val%';
81+
6582
-- TODO: Non-mergejoinable join condition.
6683
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
6784
SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
@@ -71,4 +88,6 @@ SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
7188
DROP EXTENSION aqo CASCADE;
7289
DROP EXTENSION postgres_fdw CASCADE;
7390
DROP TABLE local;
91+
DROP TABLE local_b;
92+
DROP TABLE local_a;
7493

0 commit comments

Comments
 (0)