|
|
|
@ -392,6 +392,11 @@ static void get_rule_windowspec(WindowClause *wc, List *targetList,
|
|
|
|
|
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);
|
|
|
|
@ -407,7 +412,10 @@ static void get_rule_expr_toplevel(Node *node, 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,
|
|
|
|
@ -5877,7 +5885,6 @@ get_utility_query_def(Query *query, deparse_context *context)
|
|
|
|
|
}
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
|
* Display a Var appropriately.
|
|
|
|
|
*
|
|
|
|
@ -5930,82 +5937,11 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
|
|
|
|
|
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;
|
|
|
|
|
}
|
|
|
|
|
|
|
|
|
|
/*
|
|
|
|
@ -6118,6 +6054,101 @@ get_variable(Var *var, int levelsup, bool istoplevel, deparse_context *context)
|
|
|
|
|
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
|
|
|
|
@ -7080,7 +7111,7 @@ get_rule_expr(Node *node, deparse_context *context,
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_Aggref:
|
|
|
|
|
get_agg_expr((Aggref *) node, context);
|
|
|
|
|
get_agg_expr((Aggref *) node, context, (Aggref *) node);
|
|
|
|
|
break;
|
|
|
|
|
|
|
|
|
|
case T_GroupingFunc:
|
|
|
|
@ -8236,13 +8267,36 @@ get_func_expr(FuncExpr *expr, deparse_context *context,
|
|
|
|
|
* 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);
|
|
|
|
|
|
|
|
|
@ -8311,6 +8365,24 @@ get_agg_expr(Aggref *aggref, deparse_context *context)
|
|
|
|
|
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
|
|
|
|
|
*/
|
|
|
|
|