@ -48,10 +48,12 @@
# include "storage/dsm_impl.h"
# include "utils/rel.h"
# include "utils/selfuncs.h"
# include "utils/syscache.h"
/* GUC parameter */
/* GUC parameters */
double cursor_tuple_fraction = DEFAULT_CURSOR_TUPLE_FRACTION ;
int force_parallel_mode = FORCE_PARALLEL_OFF ;
/* Hook for plugins to get control in planner() */
planner_hook_type planner_hook = NULL ;
@ -230,25 +232,31 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
! has_parallel_hazard ( ( Node * ) parse , true ) ;
/*
* glob - > parallelModeOK should tell us whether it ' s necessary to impose
* the parallel mode restrictions , but we don ' t actually want to impose
* them unless we choose a parallel plan , so that people who mislabel
* their functions but don ' t use parallelism anyway aren ' t harmed .
* However , it ' s useful for testing purposes to be able to force the
* restrictions to be imposed whenever a parallel plan is actually chosen
* or not .
* glob - > parallelModeNeeded should tell us whether it ' s necessary to
* impose the parallel mode restrictions , but we don ' t actually want to
* impose them unless we choose a parallel plan , so that people who
* mislabel their functions but don ' t use parallelism anyway aren ' t
* harmed . But when force_parallel_mode is set , we enable the restrictions
* whenever possible for testing purposes .
*
* ( It ' s been suggested that we should always impose these restrictions
* whenever glob - > parallelModeOK is true , so that it ' s easier to notice
* incorrectly - labeled functions sooner . That might be the right thing to
* do , but for now I ' ve taken this approach . We could also control this
* with a GUC . )
* glob - > wholePlanParallelSafe should tell us whether it ' s OK to stick a
* Gather node on top of the entire plan . However , it only needs to be
* accurate when force_parallel_mode is ' on ' or ' regress ' , so we don ' t
* bother doing the work otherwise . The value we set here is just a
* preliminary guess ; it may get changed from true to false later , but
* not visca versa .
*/
# ifdef FORCE_PARALLEL_MODE
glob - > parallelModeNeeded = glob - > parallelModeOK ;
# else
glob - > parallelModeNeeded = false ;
# endif
if ( force_parallel_mode = = FORCE_PARALLEL_OFF | | ! glob - > parallelModeOK )
{
glob - > parallelModeNeeded = false ;
glob - > wholePlanParallelSafe = false ; /* either false or don't care */
}
else
{
glob - > parallelModeNeeded = true ;
glob - > wholePlanParallelSafe =
! has_parallel_hazard ( ( Node * ) parse , false ) ;
}
/* Determine what fraction of the plan is likely to be scanned */
if ( cursorOptions & CURSOR_OPT_FAST_PLAN )
@ -292,6 +300,35 @@ standard_planner(Query *parse, int cursorOptions, ParamListInfo boundParams)
top_plan = materialize_finished_plan ( top_plan ) ;
}
/*
* At present , we don ' t copy subplans to workers . The presence of a
* subplan in one part of the plan doesn ' t preclude the use of parallelism
* in some other part of the plan , but it does preclude the possibility of
* regarding the entire plan parallel - safe .
*/
if ( glob - > subplans ! = NULL )
glob - > wholePlanParallelSafe = false ;
/*
* Optionally add a Gather node for testing purposes , provided this is
* actually a safe thing to do .
*/
if ( glob - > wholePlanParallelSafe & &
force_parallel_mode ! = FORCE_PARALLEL_OFF )
{
Gather * gather = makeNode ( Gather ) ;
gather - > plan . targetlist = top_plan - > targetlist ;
gather - > plan . qual = NIL ;
gather - > plan . lefttree = top_plan ;
gather - > plan . righttree = NULL ;
gather - > num_workers = 1 ;
gather - > single_copy = true ;
gather - > invisible = ( force_parallel_mode = = FORCE_PARALLEL_REGRESS ) ;
root - > glob - > parallelModeNeeded = true ;
top_plan = & gather - > plan ;
}
/*
* If any Params were generated , run through the plan tree and compute
* each plan node ' s extParam / allParam sets . Ideally we ' d merge this into