diff options
Diffstat (limited to 'src/backend/utils/adt/ruleutils.c')
-rw-r--r-- | src/backend/utils/adt/ruleutils.c | 217 |
1 files changed, 182 insertions, 35 deletions
diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 298eebf5e67..0a77400a801 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -44,6 +44,7 @@ #include "nodes/nodeFuncs.h" #include "optimizer/tlist.h" #include "parser/keywords.h" +#include "parser/parse_node.h" #include "parser/parse_agg.h" #include "parser/parse_func.h" #include "parser/parse_oper.h" @@ -105,6 +106,8 @@ typedef struct int wrapColumn; /* max line length, or -1 for no limit */ int indentLevel; /* current indent level for prettyprint */ bool varprefix; /* TRUE to print prefixes on Vars */ + ParseExprKind special_exprkind; /* set only for exprkinds needing */ + /* special handling */ } deparse_context; /* @@ -369,9 +372,11 @@ static void get_target_list(List *targetList, deparse_context *context, static void get_setop_query(Node *setOp, Query *query, deparse_context *context, TupleDesc resultDesc); -static Node *get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, +static Node *get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context); +static void get_rule_groupingset(GroupingSet *gset, List *targetlist, + bool omit_parens, deparse_context *context); static void get_rule_orderby(List *orderList, List *targetList, bool force_colno, deparse_context *context); static void get_rule_windowclause(Query *query, deparse_context *context); @@ -419,8 +424,9 @@ static void printSubscripts(ArrayRef *aref, deparse_context *context); static char *get_relation_name(Oid relid); static char *generate_relation_name(Oid relid, List *namespaces); static char *generate_function_name(Oid funcid, int nargs, - List *argnames, Oid *argtypes, - bool has_variadic, bool *use_variadic_p); + List *argnames, Oid *argtypes, + bool has_variadic, bool *use_variadic_p, + ParseExprKind special_exprkind); static char *generate_operator_name(Oid operid, Oid arg1, Oid arg2); static text *string_to_text(char *str); static char *flatten_reloptions(Oid relid); @@ -878,6 +884,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) context.prettyFlags = pretty ? PRETTYFLAG_PAREN | PRETTYFLAG_INDENT : PRETTYFLAG_INDENT; context.wrapColumn = WRAP_COLUMN_DEFAULT; context.indentLevel = PRETTYINDENT_STD; + context.special_exprkind = EXPR_KIND_NONE; get_rule_expr(qual, &context, false); @@ -887,7 +894,7 @@ pg_get_triggerdef_worker(Oid trigid, bool pretty) appendStringInfo(&buf, "EXECUTE PROCEDURE %s(", generate_function_name(trigrec->tgfoid, 0, NIL, NULL, - false, NULL)); + false, NULL, EXPR_KIND_NONE)); if (trigrec->tgnargs > 0) { @@ -2502,6 +2509,7 @@ deparse_expression_pretty(Node *expr, List *dpcontext, context.prettyFlags = prettyFlags; context.wrapColumn = WRAP_COLUMN_DEFAULT; context.indentLevel = startIndent; + context.special_exprkind = EXPR_KIND_NONE; get_rule_expr(expr, &context, showimplicit); @@ -4112,6 +4120,7 @@ make_ruledef(StringInfo buf, HeapTuple ruletup, TupleDesc rulettc, context.prettyFlags = prettyFlags; context.wrapColumn = WRAP_COLUMN_DEFAULT; context.indentLevel = PRETTYINDENT_STD; + context.special_exprkind = EXPR_KIND_NONE; set_deparse_for_query(&dpns, query, NIL); @@ -4307,6 +4316,7 @@ get_query_def(Query *query, StringInfo buf, List *parentnamespace, context.prettyFlags = prettyFlags; context.wrapColumn = wrapColumn; context.indentLevel = startIndent; + context.special_exprkind = EXPR_KIND_NONE; set_deparse_for_query(&dpns, query, parentnamespace); @@ -4677,7 +4687,7 @@ get_basic_select_query(Query *query, deparse_context *context, SortGroupClause *srt = (SortGroupClause *) lfirst(l); appendStringInfoString(buf, sep); - get_rule_sortgroupclause(srt, query->targetList, + get_rule_sortgroupclause(srt->tleSortGroupRef, query->targetList, false, context); sep = ", "; } @@ -4702,20 +4712,43 @@ get_basic_select_query(Query *query, deparse_context *context, } /* Add the GROUP BY clause if given */ - if (query->groupClause != NULL) + if (query->groupClause != NULL || query->groupingSets != NULL) { + ParseExprKind save_exprkind; + appendContextKeyword(context, " GROUP BY ", -PRETTYINDENT_STD, PRETTYINDENT_STD, 1); - sep = ""; - foreach(l, query->groupClause) + + save_exprkind = context->special_exprkind; + context->special_exprkind = EXPR_KIND_GROUP_BY; + + if (query->groupingSets == NIL) { - SortGroupClause *grp = (SortGroupClause *) lfirst(l); + sep = ""; + foreach(l, query->groupClause) + { + SortGroupClause *grp = (SortGroupClause *) lfirst(l); - appendStringInfoString(buf, sep); - get_rule_sortgroupclause(grp, query->targetList, - false, context); - sep = ", "; + appendStringInfoString(buf, sep); + get_rule_sortgroupclause(grp->tleSortGroupRef, query->targetList, + false, context); + sep = ", "; + } } + else + { + sep = ""; + foreach(l, query->groupingSets) + { + GroupingSet *grp = lfirst(l); + + appendStringInfoString(buf, sep); + get_rule_groupingset(grp, query->targetList, true, context); + sep = ", "; + } + } + + context->special_exprkind = save_exprkind; } /* Add the HAVING clause if given */ @@ -4782,7 +4815,7 @@ get_target_list(List *targetList, deparse_context *context, * different from a whole-row Var). We need to call get_variable * directly so that we can tell it to do the right thing. */ - if (tle->expr && IsA(tle->expr, Var)) + if (tle->expr && (IsA(tle->expr, Var))) { attname = get_variable((Var *) tle->expr, 0, true, context); } @@ -5001,23 +5034,24 @@ get_setop_query(Node *setOp, Query *query, deparse_context *context, * Also returns the expression tree, so caller need not find it again. */ static Node * -get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno, +get_rule_sortgroupclause(Index ref, List *tlist, bool force_colno, deparse_context *context) { StringInfo buf = context->buf; TargetEntry *tle; Node *expr; - tle = get_sortgroupclause_tle(srt, tlist); + tle = get_sortgroupref_tle(ref, tlist); expr = (Node *) tle->expr; /* - * Use column-number form if requested by caller. Otherwise, if - * expression is a constant, force it to be dumped with an explicit cast - * as decoration --- this is because a simple integer constant is - * ambiguous (and will be misinterpreted by findTargetlistEntry()) if we - * dump it without any decoration. Otherwise, just dump the expression - * normally. + * Use column-number form if requested by caller. Otherwise, if expression + * is a constant, force it to be dumped with an explicit cast as decoration + * --- this is because a simple integer constant is ambiguous (and will be + * misinterpreted by findTargetlistEntry()) if we dump it without any + * decoration. If it's anything more complex than a simple Var, then force + * extra parens around it, to ensure it can't be misinterpreted as a cube() + * or rollup() construct. */ if (force_colno) { @@ -5026,13 +5060,92 @@ get_rule_sortgroupclause(SortGroupClause *srt, List *tlist, bool force_colno, } else if (expr && IsA(expr, Const)) get_const_expr((Const *) expr, context, 1); + else if (!expr || IsA(expr, Var)) + get_rule_expr(expr, context, true); else + { + /* + * We must force parens for function-like expressions even if + * PRETTY_PAREN is off, since those are the ones in danger of + * misparsing. For other expressions we need to force them + * only if PRETTY_PAREN is on, since otherwise the expression + * will output them itself. (We can't skip the parens.) + */ + bool need_paren = (PRETTY_PAREN(context) + || IsA(expr, FuncExpr) + || IsA(expr, Aggref) + || IsA(expr, WindowFunc)); + if (need_paren) + appendStringInfoString(context->buf, "("); get_rule_expr(expr, context, true); + if (need_paren) + appendStringInfoString(context->buf, ")"); + } return expr; } /* + * Display a GroupingSet + */ +static void +get_rule_groupingset(GroupingSet *gset, List *targetlist, + bool omit_parens, deparse_context *context) +{ + ListCell *l; + StringInfo buf = context->buf; + bool omit_child_parens = true; + char *sep = ""; + + switch (gset->kind) + { + case GROUPING_SET_EMPTY: + appendStringInfoString(buf, "()"); + return; + + case GROUPING_SET_SIMPLE: + { + if (!omit_parens || list_length(gset->content) != 1) + appendStringInfoString(buf, "("); + + foreach(l, gset->content) + { + Index ref = lfirst_int(l); + + appendStringInfoString(buf, sep); + get_rule_sortgroupclause(ref, targetlist, + false, context); + sep = ", "; + } + + if (!omit_parens || list_length(gset->content) != 1) + appendStringInfoString(buf, ")"); + } + return; + + case GROUPING_SET_ROLLUP: + appendStringInfoString(buf, "ROLLUP("); + break; + case GROUPING_SET_CUBE: + appendStringInfoString(buf, "CUBE("); + break; + case GROUPING_SET_SETS: + appendStringInfoString(buf, "GROUPING SETS ("); + omit_child_parens = false; + break; + } + + foreach(l, gset->content) + { + appendStringInfoString(buf, sep); + get_rule_groupingset(lfirst(l), targetlist, omit_child_parens, context); + sep = ", "; + } + + appendStringInfoString(buf, ")"); +} + +/* * Display an ORDER BY list. */ static void @@ -5052,7 +5165,7 @@ get_rule_orderby(List *orderList, List *targetList, TypeCacheEntry *typentry; appendStringInfoString(buf, sep); - sortexpr = get_rule_sortgroupclause(srt, targetList, + sortexpr = get_rule_sortgroupclause(srt->tleSortGroupRef, targetList, force_colno, context); sortcoltype = exprType(sortexpr); /* See whether operator is default < or > for datatype */ @@ -5152,7 +5265,7 @@ get_rule_windowspec(WindowClause *wc, List *targetList, SortGroupClause *grp = (SortGroupClause *) lfirst(l); appendStringInfoString(buf, sep); - get_rule_sortgroupclause(grp, targetList, + get_rule_sortgroupclause(grp->tleSortGroupRef, targetList, false, context); sep = ", "; } @@ -6879,6 +6992,16 @@ get_rule_expr(Node *node, deparse_context *context, get_agg_expr((Aggref *) node, context); break; + case T_GroupingFunc: + { + GroupingFunc *gexpr = (GroupingFunc *) node; + + appendStringInfoString(buf, "GROUPING("); + get_rule_expr((Node *) gexpr->args, context, true); + appendStringInfoChar(buf, ')'); + } + break; + case T_WindowFunc: get_windowfunc_expr((WindowFunc *) node, context); break; @@ -7917,7 +8040,8 @@ get_func_expr(FuncExpr *expr, deparse_context *context, generate_function_name(funcoid, nargs, argnames, argtypes, expr->funcvariadic, - &use_variadic)); + &use_variadic, + context->special_exprkind)); nargs = 0; foreach(l, expr->args) { @@ -7949,7 +8073,8 @@ get_agg_expr(Aggref *aggref, deparse_context *context) generate_function_name(aggref->aggfnoid, nargs, NIL, argtypes, aggref->aggvariadic, - &use_variadic), + &use_variadic, + context->special_exprkind), (aggref->aggdistinct != NIL) ? "DISTINCT " : ""); if (AGGKIND_IS_ORDERED_SET(aggref->aggkind)) @@ -8039,7 +8164,8 @@ get_windowfunc_expr(WindowFunc *wfunc, deparse_context *context) appendStringInfo(buf, "%s(", generate_function_name(wfunc->winfnoid, nargs, argnames, argtypes, - false, NULL)); + false, NULL, + context->special_exprkind)); /* winstar can be set only in zero-argument aggregates */ if (wfunc->winstar) appendStringInfoChar(buf, '*'); @@ -9291,7 +9417,8 @@ generate_relation_name(Oid relid, List *namespaces) */ static char * generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, - bool has_variadic, bool *use_variadic_p) + bool has_variadic, bool *use_variadic_p, + ParseExprKind special_exprkind) { char *result; HeapTuple proctup; @@ -9306,6 +9433,7 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, int p_nvargs; Oid p_vatype; Oid *p_true_typeids; + bool force_qualify = false; proctup = SearchSysCache1(PROCOID, ObjectIdGetDatum(funcid)); if (!HeapTupleIsValid(proctup)) @@ -9314,6 +9442,16 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, proname = NameStr(procform->proname); /* + * Due to parser hacks to avoid needing to reserve CUBE, we need to force + * qualification in some special cases. + */ + if (special_exprkind == EXPR_KIND_GROUP_BY) + { + if (strcmp(proname, "cube") == 0 || strcmp(proname, "rollup") == 0) + force_qualify = true; + } + + /* * Determine whether VARIADIC should be printed. We must do this first * since it affects the lookup rules in func_get_detail(). * @@ -9344,14 +9482,23 @@ generate_function_name(Oid funcid, int nargs, List *argnames, Oid *argtypes, /* * The idea here is to schema-qualify only if the parser would fail to * resolve the correct function given the unqualified func name with the - * specified argtypes and VARIADIC flag. + * specified argtypes and VARIADIC flag. But if we already decided to + * force qualification, then we can skip the lookup and pretend we didn't + * find it. */ - p_result = func_get_detail(list_make1(makeString(proname)), - NIL, argnames, nargs, argtypes, - !use_variadic, true, - &p_funcid, &p_rettype, - &p_retset, &p_nvargs, &p_vatype, - &p_true_typeids, NULL); + if (!force_qualify) + p_result = func_get_detail(list_make1(makeString(proname)), + NIL, argnames, nargs, argtypes, + !use_variadic, true, + &p_funcid, &p_rettype, + &p_retset, &p_nvargs, &p_vatype, + &p_true_typeids, NULL); + else + { + p_result = FUNCDETAIL_NOTFOUND; + p_funcid = InvalidOid; + } + if ((p_result == FUNCDETAIL_NORMAL || p_result == FUNCDETAIL_AGGREGATE || p_result == FUNCDETAIL_WINDOWFUNC) && |