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

Commita87c0c7

Browse files
committed
Allow parallel query for prepared statements with generic plans.
This was always intended to work, but due to an oversight inmax_parallel_hazard_walker, it didn't. In testing, we missed thefact that it was only working for custom plans, where the parametervalue has been substituted for the parameter itself early enoughthat everything worked. In a generic plan, the Param node survivesand must be treated as parallel-safe. SerializeParamList providesfor the transmission of parameter values to workers.Amit Kapila with help from Kuntal Ghosh. Some changes by me.Discussion:http://postgr.es/m/CAA4eK1+_BuZrmVCeua5Eqnm4Co9DAXdM5HPAOE2J19ePbR912Q@mail.gmail.com
1 parent69125c8 commita87c0c7

File tree

4 files changed

+76
-21
lines changed

4 files changed

+76
-21
lines changed

‎src/backend/optimizer/util/clauses.c

Lines changed: 6 additions & 2 deletions
Original file line numberDiff line numberDiff line change
@@ -1223,13 +1223,17 @@ max_parallel_hazard_walker(Node *node, max_parallel_hazard_context *context)
12231223

12241224
/*
12251225
* We can't pass Params to workers at the moment either, so they are also
1226-
* parallel-restricted, unless they are PARAM_EXEC Params listed in
1227-
* safe_param_ids, meaning they could be generated within the worker.
1226+
* parallel-restricted, unless they are PARAM_EXTERN Params or are
1227+
* PARAM_EXEC Params listed in safe_param_ids, meaning they could be
1228+
* generated within the worker.
12281229
*/
12291230
elseif (IsA(node,Param))
12301231
{
12311232
Param*param= (Param*)node;
12321233

1234+
if (param->paramkind==PARAM_EXTERN)
1235+
return false;
1236+
12331237
if (param->paramkind!=PARAM_EXEC||
12341238
!list_member_int(context->safe_param_ids,param->paramid))
12351239
{

‎src/pl/plpgsql/src/pl_exec.c

Lines changed: 44 additions & 19 deletions
Original file line numberDiff line numberDiff line change
@@ -6821,7 +6821,7 @@ exec_simple_recheck_plan(PLpgSQL_expr *expr, CachedPlan *cplan)
68216821
{
68226822
PlannedStmt*stmt;
68236823
Plan*plan;
6824-
TargetEntry*tle;
6824+
Expr*tle_expr;
68256825

68266826
/*
68276827
* Initialize to "not simple", and remember the plan generation number we
@@ -6836,18 +6836,51 @@ exec_simple_recheck_plan(PLpgSQL_expr *expr, CachedPlan *cplan)
68366836
if (list_length(cplan->stmt_list)!=1)
68376837
return;
68386838
stmt=linitial_node(PlannedStmt,cplan->stmt_list);
6839+
if (stmt->commandType!=CMD_SELECT)
6840+
return;
68396841

68406842
/*
6841-
* 2. It must be a RESULT plan --> no scan's required
6843+
* 2. Ordinarily, the plan node should be a simple Result. However, if
6844+
* force_parallel_mode is on, the planner might've stuck a Gather node
6845+
* atop that. The simplest way to deal with this is to look through the
6846+
* Gather node. The Gather node's tlist would normally contain a Var
6847+
* referencing the child node's output, but it could also be a Param, or
6848+
* it could be a Const that setrefs.c copied as-is.
68426849
*/
6843-
if (stmt->commandType!=CMD_SELECT)
6844-
return;
68456850
plan=stmt->planTree;
6846-
if (!IsA(plan,Result))
6847-
return;
6851+
for (;;)
6852+
{
6853+
/*
6854+
* 3. The plan must have a single attribute as result
6855+
*/
6856+
if (list_length(plan->targetlist)!=1)
6857+
return;
6858+
tle_expr=castNode(TargetEntry,linitial(plan->targetlist))->expr;
6859+
6860+
if (IsA(plan,Gather))
6861+
{
6862+
if (plan->righttree!=NULL||
6863+
plan->initPlan!=NULL||
6864+
plan->qual!=NULL)
6865+
return;
6866+
/* If setrefs.c copied up a Const, no need to look further */
6867+
if (IsA(tle_expr,Const))
6868+
break;
6869+
/* Otherwise, it had better be a Param or an outer Var */
6870+
if (!IsA(tle_expr,Param)&& !(IsA(tle_expr,Var)&&
6871+
((Var*)tle_expr)->varno==OUTER_VAR))
6872+
return;
6873+
/* Descend to the child node */
6874+
plan=plan->lefttree;
6875+
continue;
6876+
}
6877+
elseif (!IsA(plan,Result))
6878+
return;
6879+
break;
6880+
}
68486881

68496882
/*
6850-
*3. Can't have any subplan or qual clause, either
6883+
*4. Can't have any subplan or qual clause, either
68516884
*/
68526885
if (plan->lefttree!=NULL||
68536886
plan->righttree!=NULL||
@@ -6856,31 +6889,23 @@ exec_simple_recheck_plan(PLpgSQL_expr *expr, CachedPlan *cplan)
68566889
((Result*)plan)->resconstantqual!=NULL)
68576890
return;
68586891

6859-
/*
6860-
* 4. The plan must have a single attribute as result
6861-
*/
6862-
if (list_length(plan->targetlist)!=1)
6863-
return;
6864-
6865-
tle= (TargetEntry*)linitial(plan->targetlist);
6866-
68676892
/*
68686893
* 5. Check that all the nodes in the expression are non-scary.
68696894
*/
6870-
if (!exec_simple_check_node((Node*)tle->expr))
6895+
if (!exec_simple_check_node((Node*)tle_expr))
68716896
return;
68726897

68736898
/*
68746899
* Yes - this is a simple expression. Mark it as such, and initialize
68756900
* state to "not valid in current transaction".
68766901
*/
6877-
expr->expr_simple_expr=tle->expr;
6902+
expr->expr_simple_expr=tle_expr;
68786903
expr->expr_simple_state=NULL;
68796904
expr->expr_simple_in_use= false;
68806905
expr->expr_simple_lxid=InvalidLocalTransactionId;
68816906
/* Also stash away the expression result type */
6882-
expr->expr_simple_type=exprType((Node*)tle->expr);
6883-
expr->expr_simple_typmod=exprTypmod((Node*)tle->expr);
6907+
expr->expr_simple_type=exprType((Node*)tle_expr);
6908+
expr->expr_simple_typmod=exprTypmod((Node*)tle_expr);
68846909
}
68856910

68866911
/*

‎src/test/regress/expected/select_parallel.out

Lines changed: 20 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -101,6 +101,26 @@ explain (costs off)
101101
-> Parallel Index Only Scan using tenk1_unique1 on tenk1
102102
(5 rows)
103103

104+
-- test prepared statement
105+
prepare tenk1_count(integer) As select count((unique1)) from tenk1 where hundred > $1;
106+
explain (costs off) execute tenk1_count(1);
107+
QUERY PLAN
108+
----------------------------------------------
109+
Finalize Aggregate
110+
-> Gather
111+
Workers Planned: 4
112+
-> Partial Aggregate
113+
-> Parallel Seq Scan on tenk1
114+
Filter: (hundred > 1)
115+
(6 rows)
116+
117+
execute tenk1_count(1);
118+
count
119+
-------
120+
9800
121+
(1 row)
122+
123+
deallocate tenk1_count;
104124
-- test parallel plans for queries containing un-correlated subplans.
105125
alter table tenk2 set (parallel_workers = 0);
106126
explain (costs off)

‎src/test/regress/sql/select_parallel.sql

Lines changed: 6 additions & 0 deletions
Original file line numberDiff line numberDiff line change
@@ -39,6 +39,12 @@ explain (costs off)
3939
selectsum(parallel_restricted(unique1))from tenk1
4040
group by(parallel_restricted(unique1));
4141

42+
-- test prepared statement
43+
prepare tenk1_count(integer)Asselectcount((unique1))from tenk1where hundred> $1;
44+
explain (costs off) execute tenk1_count(1);
45+
execute tenk1_count(1);
46+
deallocate tenk1_count;
47+
4248
-- test parallel plans for queries containing un-correlated subplans.
4349
altertable tenk2set (parallel_workers=0);
4450
explain (costs off)

0 commit comments

Comments
 (0)

[8]ページ先頭

©2009-2025 Movatter.jp