deparse_context *context);
static RangeTblEntry *find_rte_by_refname(const char *refname,
deparse_context *context);
+static Node *find_param_referent(Param *param, deparse_context *context,
+ deparse_namespace **dpns_p, ListCell **ancestor_cell_p);
static void get_parameter(Param *param, deparse_context *context);
-static void print_parameter_expr(Node *expr, ListCell *ancestor_cell,
- deparse_namespace *dpns, deparse_context *context);
static const char *get_simple_binary_op_name(OpExpr *expr);
static bool isSimpleNode(Node *node, Node *parentNode, int prettyFlags);
static void appendContextKeyword(deparse_context *context, const char *str,
/*
- * Get the name of a field of an expression of composite type.
- *
- * This is fairly straightforward except for the case of a Var of type RECORD.
- * Since no actual table or view column is allowed to have type RECORD, such
- * a Var must refer to a JOIN or FUNCTION RTE or to a subquery output. We
- * drill down to find the ultimate defining expression and attempt to infer
- * the field name from it. We ereport if we can't determine the name.
+ * Get the name of a field of an expression of composite type. The
+ * expression is usually a Var, but we handle other cases too.
*
* levelsup is an extra offset to interpret the Var's varlevelsup correctly.
+ *
+ * This is fairly straightforward when the expression has a named composite
+ * type; we need only look up the type in the catalogs. However, the type
+ * could also be RECORD. Since no actual table or view column is allowed to
+ * have type RECORD, a Var of type RECORD must refer to a JOIN or FUNCTION RTE
+ * or to a subquery output. We drill down to find the ultimate defining
+ * expression and attempt to infer the field name from it. We ereport if we
+ * can't determine the name.
+ *
+ * Similarly, a PARAM of type RECORD has to refer to some expression of
+ * a determinable composite type.
*/
static const char *
get_name_for_var_field(Var *var, int fieldno,
return strVal(list_nth(r->colnames, fieldno - 1));
}
+ /*
+ * If it's a Param of type RECORD, try to find what the Param refers to.
+ */
+ if (IsA(var, Param))
+ {
+ Param *param = (Param *) var;
+ ListCell *ancestor_cell;
+
+ expr = find_param_referent(param, context, &dpns, &ancestor_cell);
+ if (expr)
+ {
+ /* Found a match, so recurse to decipher the field name */
+ deparse_namespace save_dpns;
+ const char *result;
+
+ push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
+ result = get_name_for_var_field((Var *) expr, fieldno,
+ 0, context);
+ pop_ancestor_plan(dpns, &save_dpns);
+ return result;
+ }
+ }
+
/*
* If it's a Var of type RECORD, we have to find what the Var refers to;
* if not, we can use get_expr_result_type. If that fails, we try
}
/*
- * Display a Param appropriately.
+ * Try to find the referenced expression for a PARAM_EXEC Param that might
+ * reference a parameter supplied by an upper NestLoop or SubPlan plan node.
+ *
+ * If successful, return the expression and set *dpns_p and *ancestor_cell_p
+ * appropriately for calling push_ancestor_plan(). If no referent can be
+ * found, return NULL.
*/
-static void
-get_parameter(Param *param, deparse_context *context)
+static Node *
+find_param_referent(Param *param, deparse_context *context,
+ deparse_namespace **dpns_p, ListCell **ancestor_cell_p)
{
+ /* Initialize output parameters to prevent compiler warnings */
+ *dpns_p = NULL;
+ *ancestor_cell_p = NULL;
+
/*
- * If it's a PARAM_EXEC parameter, try to locate the expression from which
- * the parameter was computed. This will necessarily be in some ancestor
- * of the current expression's PlanState. Note that failing to find a
- * referent isn't an error, since the Param might well be a subplan output
- * rather than an input.
+ * If it's a PARAM_EXEC parameter, look for a matching NestLoopParam or
+ * SubPlan argument. This will necessarily be in some ancestor of the
+ * current expression's PlanState.
*/
if (param->paramkind == PARAM_EXEC)
{
if (nlp->paramno == param->paramid)
{
- /* Found a match, so print it */
- print_parameter_expr((Node *) nlp->paramval, lc,
- dpns, context);
- return;
+ /* Found a match, so return it */
+ *dpns_p = dpns;
+ *ancestor_cell_p = lc;
+ return (Node *) nlp->paramval;
}
}
}
if (paramid == param->paramid)
{
- /* Found a match, so print it */
- print_parameter_expr(arg, lc, dpns, context);
- return;
+ /* Found a match, so return it */
+ *dpns_p = dpns;
+ *ancestor_cell_p = lc;
+ return arg;
}
}
}
}
- /*
- * Not PARAM_EXEC, or couldn't find referent: just print $N.
- */
- appendStringInfo(context->buf, "$%d", param->paramid);
+ /* No referent found */
+ return NULL;
}
-/* Print a parameter reference expression found by get_parameter */
+/*
+ * Display a Param appropriately.
+ */
static void
-print_parameter_expr(Node *expr, ListCell *ancestor_cell,
- deparse_namespace *dpns, deparse_context *context)
+get_parameter(Param *param, deparse_context *context)
{
- deparse_namespace save_dpns;
- bool save_varprefix;
- bool need_paren;
-
- /* Switch attention to the ancestor plan node */
- push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
+ Node *expr;
+ deparse_namespace *dpns;
+ ListCell *ancestor_cell;
/*
- * Force prefixing of Vars, since they won't belong to the relation being
- * scanned in the original plan node.
+ * If it's a PARAM_EXEC parameter, try to locate the expression from which
+ * the parameter was computed. Note that failing to find a referent isn't
+ * an error, since the Param might well be a subplan output rather than an
+ * input.
*/
- save_varprefix = context->varprefix;
- context->varprefix = true;
+ expr = find_param_referent(param, context, &dpns, &ancestor_cell);
+ if (expr)
+ {
+ /* Found a match, so print it */
+ deparse_namespace save_dpns;
+ bool save_varprefix;
+ bool need_paren;
- /*
- * A Param's expansion is typically a Var, Aggref, or upper-level Param,
- * which wouldn't need extra parentheses. Otherwise, insert parens to
- * ensure the expression looks atomic.
- */
- need_paren = !(IsA(expr, Var) ||
- IsA(expr, Aggref) ||
- IsA(expr, Param));
- if (need_paren)
- appendStringInfoChar(context->buf, '(');
+ /* Switch attention to the ancestor plan node */
+ push_ancestor_plan(dpns, ancestor_cell, &save_dpns);
- get_rule_expr(expr, context, false);
+ /*
+ * Force prefixing of Vars, since they won't belong to the relation
+ * being scanned in the original plan node.
+ */
+ save_varprefix = context->varprefix;
+ context->varprefix = true;
- if (need_paren)
- appendStringInfoChar(context->buf, ')');
+ /*
+ * A Param's expansion is typically a Var, Aggref, or upper-level
+ * Param, which wouldn't need extra parentheses. Otherwise, insert
+ * parens to ensure the expression looks atomic.
+ */
+ need_paren = !(IsA(expr, Var) ||
+ IsA(expr, Aggref) ||
+ IsA(expr, Param));
+ if (need_paren)
+ appendStringInfoChar(context->buf, '(');
+
+ get_rule_expr(expr, context, false);
+
+ if (need_paren)
+ appendStringInfoChar(context->buf, ')');
+
+ context->varprefix = save_varprefix;
- context->varprefix = save_varprefix;
+ pop_ancestor_plan(dpns, &save_dpns);
- pop_ancestor_plan(dpns, &save_dpns);
+ return;
+ }
+
+ /*
+ * Not PARAM_EXEC, or couldn't find referent: just print $N.
+ */
+ appendStringInfo(context->buf, "$%d", param->paramid);
}
/*