deparse_context *context);
static char *get_variable(Var *var, int levelsup, bool istoplevel,
deparse_context *context);
+static void get_special_variable(Node *node, deparse_context *context,
+ void *private);
+static void resolve_special_varno(Node *node, deparse_context *context,
+ void *private,
+ void (*callback) (Node *, deparse_context *, void *));
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 get_oper_expr(OpExpr *expr, deparse_context *context);
static void get_func_expr(FuncExpr *expr, deparse_context *context,
bool showimplicit);
-static void get_agg_expr(Aggref *aggref, deparse_context *context);
+static void get_agg_expr(Aggref *aggref, deparse_context *context,
+ Aggref *original_aggref);
+static void get_agg_combine_expr(Node *node, deparse_context *context,
+ void *private);
static void get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context);
static void get_coercion_expr(Node *arg, deparse_context *context,
Oid resulttype, int32 resulttypmod,
}
}
-
/*
* Display a Var appropriately.
*
colinfo = deparse_columns_fetch(var->varno, dpns);
attnum = var->varattno;
}
- else if (var->varno == OUTER_VAR && dpns->outer_tlist)
- {
- TargetEntry *tle;
- deparse_namespace save_dpns;
-
- tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
- if (!tle)
- elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
-
- Assert(netlevelsup == 0);
- push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
-
- /*
- * Force parentheses because our caller probably assumed a Var is a
- * simple expression.
- */
- if (!IsA(tle->expr, Var))
- appendStringInfoChar(buf, '(');
- get_rule_expr((Node *) tle->expr, context, true);
- if (!IsA(tle->expr, Var))
- appendStringInfoChar(buf, ')');
-
- pop_child_plan(dpns, &save_dpns);
- return NULL;
- }
- else if (var->varno == INNER_VAR && dpns->inner_tlist)
- {
- TargetEntry *tle;
- deparse_namespace save_dpns;
-
- tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
- if (!tle)
- elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
-
- Assert(netlevelsup == 0);
- push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
-
- /*
- * Force parentheses because our caller probably assumed a Var is a
- * simple expression.
- */
- if (!IsA(tle->expr, Var))
- appendStringInfoChar(buf, '(');
- get_rule_expr((Node *) tle->expr, context, true);
- if (!IsA(tle->expr, Var))
- appendStringInfoChar(buf, ')');
-
- pop_child_plan(dpns, &save_dpns);
- return NULL;
- }
- else if (var->varno == INDEX_VAR && dpns->index_tlist)
- {
- TargetEntry *tle;
-
- tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
- if (!tle)
- elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
-
- Assert(netlevelsup == 0);
-
- /*
- * Force parentheses because our caller probably assumed a Var is a
- * simple expression.
- */
- if (!IsA(tle->expr, Var))
- appendStringInfoChar(buf, '(');
- get_rule_expr((Node *) tle->expr, context, true);
- if (!IsA(tle->expr, Var))
- appendStringInfoChar(buf, ')');
-
- return NULL;
- }
else
{
- elog(ERROR, "bogus varno: %d", var->varno);
- return NULL; /* keep compiler quiet */
+ resolve_special_varno((Node *) var, context, NULL,
+ get_special_variable);
+ return NULL;
}
/*
return attname;
}
+/*
+ * Deparse a Var which references OUTER_VAR, INNER_VAR, or INDEX_VAR. This
+ * routine is actually a callback for get_special_varno, which handles finding
+ * the correct TargetEntry. We get the expression contained in that
+ * TargetEntry and just need to deparse it, a job we can throw back on
+ * get_rule_expr.
+ */
+static void
+get_special_variable(Node *node, deparse_context *context, void *private)
+{
+ StringInfo buf = context->buf;
+
+ /*
+ * Force parentheses because our caller probably assumed a Var is a simple
+ * expression.
+ */
+ if (!IsA(node, Var))
+ appendStringInfoChar(buf, '(');
+ get_rule_expr(node, context, true);
+ if (!IsA(node, Var))
+ appendStringInfoChar(buf, ')');
+}
+
+/*
+ * Chase through plan references to special varnos (OUTER_VAR, INNER_VAR,
+ * INDEX_VAR) until we find a real Var or some kind of non-Var node; then,
+ * invoke the callback provided.
+ */
+static void
+resolve_special_varno(Node *node, deparse_context *context, void *private,
+ void (*callback) (Node *, deparse_context *, void *))
+{
+ Var *var;
+ deparse_namespace *dpns;
+
+ /* If it's not a Var, invoke the callback. */
+ if (!IsA(node, Var))
+ {
+ callback(node, context, private);
+ return;
+ }
+
+ /* Find appropriate nesting depth */
+ var = (Var *) node;
+ dpns = (deparse_namespace *) list_nth(context->namespaces,
+ var->varlevelsup);
+
+ /*
+ * It's a special RTE, so recurse.
+ */
+ if (var->varno == OUTER_VAR && dpns->outer_tlist)
+ {
+ TargetEntry *tle;
+ deparse_namespace save_dpns;
+
+ tle = get_tle_by_resno(dpns->outer_tlist, var->varattno);
+ if (!tle)
+ elog(ERROR, "bogus varattno for OUTER_VAR var: %d", var->varattno);
+
+ push_child_plan(dpns, dpns->outer_planstate, &save_dpns);
+ resolve_special_varno((Node *) tle->expr, context, private, callback);
+ pop_child_plan(dpns, &save_dpns);
+ return;
+ }
+ else if (var->varno == INNER_VAR && dpns->inner_tlist)
+ {
+ TargetEntry *tle;
+ deparse_namespace save_dpns;
+
+ tle = get_tle_by_resno(dpns->inner_tlist, var->varattno);
+ if (!tle)
+ elog(ERROR, "bogus varattno for INNER_VAR var: %d", var->varattno);
+
+ push_child_plan(dpns, dpns->inner_planstate, &save_dpns);
+ resolve_special_varno((Node *) tle->expr, context, private, callback);
+ pop_child_plan(dpns, &save_dpns);
+ return;
+ }
+ else if (var->varno == INDEX_VAR && dpns->index_tlist)
+ {
+ TargetEntry *tle;
+
+ tle = get_tle_by_resno(dpns->index_tlist, var->varattno);
+ if (!tle)
+ elog(ERROR, "bogus varattno for INDEX_VAR var: %d", var->varattno);
+
+ resolve_special_varno((Node *) tle->expr, context, private, callback);
+ return;
+ }
+ else if (var->varno < 1 || var->varno > list_length(dpns->rtable))
+ elog(ERROR, "bogus varno: %d", var->varno);
+
+ /* Not special. Just invoke the callback. */
+ callback(node, context, private);
+}
/*
* Get the name of a field of an expression of composite type. The
break;
case T_Aggref:
- get_agg_expr((Aggref *) node, context);
+ get_agg_expr((Aggref *) node, context, (Aggref *) node);
break;
case T_GroupingFunc:
* get_agg_expr - Parse back an Aggref node
*/
static void
-get_agg_expr(Aggref *aggref, deparse_context *context)
+get_agg_expr(Aggref *aggref, deparse_context *context,
+ Aggref *original_aggref)
{
StringInfo buf = context->buf;
Oid argtypes[FUNC_MAX_ARGS];
int nargs;
bool use_variadic;
+ /*
+ * For a combining aggregate, we look up and deparse the corresponding
+ * partial aggregate instead. This is necessary because our input
+ * argument list has been replaced; the new argument list always has just
+ * one element, which will point to a partial Aggref that supplies us with
+ * transition states to combine.
+ */
+ if (aggref->aggcombine)
+ {
+ TargetEntry *tle = linitial(aggref->args);
+
+ Assert(list_length(aggref->args) == 1);
+ Assert(IsA(tle, TargetEntry));
+ resolve_special_varno((Node *) tle->expr, context, original_aggref,
+ get_agg_combine_expr);
+ return;
+ }
+
+ /* Mark as PARTIAL, if appropriate. */
+ if (original_aggref->aggpartial)
+ appendStringInfoString(buf, "PARTIAL ");
+
/* Extract the argument types as seen by the parser */
nargs = get_aggregate_argtypes(aggref, argtypes);
appendStringInfoChar(buf, ')');
}
+/*
+ * This is a helper function for get_agg_expr(). It's used when we deparse
+ * a combining Aggref; resolve_special_varno locates the corresponding partial
+ * Aggref and then calls this.
+ */
+static void
+get_agg_combine_expr(Node *node, deparse_context *context, void *private)
+{
+ Aggref *aggref;
+ Aggref *original_aggref = private;
+
+ if (!IsA(node, Aggref))
+ elog(ERROR, "combining Aggref does not point to an Aggref");
+
+ aggref = (Aggref *) node;
+ get_agg_expr(aggref, context, original_aggref);
+}
+
/*
* get_windowfunc_expr - Parse back a WindowFunc node
*/