zoukankan      html  css  js  c++  java
  • PostgreSQL 的 target_list分析(四)

    根据 <PostgreSQL 数据库内核分析>200和201页的说法,

    ResTarget 应该指向 ColumnRef 。这是如何实现的呢?

    target_list:                                
                target_el                { $$ = list_make1($1); }    
                | target_list ',' target_el                { $$ = lappend($1, $3); } 
            ;                        
                                    
    target_el:    a_expr AS ColLabel                            
                    {                
                        $$ = makeNode(ResTarget);            
                        $$->name = $3;            
                        $$->indirection = NIL;            
                        $$->val = (Node *)$1;            
                        $$->location = @1;            
                    }                
                /*                    
                 * We support omitting AS only for column labels that aren't  
                 * any known keyword.  There is an ambiguity against postfix
                 * operators: is "a ! b" an infix expression, or a postfix 
                 * expression and a column label?  We prefer to resolve this 
                 * as an infix expression, which we accomplish by assigning  
                 * IDENT a precedence higher than POSTFIXOP.                    
                 */                    
        | a_expr IDENT                            
                    {                
                        $$ = makeNode(ResTarget);            
                        $$->name = $2;            
                        $$->indirection = NIL;            
                        $$->val = (Node *)$1;            
                        $$->location = @1;            
                    }                
        | a_expr                            
                    {                
                        $$ = makeNode(ResTarget);            
                        $$->name = NULL;            
                        $$->indirection = NIL;            
                        $$->val = (Node *)$1;            
                        $$->location = @1; 
                    }                
                | '*'                    
                    {                
                        ColumnRef *n = makeNode(ColumnRef);            
                        n->fields = list_make1(makeNode(A_Star));            
                        n->location = @1;            
                                    
                        $$ = makeNode(ResTarget);            
                        $$->name = NULL;            
                        $$->indirection = NIL;            
                        $$->val = (Node *)n;            
                        $$->location = @1;            
                    }                
            ;                        

     和

    a_expr:     c_expr        
    { $$ = $1; } | a_expr TYPECAST Typename { $$ = makeTypeCast($1, $3, @2); } | a_expr COLLATE any_name { CollateClause *n = makeNode(CollateClause); n->arg = $1; n->collname = $3; n->location = @2; $$ = (Node *) n; }
    ...

    c_expr:     columnref                               { $$ = $1; }
                | AexprConst                            { $$ = $1; }
                | PARAM opt_indirection                            
                    {                        
                        ParamRef *p = makeNode(ParamRef);                    
                        p->number = $1;                    
                        p->location = @1;                    
                        if ($2)                    
                        {                    
                            A_Indirection *n = makeNode(A_Indirection);                
                            n->arg = (Node *) p;                
                            n->indirection = check_indirection($2, yyscanner);                
                            $$ = (Node *) n;                
                        }                    
                        else                    
                            $$ = (Node *) p;                
                    }                        
                | '(' a_expr ')' opt_indirection                            
                    {                        
                        if ($4)                    
                        {                    
                            A_Indirection *n = makeNode(A_Indirection);                
                            n->arg = $2;                
                            n->indirection = check_indirection($4, yyscanner);                
                            $$ = (Node *)n;                
                        }                    
                        else                    
                            $$ = $2;                
                    }                        
                | case_expr                            
                    { $$ = $1; }                        
                | func_expr                            
                    { $$ = $1; }                        
                | select_with_parens            %prec UMINUS                
                    {                        
                        SubLink *n = makeNode(SubLink);                    
                        n->subLinkType = EXPR_SUBLINK;                    
                        n->testexpr = NULL;                    
                        n->operName = NIL;                    
                        n->subselect = $1;                    
                        n->location = @1;                    
                        $$ = (Node *)n;                    
                    }                        
                | EXISTS select_with_parens                            
                    {                        
                        SubLink *n = makeNode(SubLink);                    
                        n->subLinkType = EXISTS_SUBLINK;                    
                        n->testexpr = NULL;                    
                        n->operName = NIL;                    
                        n->subselect = $2;                    
                        n->location = @1;                    
                        $$ = (Node *)n;                    
                    }                        
                | ARRAY select_with_parens                            
                    {                        
                        SubLink *n = makeNode(SubLink);                    
                        n->subLinkType = ARRAY_SUBLINK;                    
                        n->testexpr = NULL;                    
                        n->operName = NIL;                    
                        n->subselect = $2;                    
                        n->location = @1;                    
                        $$ = (Node *)n;                    
                    }                        
                | ARRAY array_expr                            
                    {                        
                        A_ArrayExpr *n = (A_ArrayExpr *) $2;                    
                        Assert(IsA(n, A_ArrayExpr));                    
                        /* point outermost A_ArrayExpr to the ARRAY keyword */                    
                        n->location = @1;                    
                        $$ = (Node *)n;                    
                    }                        
                | row                            
                    {                        
                        RowExpr *r = makeNode(RowExpr);                    
                        r->args = $1;                    
                        r->row_typeid = InvalidOid;    /* not analyzed yet */                
                        r->location = @1;                    
                        $$ = (Node *)r;                    
                    }                        
            ;                                

    这个时候,距离ColumnRef 就已经不远了。

    然后挑选最简单的情况:

    columnref:    ColId                                
                    {                    
                        $$ = makeColumnRef($1, NIL, @1, yyscanner);                
                    }                    
        | ColId indirection                                
                    {                    
                        $$ = makeColumnRef($1, $2, @1, yyscanner);                
                    }                    
        ;                                

    查了一下, 原来 makeColumnRef 就在 gram.y 里面:

    static Node *                                                                
    makeColumnRef(char *colname, List *indirection, 
                  int location, core_yyscan_t yyscanner)
    {                                                                
        /*                                                            
         * Generate a ColumnRef node, with an A_Indirection node added if there 
         * is any subscripting in the specified indirection list.  However,
         * any field selection at the start of the indirection list must be 
         * transposed into the "fields" part of the ColumnRef node. 
         */                                                            
        ColumnRef  *c = makeNode(ColumnRef);                                                            
        int        nfields = 0;                                                    
        ListCell *l;                                                            
                                                                    
        c->location = location; 
        foreach(l, indirection)
        {                                                            
            if (IsA(lfirst(l), A_Indices)) 
            {                                                        
                A_Indirection *i = makeNode(A_Indirection);
                                                                    
                if (nfields == 0)                                                    
                {                                                    
                    /* easy case - all indirection goes to A_Indirection */ 
                    c->fields = list_make1(makeString(colname));                                                
                    i->indirection = check_indirection(indirection, yyscanner);                                                
                }                                                    
                else                                                    
                {                                                    
                    /* got to split the list in two */
                    i->indirection = check_indirection(
    list_copy_tail(indirection, nfields),yyscanner); indirection
    = list_truncate(indirection, nfields); c->fields = lcons(makeString(colname), indirection); } i->arg = (Node *) c; return (Node *) i; } else if (IsA(lfirst(l), A_Star)) { /* We only allow '*' at the end of a ColumnRef */ if (lnext(l) != NULL) parser_yyerror("improper use of \"*\""); } nfields++; } /* No subscripting, so all indirection gets added to field list */ c->fields = lcons(makeString(colname), indirection); return (Node *) c; }

    这个

    ColumnRef  *c = makeNode(ColumnRef);

    c->fields = list_make1(makeString(colname)); 将 字段 赋予了 ColumnRef。

    可以看出,语法分析是一层套着一层。而整个语法分析的目的,就是逐层地构建一个语法分析树形结构。

  • 相关阅读:
    垂直margin为什么会重叠
    forEach()和for/in循环的缺点与for-of循环
    使用CleanWebpackPlugin插件报错原因:CleanWebpackPlugin is not a constructor
    Vue中常用的组件库
    Vue中使用keep-alive优化网页性能
    Vue中router路由异步加载组件-优化性能
    面试题-JS中的作用域相关问题
    JS中的垃圾回收机制
    【转】 SpringMVC详解(三)------基于注解的入门实例
    【转】 SpringMVC详解(二)------详细架构
  • 原文地址:https://www.cnblogs.com/gaojian/p/2678905.html
Copyright © 2011-2022 走看看