@@ -207,9 +207,9 @@ static char *get_variable(Var *var, int levelsup, bool showstar,
207207 deparse_context * context );
208208static RangeTblEntry * find_rte_by_refname (const char * refname ,
209209 deparse_context * context );
210+ static Node * find_param_referent (Param * param , deparse_context * context ,
211+ deparse_namespace * * dpns_p , ListCell * * ancestor_cell_p );
210212static void get_parameter (Param * param , deparse_context * context );
211- static void print_parameter_expr (Node * expr , ListCell * ancestor_cell ,
212- deparse_namespace * dpns , deparse_context * context );
213213static const char * get_simple_binary_op_name (OpExpr * expr );
214214static bool isSimpleNode (Node * node , Node * parentNode , int prettyFlags );
215215static void appendContextKeyword (deparse_context * context , const char * str ,
@@ -3892,15 +3892,21 @@ get_variable(Var *var, int levelsup, bool showstar, deparse_context *context)
38923892
38933893
38943894/*
3895- * Get the name of a field of an expression of composite type.
3896- *
3897- * This is fairly straightforward except for the case of a Var of type RECORD.
3898- * Since no actual table or view column is allowed to have type RECORD, such
3899- * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
3900- * drill down to find the ultimate defining expression and attempt to infer
3901- * the field name from it. We ereport if we can't determine the name.
3895+ * Get the name of a field of an expression of composite type. The
3896+ * expression is usually a Var, but we handle other cases too.
39023897 *
39033898 * levelsup is an extra offset to interpret the Var's varlevelsup correctly.
3899+ *
3900+ * This is fairly straightforward when the expression has a named composite
3901+ * type; we need only look up the type in the catalogs. However, the type
3902+ * could also be RECORD. Since no actual table or view column is allowed to
3903+ * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
3904+ * or to a subquery output. We drill down to find the ultimate defining
3905+ * expression and attempt to infer the field name from it. We ereport if we
3906+ * can't determine the name.
3907+ *
3908+ * Similarly, a PARAM of type RECORD has to refer to some expression of
3909+ * a determinable composite type.
39043910 */
39053911static const char *
39063912get_name_for_var_field (Var * var , int fieldno ,
@@ -3925,6 +3931,29 @@ get_name_for_var_field(Var *var, int fieldno,
39253931 return strVal (list_nth (r -> colnames , fieldno - 1 ));
39263932 }
39273933
3934+ /*
3935+ * If it's a Param of type RECORD, try to find what the Param refers to.
3936+ */
3937+ if (IsA (var , Param ))
3938+ {
3939+ Param * param = (Param * ) var ;
3940+ ListCell * ancestor_cell ;
3941+
3942+ expr = find_param_referent (param , context , & dpns , & ancestor_cell );
3943+ if (expr )
3944+ {
3945+ /* Found a match, so recurse to decipher the field name */
3946+ deparse_namespace save_dpns ;
3947+ const char * result ;
3948+
3949+ push_ancestor_plan (dpns , ancestor_cell , & save_dpns );
3950+ result = get_name_for_var_field ((Var * ) expr , fieldno ,
3951+ 0 , context );
3952+ pop_ancestor_plan (dpns , & save_dpns );
3953+ return result ;
3954+ }
3955+ }
3956+
39283957 /*
39293958 * If it's a Var of type RECORD, we have to find what the Var refers to;
39303959 * if not, we can use get_expr_result_type. If that fails, we try
@@ -4279,17 +4308,25 @@ find_rte_by_refname(const char *refname, deparse_context *context)
42794308}
42804309
42814310/*
4282- * Display a Param appropriately.
4311+ * Try to find the referenced expression for a PARAM_EXEC Param that might
4312+ * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
4313+ *
4314+ * If successful, return the expression and set *dpns_p and *ancestor_cell_p
4315+ * appropriately for calling push_ancestor_plan(). If no referent can be
4316+ * found, return NULL.
42834317 */
4284- static void
4285- get_parameter (Param * param , deparse_context * context )
4318+ static Node *
4319+ find_param_referent (Param * param , deparse_context * context ,
4320+ deparse_namespace * * dpns_p , ListCell * * ancestor_cell_p )
42864321{
4322+ /* Initialize output parameters to prevent compiler warnings */
4323+ * dpns_p = NULL ;
4324+ * ancestor_cell_p = NULL ;
4325+
42874326 /*
4288- * If it's a PARAM_EXEC parameter, try to locate the expression from which
4289- * the parameter was computed. This will necessarily be in some ancestor
4290- * of the current expression's PlanState. Note that failing to find a
4291- * referent isn't an error, since the Param might well be a subplan output
4292- * rather than an input.
4327+ * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
4328+ * SubPlan argument. This will necessarily be in some ancestor of the
4329+ * current expression's PlanState.
42934330 */
42944331 if (param -> paramkind == PARAM_EXEC )
42954332 {
@@ -4324,10 +4361,10 @@ get_parameter(Param *param, deparse_context *context)
43244361
43254362 if (nlp -> paramno == param -> paramid )
43264363 {
4327- /* Found a match, so print it */
4328- print_parameter_expr (( Node * ) nlp -> paramval , lc ,
4329- dpns , context ) ;
4330- return ;
4364+ /* Found a match, so return it */
4365+ * dpns_p = dpns ;
4366+ * ancestor_cell_p = lc ;
4367+ return ( Node * ) nlp -> paramval ;
43314368 }
43324369 }
43334370 }
@@ -4353,9 +4390,10 @@ get_parameter(Param *param, deparse_context *context)
43534390
43544391 if (paramid == param -> paramid )
43554392 {
4356- /* Found a match, so print it */
4357- print_parameter_expr (arg , lc , dpns , context );
4358- return ;
4393+ /* Found a match, so return it */
4394+ * dpns_p = dpns ;
4395+ * ancestor_cell_p = lc ;
4396+ return arg ;
43594397 }
43604398 }
43614399
@@ -4390,50 +4428,71 @@ get_parameter(Param *param, deparse_context *context)
43904428 }
43914429 }
43924430
4393- /*
4394- * Not PARAM_EXEC, or couldn't find referent: just print $N.
4395- */
4396- appendStringInfo (context -> buf , "$%d" , param -> paramid );
4431+ /* No referent found */
4432+ return NULL ;
43974433}
43984434
4399- /* Print a parameter reference expression found by get_parameter */
4435+ /*
4436+ * Display a Param appropriately.
4437+ */
44004438static void
4401- print_parameter_expr (Node * expr , ListCell * ancestor_cell ,
4402- deparse_namespace * dpns , deparse_context * context )
4439+ get_parameter (Param * param , deparse_context * context )
44034440{
4404- deparse_namespace save_dpns ;
4405- bool save_varprefix ;
4406- bool need_paren ;
4407-
4408- /* Switch attention to the ancestor plan node */
4409- push_ancestor_plan (dpns , ancestor_cell , & save_dpns );
4441+ Node * expr ;
4442+ deparse_namespace * dpns ;
4443+ ListCell * ancestor_cell ;
44104444
44114445 /*
4412- * Force prefixing of Vars, since they won't belong to the relation being
4413- * scanned in the original plan node.
4446+ * If it's a PARAM_EXEC parameter, try to locate the expression from which
4447+ * the parameter was computed. Note that failing to find a referent isn't
4448+ * an error, since the Param might well be a subplan output rather than an
4449+ * input.
44144450 */
4415- save_varprefix = context -> varprefix ;
4416- context -> varprefix = true;
4451+ expr = find_param_referent (param , context , & dpns , & ancestor_cell );
4452+ if (expr )
4453+ {
4454+ /* Found a match, so print it */
4455+ deparse_namespace save_dpns ;
4456+ bool save_varprefix ;
4457+ bool need_paren ;
44174458
4418- /*
4419- * A Param's expansion is typically a Var, Aggref, or upper-level Param,
4420- * which wouldn't need extra parentheses. Otherwise, insert parens to
4421- * ensure the expression looks atomic.
4422- */
4423- need_paren = !(IsA (expr , Var ) ||
4424- IsA (expr , Aggref ) ||
4425- IsA (expr , Param ));
4426- if (need_paren )
4427- appendStringInfoChar (context -> buf , '(' );
4459+ /* Switch attention to the ancestor plan node */
4460+ push_ancestor_plan (dpns , ancestor_cell , & save_dpns );
44284461
4429- get_rule_expr (expr , context , false);
4462+ /*
4463+ * Force prefixing of Vars, since they won't belong to the relation
4464+ * being scanned in the original plan node.
4465+ */
4466+ save_varprefix = context -> varprefix ;
4467+ context -> varprefix = true;
44304468
4431- if (need_paren )
4432- appendStringInfoChar (context -> buf , ')' );
4469+ /*
4470+ * A Param's expansion is typically a Var, Aggref, or upper-level
4471+ * Param, which wouldn't need extra parentheses. Otherwise, insert
4472+ * parens to ensure the expression looks atomic.
4473+ */
4474+ need_paren = !(IsA (expr , Var ) ||
4475+ IsA (expr , Aggref ) ||
4476+ IsA (expr , Param ));
4477+ if (need_paren )
4478+ appendStringInfoChar (context -> buf , '(' );
4479+
4480+ get_rule_expr (expr , context , false);
4481+
4482+ if (need_paren )
4483+ appendStringInfoChar (context -> buf , ')' );
4484+
4485+ context -> varprefix = save_varprefix ;
44334486
4434- context -> varprefix = save_varprefix ;
4487+ pop_ancestor_plan ( dpns , & save_dpns ) ;
44354488
4436- pop_ancestor_plan (dpns , & save_dpns );
4489+ return ;
4490+ }
4491+
4492+ /*
4493+ * Not PARAM_EXEC, or couldn't find referent: just print $N.
4494+ */
4495+ appendStringInfo (context -> buf , "$%d" , param -> paramid );
44374496}
44384497
44394498/*
0 commit comments