暂无图片
暂无图片
暂无图片
暂无图片
暂无图片

PostgreSQL查询引擎——General Expressions Grammar之GROUPING

肥叔菌 2023-02-13
434

General expressions语法规则定义在src/backend/parser/gram.y文件中,其是表达式语法的核心。有两种表达式类型:a_expr
是不受限制的类型,b_expr
是必须在某些地方使用的子集,以避免移位/减少冲突。例如,我们不能将BETWEEN
作为BETWEEN a_expr AND a_exp
,因为AND
的使用与AND
作为布尔运算符冲突。因此,b_expr
BETWEEN
中使用,我们从b_expr
中删除布尔关键字。请注意,( a_expr )
b_expr
,因此始终可以使用无限制表达式,方法是用括号将其括起来。c_expr
a_expr
b_expr
共同的所有乘积;它被分解出来只是为了消除冗余编码。注意涉及多个terminal token的产出productions。默认情况下,bison将为此类productions分配其最后一个terminal的优先级,但在几乎所有情况下,您都希望它是第一个terminal的优先权;否则你不会得到你期望的行为!因此,我们可以自由使用%prec
注释来设置优先级。

productions expression

c_expr
a_expr
b_expr
所共有的规则,递归引用a_expr
b_expr
的productions通常不能出现在c_expr
规则中。但是,可以引用出现在括号内的a_exprs
,例如函数参数;这不会给b_expr
语法带来歧义。productions that refer recursively to a_expr or b_expr mostly cannot appear here. However, it’s OK to refer to a_exprs that occur inside parentheses, such as function arguments; that cannot introduce ambiguity to the b_expr syntax.

规则十:GROUPING '(' expr_list ')'
 GroupingFunc是GROUPING()表达式的节点结构体,其行为在许多方面类似于聚合函数(例如,它“属于”一个特定的查询级别,可能不是直接包含它的查询级别),但在一个重要方面也有所不同:它从不计算其参数,它们只从它所属的查询级别的GROUP BY子句中指定表达式。该规范纯粹通过语法替换来定义GROUPING()的求值,但为了优化目的,我们将其作为一个实际表达式,以便一个Agg节点可以同时处理多个分组集。评估结果只需要列位置来对照投影的分组集进行检查。然而,为了使EXPLAIN产生有意义的输出,我们必须保留原始表达式,因为expression deparse没有给我们任何可行的方法来获取GROUP BY子句。此外,我们将两个GroupingFunc节点视为相等,如果它们具有相等的参数列表和agglevelsup,而不比较refs和cols注释。在原始解析输出中,我们只有参数列表;parse analysis填充refs列表,而planner填充cols列表。A GroupingFunc is a GROUPING(…) expression, which behaves in many ways like an aggregate function (e.g. it “belongs” to a specific query level, which might not be the one immediately containing it), but also differs in an important respect: it never evaluates its arguments, they merely designate expressions from the GROUP BY clause of the query level to which it belongs. The spec defines the evaluation of GROUPING() purely by syntactic replacement, but we make it a real expression for optimization purposes so that one Agg node can handle multiple grouping sets at once. Evaluating the result only needs the column positions to check against the grouping set being projected. However, for EXPLAIN to produce meaningful output, we have to keep the original expressions around, since expression deparse does not give us any feasible way to get at the GROUP BY clause. Also, we treat two GroupingFunc nodes as equal if they have equal arguments lists and agglevelsup, without comparing the refs and cols annotations.In raw parse output we have only the args list; parse analysis fills in the refs list, and the planner fills in the cols list.

          | GROUPING '(' expr_list ')'
    {
    GroupingFunc *g = makeNode(GroupingFunc);
    g->args = $3;
    g->location = @1;
    $$ = (Node *)g;
    }
    typedef struct GroupingFunc{
    Expr xpr;
    List *args; /* arguments, not evaluated but kept for benefit of EXPLAIN etc. */
    List *refs; /* ressortgrouprefs of arguments */
    List *cols; /* actual column positions set by planner */
    Index agglevelsup; /* same as Aggref.agglevelsup */
    int location; /* token location */
    } GroupingFunc;

    Node *transformGroupingFunc(ParseState *pstate, GroupingFunc *p)
    函数定义在src/backend/parser/parse_agg.c文件中,用于转换GROUPING表达式。调用transformExpr处理GroupingFunc的args列表成员。

      Node *transformGroupingFunc(ParseState *pstate, GroupingFunc *p){
      ListCell *lc;
      List *args = p->args;

      GroupingFunc *result = makeNode(GroupingFunc);
      if (list_length(args) > 31) ereport(ERROR, (errcode(ERRCODE_TOO_MANY_ARGUMENTS), errmsg("GROUPING must have fewer than 32 arguments"), parser_errposition(pstate, p->location)));

      List *result_list = NIL;
      foreach(lc, args)
      {
      Node *current_result = transformExpr(pstate, (Node *) lfirst(lc), pstate->p_expr_kind);
      result_list = lappend(result_list, current_result); /* acceptability of expressions is checked later */
      }


      result->args = result_list; result->location = p->location;
      check_agglevels_and_constraints(pstate, (Node *) result);


      return (Node *) result;
      }

      欢迎关注微信公众号肥叔菌PostgreSQL数据库专栏:




      文章转载自肥叔菌,如果涉嫌侵权,请发送邮件至:contact@modb.pro进行举报,并提供相关证据,一经查实,墨天轮将立刻删除相关内容。

      评论