Skip to content

Commit 2db2a3c

Browse files
committed
Add basic regression test on FDW support.
Switch from AQO_EXPLAIN define to the two user GUCS: aqo.show_details and aqo.show_hash. New ExplainOneNode hook allows to add info into explain of each node. The changes concern the core and the extension.
1 parent 8683934 commit 2db2a3c

File tree

8 files changed

+256
-82
lines changed

8 files changed

+256
-82
lines changed

Makefile

Lines changed: 2 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -14,11 +14,13 @@ REGRESS = aqo_disabled \
1414
aqo_forced \
1515
aqo_learn \
1616
schema \
17+
aqo_fdw \
1718
aqo_CVE-2020-14350
1819

1920
fdw_srcdir = $(top_srcdir)/contrib/postgres_fdw
2021
PG_CPPFLAGS += -I$(libpq_srcdir) -I$(fdw_srcdir)
2122
EXTRA_REGRESS_OPTS=--temp-config=$(top_srcdir)/$(subdir)/conf.add
23+
EXTRA_INSTALL = contrib/postgres_fdw
2224

2325
DATA = aqo--1.0.sql aqo--1.0--1.1.sql aqo--1.1--1.2.sql aqo--1.2.sql
2426

aqo.c

Lines changed: 32 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -18,6 +18,8 @@ void _PG_init(void);
1818
/* Strategy of determining feature space for new queries. */
1919
int aqo_mode;
2020
bool force_collect_stat;
21+
bool aqo_show_hash;
22+
bool aqo_details;
2123

2224
/* GUC variables */
2325
static const struct config_enum_entry format_options[] = {
@@ -83,6 +85,7 @@ set_joinrel_size_estimates_hook_type prev_set_joinrel_size_estimates_hook;
8385
get_parameterized_joinrel_size_hook_type prev_get_parameterized_joinrel_size_hook;
8486
copy_generic_path_info_hook_type prev_copy_generic_path_info_hook;
8587
ExplainOnePlan_hook_type prev_ExplainOnePlan_hook;
88+
ExplainOneNode_hook_type prev_ExplainOneNode_hook;
8689

8790
/*****************************************************************************
8891
*
@@ -116,7 +119,33 @@ _PG_init(void)
116119
NULL,
117120
NULL,
118121
NULL
119-
);
122+
);
123+
124+
DefineCustomBoolVariable(
125+
"aqo.show_hash",
126+
"Show query and node hash on explain.",
127+
"Hash value depend on each instance and is not good to enable it in regression or TAP tests.",
128+
&aqo_show_hash,
129+
false,
130+
PGC_USERSET,
131+
0,
132+
NULL,
133+
NULL,
134+
NULL
135+
);
136+
137+
DefineCustomBoolVariable(
138+
"aqo.show_details",
139+
"Show AQO state on a query.",
140+
NULL,
141+
&aqo_details,
142+
false,
143+
PGC_USERSET,
144+
0,
145+
NULL,
146+
NULL,
147+
NULL
148+
);
120149

121150
prev_planner_hook = planner_hook;
122151
planner_hook = aqo_planner;
@@ -139,6 +168,8 @@ _PG_init(void)
139168
copy_generic_path_info_hook = aqo_copy_generic_path_info;
140169
prev_ExplainOnePlan_hook = ExplainOnePlan_hook;
141170
ExplainOnePlan_hook = print_into_explain;
171+
prev_ExplainOneNode_hook = ExplainOneNode_hook;
172+
ExplainOneNode_hook = print_node_explain;
142173
parampathinfo_postinit_hook = ppi_hook;
143174

144175
init_deactivated_queries_storage();

aqo.h

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -174,6 +174,8 @@ typedef enum
174174

175175
extern int aqo_mode;
176176
extern bool force_collect_stat;
177+
extern bool aqo_show_hash;
178+
extern bool aqo_details;
177179

178180
/*
179181
* It is mostly needed for auto tuning of query. with auto tuning mode aqo
@@ -311,6 +313,10 @@ void print_into_explain(PlannedStmt *plannedstmt, IntoClause *into,
311313
ExplainState *es, const char *queryString,
312314
ParamListInfo params, const instr_time *planduration,
313315
QueryEnvironment *queryEnv);
316+
extern void print_node_explain(ExplainState *es,
317+
PlanState *ps,
318+
Plan *plan,
319+
double rows);
314320
void disable_aqo_for_query(void);
315321

316322
/* Cardinality estimation hooks */

aqo_pg12.patch

Lines changed: 18 additions & 37 deletions
Original file line numberDiff line numberDiff line change
@@ -11,7 +11,7 @@ index 92184ed487..ac8abbfd03 100644
1111
auto_explain \
1212
bloom \
1313
diff --git a/src/backend/commands/explain.c b/src/backend/commands/explain.c
14-
index a40bc14ec5..28ec281a70 100644
14+
index a40bc14ec5..d157c3043e 100644
1515
--- a/src/backend/commands/explain.c
1616
+++ b/src/backend/commands/explain.c
1717
@@ -24,6 +24,7 @@
@@ -22,17 +22,20 @@ index a40bc14ec5..28ec281a70 100644
2222
#include "parser/parsetree.h"
2323
#include "rewrite/rewriteHandler.h"
2424
#include "storage/bufmgr.h"
25-
@@ -46,6 +47,9 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
25+
@@ -46,6 +47,12 @@ ExplainOneQuery_hook_type ExplainOneQuery_hook = NULL;
2626
/* Hook for plugins to get control in explain_get_index_name() */
2727
explain_get_index_name_hook_type explain_get_index_name_hook = NULL;
2828

2929
+/* Hook for plugins to get control in ExplainOnePlan() */
3030
+ExplainOnePlan_hook_type ExplainOnePlan_hook = NULL;
31+
+
32+
+/* Hook for plugins to get control in ExplainOnePlan() */
33+
+ExplainOneNode_hook_type ExplainOneNode_hook = NULL;
3134
+
3235

3336
/* OR-able flags for ExplainXMLTag() */
3437
#define X_OPENING 0
35-
@@ -597,6 +601,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
38+
@@ -597,6 +604,10 @@ ExplainOnePlan(PlannedStmt *plannedstmt, IntoClause *into, ExplainState *es,
3639
ExplainPropertyFloat("Execution Time", "ms", 1000.0 * totaltime, 3,
3740
es);
3841

@@ -43,42 +46,13 @@ index a40bc14ec5..28ec281a70 100644
4346
ExplainCloseGroup("Query", NULL, true, es);
4447
}
4548

46-
@@ -1521,6 +1529,38 @@ ExplainNode(PlanState *planstate, List *ancestors,
49+
@@ -1521,6 +1532,9 @@ ExplainNode(PlanState *planstate, List *ancestors,
4750
appendStringInfo(es->str,
4851
" (actual rows=%.0f loops=%.0f)",
4952
rows, nloops);
5053
+
51-
+#ifdef AQO_EXPLAIN
52-
+ if (es->verbose && plan && planstate->instrument)
53-
+ {
54-
+ int wrkrs = 1;
55-
+ double error = -1.;
56-
+
57-
+ if (planstate->worker_instrument && IsParallelTuplesProcessing(plan))
58-
+ {
59-
+ int i;
60-
+ for (i = 0; i < planstate->worker_instrument->num_workers; i++)
61-
+ {
62-
+ Instrumentation *instrument = &planstate->worker_instrument->instrument[i];
63-
+ if (instrument->nloops <= 0)
64-
+ continue;
65-
+ wrkrs++;
66-
+ }
67-
+ }
68-
+
69-
+ if (plan->predicted_cardinality > 0.)
70-
+ {
71-
+ error = 100. * (plan->predicted_cardinality - (rows*wrkrs))
72-
+ / plan->predicted_cardinality;
73-
+ appendStringInfo(es->str,
74-
+ " (AQO: cardinality=%.0lf, error=%.0lf%%, fsspace_hash=%d)",
75-
+ plan->predicted_cardinality, error, plan->fss_hash);
76-
+ }
77-
+ else
78-
+ appendStringInfo(es->str, " (AQO not used, fsspace_hash=%d)",
79-
+ plan->fss_hash);
80-
+ }
81-
+#endif
54+
+ if (ExplainOneNode_hook)
55+
+ ExplainOneNode_hook(es, planstate, plan, rows);
8256
}
8357
else
8458
{
@@ -909,10 +883,10 @@ index 7758a49fa4..4f221a000b 100644
909883

910884
return ppi;
911885
diff --git a/src/include/commands/explain.h b/src/include/commands/explain.h
912-
index f8b79ec120..b5eda01907 100644
886+
index f8b79ec120..f970971a4a 100644
913887
--- a/src/include/commands/explain.h
914888
+++ b/src/include/commands/explain.h
915-
@@ -62,6 +62,12 @@ extern PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook;
889+
@@ -62,6 +62,19 @@ extern PGDLLIMPORT ExplainOneQuery_hook_type ExplainOneQuery_hook;
916890
typedef const char *(*explain_get_index_name_hook_type) (Oid indexId);
917891
extern PGDLLIMPORT explain_get_index_name_hook_type explain_get_index_name_hook;
918892

@@ -922,6 +896,13 @@ index f8b79ec120..b5eda01907 100644
922896
+ ParamListInfo params, const instr_time *planduration,
923897
+ QueryEnvironment *queryEnv);
924898
+extern PGDLLIMPORT ExplainOnePlan_hook_type ExplainOnePlan_hook;
899+
+
900+
+/* Explain a plan node info */
901+
+typedef void (*ExplainOneNode_hook_type) (ExplainState *es,
902+
+ PlanState *ps,
903+
+ Plan *plan,
904+
+ double rows);
905+
+extern PGDLLIMPORT ExplainOneNode_hook_type ExplainOneNode_hook;
925906

926907
extern void ExplainQuery(ParseState *pstate, ExplainStmt *stmt, const char *queryString,
927908
ParamListInfo params, QueryEnvironment *queryEnv, DestReceiver *dest);

conf.add

Lines changed: 3 additions & 1 deletion
Original file line numberDiff line numberDiff line change
@@ -1 +1,3 @@
1-
shared_preload_libraries = 'aqo'
1+
autovacuum = off
2+
shared_preload_libraries = 'postgres_fdw, aqo'
3+
max_parallel_workers = 0 # switch off parallel workers because of unsteadiness

expected/aqo_fdw.out

Lines changed: 74 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -0,0 +1,74 @@
1+
-- Tests on cardinality estimation of FDW-queries:
2+
-- simple ForeignScan.
3+
-- JOIN push-down (check push of baserestrictinfo and joininfo)
4+
-- Aggregate push-down
5+
-- Push-down of groupings with HAVING clause.
6+
CREATE EXTENSION aqo;
7+
CREATE EXTENSION postgres_fdw;
8+
SET aqo.mode = 'learn';
9+
SET aqo.show_details = 'true'; -- show AQO info for each node and entire query.
10+
SET aqo.show_hash = 'false'; -- a hash value is system-depended. Ignore it.
11+
DO $d$
12+
BEGIN
13+
EXECUTE $$CREATE SERVER loopback FOREIGN DATA WRAPPER postgres_fdw
14+
OPTIONS (dbname '$$||current_database()||$$',
15+
port '$$||current_setting('port')||$$'
16+
)$$;
17+
END;
18+
$d$;
19+
CREATE USER MAPPING FOR PUBLIC SERVER loopback;
20+
CREATE TABLE local (x int);
21+
CREATE FOREIGN TABLE frgn(x int) SERVER loopback OPTIONS (table_name 'local');
22+
INSERT INTO frgn (x) VALUES (1);
23+
ANALYZE local;
24+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT x FROM frgn;
25+
QUERY PLAN
26+
-------------------------------------------------------------
27+
Foreign Scan on frgn (actual rows=1 loops=1) (AQO not used)
28+
Using aqo: true
29+
AQO mode: LEARN
30+
JOINS: 0
31+
(4 rows)
32+
33+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT x FROM frgn;
34+
QUERY PLAN
35+
-----------------------------------------------------------------------------
36+
Foreign Scan on frgn (actual rows=1 loops=1) (AQO: cardinality=1, error=0%)
37+
Using aqo: true
38+
AQO mode: LEARN
39+
JOINS: 0
40+
(4 rows)
41+
42+
-- Push down base filters.
43+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE) SELECT x FROM frgn WHERE x < 10;
44+
QUERY PLAN
45+
--------------------------------------------------------------------
46+
Foreign Scan on public.frgn (actual rows=1 loops=1) (AQO not used)
47+
Output: x
48+
Remote SQL: SELECT x FROM public.local WHERE ((x < 10))
49+
Using aqo: true
50+
AQO mode: LEARN
51+
JOINS: 0
52+
(6 rows)
53+
54+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF, VERBOSE) SELECT x FROM frgn WHERE x < 10;
55+
QUERY PLAN
56+
------------------------------------------------------------------------------------
57+
Foreign Scan on public.frgn (actual rows=1 loops=1) (AQO: cardinality=1, error=0%)
58+
Output: x
59+
Remote SQL: SELECT x FROM public.local WHERE ((x < 10))
60+
Using aqo: true
61+
AQO mode: LEARN
62+
JOINS: 0
63+
(6 rows)
64+
65+
EXPLAIN (ANALYZE, COSTS OFF, SUMMARY OFF, TIMING OFF) SELECT x FROM frgn WHERE x < -10; -- AQO ignores constants
66+
QUERY PLAN
67+
-------------------------------------------------------------------------------
68+
Foreign Scan on frgn (actual rows=0 loops=1) (AQO: cardinality=1, error=100%)
69+
Using aqo: true
70+
AQO mode: LEARN
71+
JOINS: 0
72+
(4 rows)
73+
74+
DROP EXTENSION aqo;

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