PostgreSQL 的 target_list分析(四)

本文涉及的产品
云原生数据库 PolarDB MySQL 版,通用型 2核4GB 50GB
云原生数据库 PolarDB PostgreSQL 版,标准版 2核4GB 50GB
简介:
根据 <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。

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


本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2012/09/10/2678905.html,如需转载请自行联系原作者
相关实践学习
使用PolarDB和ECS搭建门户网站
本场景主要介绍基于PolarDB和ECS实现搭建门户网站。
阿里云数据库产品家族及特性
阿里云智能数据库产品团队一直致力于不断健全产品体系,提升产品性能,打磨产品功能,从而帮助客户实现更加极致的弹性能力、具备更强的扩展能力、并利用云设施进一步降低企业成本。以云原生+分布式为核心技术抓手,打造以自研的在线事务型(OLTP)数据库Polar DB和在线分析型(OLAP)数据库Analytic DB为代表的新一代企业级云原生数据库产品体系, 结合NoSQL数据库、数据库生态工具、云原生智能化数据库管控平台,为阿里巴巴经济体以及各个行业的企业客户和开发者提供从公共云到混合云再到私有云的完整解决方案,提供基于云基础设施进行数据从处理、到存储、再到计算与分析的一体化解决方案。本节课带你了解阿里云数据库产品家族及特性。
目录
相关文章
|
14天前
|
SQL 关系型数据库 MySQL
MySQL 窗口函数详解:分析性查询的强大工具
MySQL 窗口函数从 8.0 版本开始支持,提供了一种灵活的方式处理 SQL 查询中的数据。无需分组即可对行集进行分析,常用于计算排名、累计和、移动平均值等。基本语法包括 `function_name([arguments]) OVER ([PARTITION BY columns] [ORDER BY columns] [frame_clause])`,常见函数有 `ROW_NUMBER()`, `RANK()`, `DENSE_RANK()`, `SUM()`, `AVG()` 等。窗口框架定义了计算聚合值时应包含的行。适用于复杂数据操作和分析报告。
56 11
|
3月前
|
存储 缓存 关系型数据库
MySQL事务日志-Redo Log工作原理分析
事务的隔离性和原子性分别通过锁和事务日志实现,而持久性则依赖于事务日志中的`Redo Log`。在MySQL中,`Redo Log`确保已提交事务的数据能持久保存,即使系统崩溃也能通过重做日志恢复数据。其工作原理是记录数据在内存中的更改,待事务提交时写入磁盘。此外,`Redo Log`采用简单的物理日志格式和高效的顺序IO,确保快速提交。通过不同的落盘策略,可在性能和安全性之间做出权衡。
1719 14
|
3月前
|
存储 关系型数据库 MySQL
基于案例分析 MySQL 权限认证中的具体优先原则
【10月更文挑战第26天】本文通过具体案例分析了MySQL权限认证中的优先原则,包括全局权限、数据库级别权限和表级别权限的设置与优先级。全局权限优先于数据库级别权限,后者又优先于表级别权限。在权限冲突时,更严格的权限将被优先执行,确保数据库的安全性与资源合理分配。
|
3月前
|
SQL 关系型数据库 MySQL
MySQL 更新1000万条数据和DDL执行时间分析
MySQL 更新1000万条数据和DDL执行时间分析
196 4
|
3月前
|
SQL 自然语言处理 关系型数据库
Vanna使用ollama分析本地MySQL数据库
这篇文章详细介绍了如何使用Vanna结合Ollama框架来分析本地MySQL数据库,实现自然语言查询功能,包括环境搭建和配置流程。
338 0
|
4月前
|
Oracle NoSQL 关系型数据库
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
主流数据库对比:MySQL、PostgreSQL、Oracle和Redis的优缺点分析
690 2
|
4月前
|
存储 关系型数据库 MySQL
分析MySQL主从复制中AUTO_INCREMENT值不一致的问题
通过对 `AUTO_INCREMENT`不一致问题的深入分析和合理应对措施的实施,可以有效地维护MySQL主从复制环境中数据的一致性和完整性,确保数据库系统的稳定性和可靠性。
130 6
|
3月前
|
SQL 关系型数据库 MySQL
MySQL EXPLAIN该如何分析?
本文将详细介绍MySQL中`EXPLAIN`关键字的工作原理及结果字段解析,帮助优化查询性能。`EXPLAIN`可显示查询SQL的执行计划,其结果包括`id`、`select_type`、`table`等字段。通过具体示例和优化建议,帮助你理解和应用`EXPLAIN`,提升数据库查询效率。
142 0
|
4月前
|
存储 关系型数据库 MySQL
分析MySQL主从复制中AUTO_INCREMENT值不一致的问题
通过对 `AUTO_INCREMENT`不一致问题的深入分析和合理应对措施的实施,可以有效地维护MySQL主从复制环境中数据的一致性和完整性,确保数据库系统的稳定性和可靠性。
78 1
|
5月前
|
SQL 监控 关系型数据库
使用 pt-query-digest 工具分析 MySQL 慢日志
【8月更文挑战第5天】使用 pt-query-digest 工具分析 MySQL 慢日志
111 3
使用 pt-query-digest 工具分析 MySQL 慢日志