30
30
static bool pathman_transform_query_walker (Node * node , void * context );
31
31
32
32
static void disable_standard_inheritance (Query * parse );
33
- static void handle_modification_query (Query * parse );
33
+ static void handle_modification_query (Query * parse , ParamListInfo params );
34
34
35
35
static void partition_filter_visitor (Plan * plan , void * context );
36
36
37
37
static rel_parenthood_status tag_extract_parenthood_status (List * relation_tag );
38
38
39
+ static Node * eval_extern_params_mutator (Node * node , ParamListInfo params );
40
+
39
41
40
42
/*
41
43
* HACK: We have to mark each Query with a unique
@@ -134,9 +136,9 @@ plan_tree_walker(Plan *plan,
134
136
135
137
/* Perform some transformations on Query tree */
136
138
void
137
- pathman_transform_query (Query * parse )
139
+ pathman_transform_query (Query * parse , ParamListInfo params )
138
140
{
139
- pathman_transform_query_walker ((Node * ) parse , NULL );
141
+ pathman_transform_query_walker ((Node * ) parse , ( void * ) params );
140
142
}
141
143
142
144
/* Walker for pathman_transform_query() */
@@ -156,7 +158,7 @@ pathman_transform_query_walker(Node *node, void *context)
156
158
/* Apply Query tree modifiers */
157
159
rowmark_add_tableoids (query );
158
160
disable_standard_inheritance (query );
159
- handle_modification_query (query );
161
+ handle_modification_query (query , ( ParamListInfo ) context );
160
162
161
163
/* Handle Query node */
162
164
return query_tree_walker (query ,
@@ -236,7 +238,7 @@ disable_standard_inheritance(Query *parse)
236
238
237
239
/* Checks if query affects only one partition */
238
240
static void
239
- handle_modification_query (Query * parse )
241
+ handle_modification_query (Query * parse , ParamListInfo params )
240
242
{
241
243
const PartRelationInfo * prel ;
242
244
Node * prel_expr ;
@@ -276,6 +278,10 @@ handle_modification_query(Query *parse)
276
278
/* Exit if there's no expr (no use) */
277
279
if (!expr ) return ;
278
280
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
+
279
285
/* Prepare partitioning expression */
280
286
prel_expr = PrelExpressionForRelid (prel , result_rel );
281
287
@@ -477,3 +483,61 @@ tag_extract_parenthood_status(List *relation_tag)
477
483
478
484
return status ;
479
485
}
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
+ }
0 commit comments