3030static bool pathman_transform_query_walker (Node * node ,void * context );
3131
3232static void disable_standard_inheritance (Query * parse );
33- static void handle_modification_query (Query * parse );
33+ static void handle_modification_query (Query * parse , ParamListInfo params );
3434
3535static void partition_filter_visitor (Plan * plan ,void * context );
3636
3737static rel_parenthood_status tag_extract_parenthood_status (List * relation_tag );
3838
39+ static Node * eval_extern_params_mutator (Node * node ,ParamListInfo params );
40+
3941
4042/*
4143 * HACK: We have to mark each Query with a unique
@@ -134,9 +136,9 @@ plan_tree_walker(Plan *plan,
134136
135137/* Perform some transformations on Query tree */
136138void
137- pathman_transform_query (Query * parse )
139+ pathman_transform_query (Query * parse , ParamListInfo params )
138140{
139- pathman_transform_query_walker ((Node * )parse ,NULL );
141+ pathman_transform_query_walker ((Node * )parse ,( void * ) params );
140142}
141143
142144/* Walker for pathman_transform_query() */
@@ -156,7 +158,7 @@ pathman_transform_query_walker(Node *node, void *context)
156158/* Apply Query tree modifiers */
157159rowmark_add_tableoids (query );
158160disable_standard_inheritance (query );
159- handle_modification_query (query );
161+ handle_modification_query (query , ( ParamListInfo ) context );
160162
161163/* Handle Query node */
162164return query_tree_walker (query ,
@@ -236,7 +238,7 @@ disable_standard_inheritance(Query *parse)
236238
237239/* Checks if query affects only one partition */
238240static void
239- handle_modification_query (Query * parse )
241+ handle_modification_query (Query * parse , ParamListInfo params )
240242{
241243const PartRelationInfo * prel ;
242244Node * prel_expr ;
@@ -276,6 +278,10 @@ handle_modification_query(Query *parse)
276278/* Exit if there's no expr (no use) */
277279if (!expr )return ;
278280
281+ /* Check if we can replace PARAMs with CONSTs */
282+ if (clause_contains_params ((Node * )expr )&& params )
283+ expr = (Expr * )eval_extern_params_mutator ((Node * )expr ,params );
284+
279285/* Prepare partitioning expression */
280286prel_expr = PrelExpressionForRelid (prel ,result_rel );
281287
@@ -477,3 +483,61 @@ tag_extract_parenthood_status(List *relation_tag)
477483
478484return status ;
479485}
486+
487+
488+ /* Replace extern param nodes with consts */
489+ static Node *
490+ eval_extern_params_mutator (Node * node ,ParamListInfo params )
491+ {
492+ if (node == NULL )
493+ return NULL ;
494+
495+ if (IsA (node ,Param ))
496+ {
497+ Param * param = (Param * )node ;
498+
499+ /* Look to see if we've been given a value for this Param */
500+ if (param -> paramkind == PARAM_EXTERN &&
501+ params != NULL &&
502+ param -> paramid > 0 &&
503+ param -> paramid <=params -> numParams )
504+ {
505+ ParamExternData * prm = & params -> params [param -> paramid - 1 ];
506+
507+ if (OidIsValid (prm -> ptype ))
508+ {
509+ /* OK to substitute parameter value? */
510+ if (prm -> pflags & PARAM_FLAG_CONST )
511+ {
512+ /*
513+ * Return a Const representing the param value.
514+ * Must copy pass-by-ref datatypes, since the
515+ * Param might be in a memory context
516+ * shorter-lived than our output plan should be.
517+ */
518+ int16 typLen ;
519+ bool typByVal ;
520+ Datum pval ;
521+
522+ Assert (prm -> ptype == param -> paramtype );
523+ get_typlenbyval (param -> paramtype ,
524+ & typLen ,& typByVal );
525+ if (prm -> isnull || typByVal )
526+ pval = prm -> value ;
527+ else
528+ pval = datumCopy (prm -> value ,typByVal ,typLen );
529+ return (Node * )makeConst (param -> paramtype ,
530+ param -> paramtypmod ,
531+ param -> paramcollid ,
532+ (int )typLen ,
533+ pval ,
534+ prm -> isnull ,
535+ typByVal );
536+ }
537+ }
538+ }
539+ }
540+
541+ return expression_tree_mutator (node ,eval_extern_params_mutator ,
542+ (void * )params );
543+ }