8000 Bugfix. Reuse existed query environment (AQO-related fields) if exists. · postgrespro/aqo@0ce1acf · GitHub
[go: up one dir, main page]

Skip to content

Commit 0ce1acf

Browse files
committed
Bugfix. Reuse existed query environment (AQO-related fields) if exists.
It is necessary to use AQO with cached plans. Improve interface of preprocessing module.
1 parent 6f6d863 commit 0ce1acf

File tree

5 files changed

+38
-35
lines changed

5 files changed

+38
-35
lines changed

aqo.c

Lines changed: 1 addition & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -12,6 +12,7 @@
1212
#include "cardinality_hooks.h"
1313
#include "ignorance.h"
1414
#include "path_utils.h"
15+
#include "preprocessing.h"
1516

1617
#include "access/relation.h"
1718
#include "access/table.h"

aqo.h

Lines changed: 0 additions & 8 deletions
Original file line numberDiff line numberDiff line change
@@ -309,14 +309,6 @@ extern void add_deactivated_query(int query_hash);
309309
/* Query preprocessing hooks */
310310
extern void get_query_text(ParseState *pstate, Query *query,
311311
JumbleState *jstate);
312-
extern PlannedStmt *call_default_planner(Query *parse,
313-
const char *query_string,
314-
int cursorOptions,
315-
ParamListInfo boundParams);
316-
extern PlannedStmt *aqo_planner(Query *parse,
317-
const char *query_string,
318-
int cursorOptions,
319-
ParamListInfo boundParams);
320312
extern void print_into_explain(PlannedStmt *plannedstmt, IntoClause *into,
321313
ExplainState *es, const char *queryString,
322314
ParamListInfo params,

postprocessing.c

Lines changed: 24 additions & 24 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,6 @@ static void update_query_stat_row(double *et, int *et_size,
7272
static void StoreToQueryEnv(QueryDesc *queryDesc);
7373
static void StorePlanInternals(QueryDesc *queryDesc);
7474
static bool ExtractFromQueryEnv(QueryDesc *queryDesc);
75-
static void RemoveFromQueryEnv(QueryDesc *queryDesc);
7675

7776

7877
/*
@@ -542,9 +541,16 @@ update_query_stat_row(double *et, int *et_size,
542541
void
543542
aqo_ExecutorStart(QueryDesc *queryDesc, int eflags)
544543
{
545-
instr_time now;
544+
instr_time now;
546545
bool use_aqo;
547546

547+
/*
548+
* If the plan pulled from a plan cache, planning don't needed. Restore
549+
* query context from the query environment.
550+
*/
551+
if (ExtractFromQueryEnv(queryDesc))
552+
Assert(INSTR_TIME_IS_ZERO(query_context.start_planning_time));
553+
548554
if (IsQueryDisabled())
549555
/* Fast path */
550556
use_aqo = false;
@@ -713,8 +719,6 @@ aqo_ExecutorEnd(QueryDesc *queryDesc)
713719

714720
cur_classes = list_delete_int(cur_classes, query_context.query_hash);
715721

716-
RemoveFromQueryEnv(queryDesc);
717-
718722
end:
719723
if (prev_ExecutorEnd_hook)
720724
prev_ExecutorEnd_hook(queryDesc);
@@ -728,9 +732,11 @@ aqo_ExecutorEnd(QueryDesc *queryDesc)
728732
}
729733

730734
/*
731-
* Store into query environment field AQO data related to the query.
735+
* Store into a query environment field an AQO data related to the query.
732736
* We introduce this machinery to avoid problems with subqueries, induced by
733737
* top-level query.
738+
* If such enr exists, routine will replace it with current value of the
739+
* query context.
734740
*/
735741
static void
736742
StoreToQueryEnv(QueryDesc *queryDesc)
@@ -740,16 +746,20 @@ StoreToQueryEnv(QueryDesc *queryDesc)
740746
MemoryContext oldCxt;
741747

742748
oldCxt = MemoryContextSwitchTo(AQOMemoryContext);
743-
enr = palloc0(sizeof(EphemeralNamedRelationData));
749+
744750
if (queryDesc->queryEnv == NULL)
745-
queryDesc->queryEnv = create_queryEnv();
751+
queryDesc->queryEnv = create_queryEnv();
752+
753+
enr = get_ENR(queryDesc->queryEnv, AQOPrivateData);
754+
if (enr == NULL)
755+
/* If such query environment don't exists, allocate new. */
756+
enr = palloc0(sizeof(EphemeralNamedRelationData));
746757

747758
enr->md.name = AQOPrivateData;
748759
enr->md.enrtuples = 0;
749760
enr->md.enrtype = 0;
750761
enr->md.reliddesc = InvalidOid;
751762
enr->md.tupdesc = NULL;
752-
753763
enr->reldata = palloc0(qcsize);
754764
memcpy(enr->reldata, &query_context, qcsize);
755765

@@ -782,10 +792,15 @@ StorePlanInternals(QueryDesc *queryDesc)
782792
planstate_tree_walker(queryDesc->planstate, calculateJoinNum, &njoins);
783793

784794
oldCxt = MemoryContextSwitchTo(AQOMemoryContext);
785-
enr = palloc0(sizeof(EphemeralNamedRelationData));
795+
786796
if (queryDesc->queryEnv == NULL)
787797
queryDesc->queryEnv = create_queryEnv();
788798

799+
enr = get_ENR(queryDesc->queryEnv, PlanStateInfo);
800+
if (enr == NULL)
801+
/* If such query environment don't exists, allocate new. */
802+
enr = palloc0(sizeof(EphemeralNamedRelationData));
803+
789804
enr->md.name = PlanStateInfo;
790805
enr->md.enrtuples = 0;
791806
enr->md.enrtype = 0;
@@ -823,21 +838,6 @@ ExtractFromQueryEnv(QueryDesc *queryDesc)
823838
return true;
824839
}
825840

826-
static void
827-
RemoveFromQueryEnv(QueryDesc *queryDesc)
828-
{
829-
EphemeralNamedRelation enr = get_ENR(queryDesc->queryEnv, AQOPrivateData);
830-
unregister_ENR(queryDesc->queryEnv, AQOPrivateData);
831-
pfree(enr->reldata);
832-
pfree(enr);
833-
834-
/* Remove the plan state internals */
835-
enr = get_ENR(queryDesc->queryEnv, PlanStateInfo);
836-
unregister_ENR(queryDesc->queryEnv, PlanStateInfo);
837-
pfree(enr->reldata);
838-
pfree(enr);
839-
}
840-
841841
void
842842
print_node_explain(ExplainState *es, PlanState *ps, Plan *plan)
843843
{

preprocessing.c

Lines changed: 6 additions & 3 deletions
Original file line numberDiff line numberDiff line change
@@ -72,7 +72,7 @@ static bool isQueryUsingSystemRelation_walker(Node *node, void *context);
7272
/*
7373
* Calls standard query planner or its previous hook.
7474
*/
75-
PlannedStmt *
75+
static PlannedStmt *
7676
call_default_planner(Query *parse,
7777
const char *query_string,
7878
int cursorOptions,
@@ -151,6 +151,9 @@ aqo_planner(Query *parse,
151151
boundParams);
152152
}
153153

154+
elog(DEBUG1, "AQO will be used for query '%s', class %d",
155+
query_string ? query_string : "null string", query_context.query_hash);
156+
154157
oldCxt = MemoryContextSwitchTo(AQOMemoryContext);
155158
cur_classes = lappend_int(cur_classes, query_context.query_hash);
156159
MemoryContextSwitchTo(oldCxt);
@@ -353,7 +356,7 @@ IsQueryDisabled(void)
353356
* Examine a fully-parsed query, and return TRUE iff any relation underlying
354357
* the query is a system relation.
355358
*/
356-
bool
359+
static bool
357360
isQueryUsingSystemRelation(Query *query)
358361
{
359362
return isQueryUsingSystemRelation_walker((Node *) query, NULL);
@@ -375,7 +378,7 @@ IsAQORelation(Relation rel)
375378
return false;
376379
}
377380

378-
bool
381+
static bool
379382
isQueryUsingSystemRelation_walker(Node *node, void *context)
380383
{
381384
if (node == NULL)

preprocessing.h

Lines changed: 7 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -1,6 +1,13 @@
11
#ifndef __PREPROCESSING_H__
22
#define __PREPROCESSING_H__
33

4+
#include "nodes/pathnodes.h"
5+
#include "nodes/plannodes.h"
6+
7+
extern PlannedStmt *aqo_planner(Query *parse,
8+
const char *query_string,
9+
int cursorOptions,
10+
ParamListInfo boundParams);
411
extern void disable_aqo_for_query(void);
512
extern bool IsQueryDisabled(void);
613

0 commit comments

Comments
 (0)
0