Skip to content

Commit 58ea474

Browse files
pyhalovdanolivo
authored andcommitted
Extract info from a Foreign Join plan node.
1 parent fc80022 commit 58ea474

File tree

3 files changed

+116
-8
lines changed

3 files changed

+116
-8
lines changed

expected/aqo_fdw.out

Lines changed: 41 additions & 4 deletions
Original file line numberDiff line numberDiff line change
@@ -110,15 +110,15 @@ SELECT str FROM expln('
110110
JOINS: 0
111111
(6 rows)
112112

113-
-- TODO: Should learn on postgres_fdw nodes
113+
-- Should learn on postgres_fdw nodes
114114
SELECT str FROM expln('
115115
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
116116
SELECT * FROM frgn AS a, frgn AS b WHERE a.x=b.x;
117117
') AS str WHERE str NOT LIKE '%Query Identifier%';
118118
str
119119
--------------------------------------------------------------------------------------------------------
120120
Foreign Scan (actual rows=1 loops=1)
121-
AQO not used
121+
AQO: rows=1, error=0%
122122
Output: a.x, b.x
123123
Relations: (public.frgn a) INNER JOIN (public.frgn b)
124124
Remote SQL: SELECT r1.x, r2.x FROM (public.local r1 INNER JOIN public.local r2 ON (((r1.x = r2.x))))
@@ -127,6 +127,39 @@ SELECT str FROM expln('
127127
JOINS: 0
128128
(8 rows)
129129

130+
CREATE TABLE local_a(aid int primary key, aval text);
131+
CREATE TABLE local_b(bid int primary key, aid int references local_a(aid), bval text);
132+
INSERT INTO local_a SELECT i, 'val_' || i FROM generate_series(1,100) i;
133+
INSERT INTO local_b SELECT i, mod((i+random()*10)::numeric, 10) + 1, 'val_' || i FROM generate_series(1,1000) i;
134+
ANALYZE local_a, local_b;
135+
CREATE FOREIGN TABLE frgn_a(aid int, aval text) SERVER loopback OPTIONS (table_name 'local_a');
136+
CREATE FOREIGN TABLE frgn_b(bid int, aid int, bval text) SERVER loopback OPTIONS (table_name 'local_b');
137+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
138+
SELECT * from frgn_a AS a, frgn_b AS b
139+
WHERE a.aid = b.aid AND b.bval like 'val%';
140+
QUERY PLAN
141+
-----------------------------------------------
142+
Foreign Scan (actual rows=1000 loops=1)
143+
AQO not used
144+
Relations: (frgn_a a) INNER JOIN (frgn_b b)
145+
Using aqo: true
146+
AQO mode: LEARN
147+
JOINS: 0
148+
(6 rows)
149+
150+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
151+
SELECT * from frgn_a AS a, frgn_b AS b
152+
WHERE a.aid = b.aid AND b.bval like 'val%';
153+
QUERY PLAN
154+
-----------------------------------------------
155+
Foreign Scan (actual rows=1000 loops=1)
156+
AQO: rows=1000, error=0%
157+
Relations: (frgn_a a) INNER JOIN (frgn_b b)
158+
Using aqo: true
159+
AQO mode: LEARN
160+
JOINS: 0
161+
(6 rows)
162+
130163
-- TODO: Non-mergejoinable join condition.
131164
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
132165
SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
@@ -147,7 +180,7 @@ SELECT str FROM expln('
147180
str
148181
--------------------------------------------------------------------------------------------------------
149182
Foreign Scan (actual rows=0 loops=1)
150-
AQO not used
183+
AQO: rows=1, error=100%
151184
Output: a.x, b.x
152185
Relations: (public.frgn a) INNER JOIN (public.frgn b)
153186
Remote SQL: SELECT r1.x, r2.x FROM (public.local r1 INNER JOIN public.local r2 ON (((r1.x < r2.x))))
@@ -158,8 +191,12 @@ SELECT str FROM expln('
158191

159192
DROP EXTENSION aqo CASCADE;
160193
DROP EXTENSION postgres_fdw CASCADE;
161-
NOTICE: drop cascades to 3 other objects
194+
NOTICE: drop cascades to 5 other objects
162195
DETAIL: drop cascades to server loopback
163196
drop cascades to user mapping for public on server loopback
164197
drop cascades to foreign table frgn
198+
drop cascades to foreign table frgn_a
199+
drop cascades to foreign table frgn_b
165200
DROP TABLE local;
201+
DROP TABLE local_b;
202+
DROP TABLE local_a;

path_utils.c

Lines changed: 55 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -23,6 +23,8 @@
2323
#include "aqo.h"
2424
#include "hash.h"
2525

26+
#include "postgres_fdw.h"
27+
2628
/*
2729
* Hook on creation of a plan node. We need to store AQO-specific data to
2830
* support learning stage.
@@ -60,6 +62,31 @@ create_aqo_plan_node()
6062
return node;
6163
}
6264

65+
66+
/* Ensure that it's postgres_fdw's foreign server oid */
67+
static bool
68+
is_postgres_fdw_server(Oid serverid)
69+
{
70+
ForeignServer *server;
71+
ForeignDataWrapper *fdw;
72+
73+
if (!OidIsValid(serverid))
74+
return false;
75+
76+
server = GetForeignServerExtended(serverid, FSV_MISSING_OK);
77+
if (!server)
78+
return false;
79+
80+
fdw = GetForeignDataWrapperExtended(server->fdwid, FDW_MISSING_OK);
81+
if (!fdw || !fdw->fdwname)
82+
return false;
83+
84+
if (strcmp(fdw->fdwname, "postgres_fdw") != 0)
85+
return false;
86+
87+
return true;
88+
}
89+
6390
/*
6491
* Extract an AQO node from the plan private field.
6592
* If no one node was found, return pointer to the default value or return NULL.
@@ -497,7 +524,8 @@ aqo_create_plan_hook(PlannerInfo *root, Path *src, Plan **dest)
497524
return;
498525

499526
is_join_path = (src->type == T_NestPath || src->type == T_MergePath ||
500-
src->type == T_HashPath);
527+
src->type == T_HashPath ||
528+
(src->type == T_ForeignPath && IS_JOIN_REL(src->parent)));
501529

502530
node = get_aqo_plan_node(plan, true);
503531

@@ -513,8 +541,32 @@ aqo_create_plan_hook(PlannerInfo *root, Path *src, Plan **dest)
513541

514542
if (is_join_path)
515543
{
516-
node->clauses = aqo_get_clauses(root, ((JoinPath *) src)->joinrestrictinfo);
517-
node->jointype = ((JoinPath *) src)->jointype;
544+
if (IsA(src, ForeignPath))
545+
{
546+
PgFdwRelationInfo *fpinfo = (PgFdwRelationInfo *) src->parent->fdw_private;
547+
List *restrictclauses = NIL;
548+
549+
if (!fpinfo)
550+
return;
551+
552+
/* We have to ensure that this is postgres_fdw ForeignPath */
553+
if (!is_postgres_fdw_server(src->parent->serverid))
554+
return;
555+
556+
restrictclauses = list_concat(restrictclauses, fpinfo->joinclauses);
557+
restrictclauses = list_concat(restrictclauses, fpinfo->remote_conds);
558+
restrictclauses = list_concat(restrictclauses, fpinfo->local_conds);
559+
560+
node->clauses = aqo_get_clauses(root, restrictclauses);
561+
node->jointype = fpinfo->jointype;
562+
563+
list_free(restrictclauses);
564+
}
565+
else
566+
{
567+
node->clauses = aqo_get_clauses(root, ((JoinPath *) src)->joinrestrictinfo);
568+
node->jointype = ((JoinPath *) src)->jointype;
569+
}
518570
}
519571
else if (IsA(src, AggPath))
520572
/* Aggregation node must store grouping clauses. */

sql/aqo_fdw.sql

Lines changed: 20 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -61,12 +61,29 @@ SELECT str FROM expln('
6161
SELECT * FROM frgn AS a, frgn AS b WHERE a.x=b.x;
6262
') AS str WHERE str NOT LIKE '%Sort Method%';
6363

64-
-- TODO: Should learn on postgres_fdw nodes
64+
-- Should learn on postgres_fdw nodes
6565
SELECT str FROM expln('
6666
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE)
6767
SELECT * FROM frgn AS a, frgn AS b WHERE a.x=b.x;
6868
') AS str WHERE str NOT LIKE '%Query Identifier%';
6969

70+
CREATE TABLE local_a(aid int primary key, aval text);
71+
CREATE TABLE local_b(bid int primary key, aid int references local_a(aid), bval text);
72+
INSERT INTO local_a SELECT i, 'val_' || i FROM generate_series(1,100) i;
73+
INSERT INTO local_b SELECT i, mod((i+random()*10)::numeric, 10) + 1, 'val_' || i FROM generate_series(1,1000) i;
74+
ANALYZE local_a, local_b;
75+
76+
CREATE FOREIGN TABLE frgn_a(aid int, aval text) SERVER loopback OPTIONS (table_name 'local_a');
77+
CREATE FOREIGN TABLE frgn_b(bid int, aid int, bval text) SERVER loopback OPTIONS (table_name 'local_b');
78+
79+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
80+
SELECT * from frgn_a AS a, frgn_b AS b
81+
WHERE a.aid = b.aid AND b.bval like 'val%';
82+
83+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
84+
SELECT * from frgn_a AS a, frgn_b AS b
85+
WHERE a.aid = b.aid AND b.bval like 'val%';
86+
7087
-- TODO: Non-mergejoinable join condition.
7188
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF)
7289
SELECT * FROM frgn AS a, frgn AS b WHERE a.x<b.x;
@@ -78,4 +95,6 @@ SELECT str FROM expln('
7895
DROP EXTENSION aqo CASCADE;
7996
DROP EXTENSION postgres_fdw CASCADE;
8097
DROP TABLE local;
98+
DROP TABLE local_b;
99+
DROP TABLE local_a;
81100

0 commit comments

Comments
 (0)
pFad - Phonifier reborn

Pfad - The Proxy pFad of © 2024 Garber Painting. All rights reserved.

Note: This service is not intended for secure transactions such as banking, social media, email, or purchasing. Use at your own risk. We assume no liability whatsoever for broken pages.


Alternative Proxies:

Alternative Proxy

pFad Proxy

pFad v3 Proxy

pFad v4 Proxy