openGauss学习——解析树结构补充

引言

在 SQL parser解读(12)—— analyze.cpp解析(上)和 SQL rewriter解读(3)—— rewriteHandler.cpp解读(三) 两篇博客中,我们简单介绍了查询解析过程中的重要结构体Query和RangeTblEntry。在本篇博客中,我们继续对结构体的部分字段以及解析树结构作补充说明。

RangeTblEntry

RangeTblEntry,即RTE结点,简单地说,是查询树节点中的表实体对象。RTE可以用来表示各种查询语句中包含的关系,其包含了很多我们在查询重写过程中会使用到的信息。其相关知识在 SQL rewriter解读(3)—— rewriteHandler.cpp解读(三) 中已经简单介绍,此处不再赘述。

Query

结构体Query用于保存语义解析所得的查询树细节,一条SQL语句的每个子句的语义分析结果会保存在Query的对应字段中。Query的定义在文件/src/include/parser/parse_node.h中。

typedef struct Query {
    NodeTag type;
    CmdType commandType; 
    QuerySource querySource; 
    uint64 queryId; 
    ……
    bool hasAggs;        
    bool hasWindowFuncs; 
    bool hasSubLinks;     
    bool hasDistinctOn;   
    bool hasRecursive;    
    bool hasModifyingCTE; 
    bool hasForUpdate;   
    bool hasRowSecurity;  
    bool hasSynonyms;    
    ……
    List* targetList; 
    List* starStart; 
    List* starEnd; 
    …… 
    Oid* fixed_paramTypes; 
    int fixed_numParams;
} Query;

这里简单补充下Query的几个比较重要的字段:

  • rtable:存储FROM子句生成的范围表(RTE)集合。rtable的数据类型为List *,其实际是一个列表指针,指向一个存储了许多RTE结点的列表,这些RTE结点中包含了很多查询重写和优化过程中会使用到的信息。

  • targetlist:targetlist用于存储查询语句中的目标属性语义分析结果。它包含了查询语句中所有被选取的属性,用于指定查询的输出结果。通过targetlist,我们可以获取查询结果中需要显示的属性以及它们的别名等信息。targetlist实际上也是一个List* 类型的指针,其指向存放了一组TargetEntry结点的列表。

  • jointree:指向查询包含的连接树的顶层结点,由FROM-WHERE clause转化而来。事实上,Query的jointree字段永远指向一个FromExpr类型的结构体,因为在查询语句中,连接操作只能够出现在FROM子句中,那么连接操作语法树的顶层结点一定为FROM表达式结点。

接下来介绍结构体TargetEntry和FromExpr。

TargetEntry

结构体 TargetEntry 用于表示查询中的目标属性。在openGauss中,查询语句通常由多个目标属性组成,每个目标属性都包含了属性名、表达式以及其他相关信息,而TargetEntry用于表示查询中的目标属性,帮助标识和处理目标属性在查询结果中的位置、名称以及其他相关信息。它的定义在文件/src/include/nodes/primnodes.h中。

typedef struct TargetEntry {
    Expr xpr;
    Expr* expr;            /* expression to evaluate */
    AttrNumber resno;      /* attribute number (see notes above) */
    char* resname;         /* name of the column (could be NULL) */
    Index ressortgroupref; /* nonzero if referenced by a sort/group
                            * clause */
    Oid resorigtbl;        /* OID of column's source table */
    AttrNumber resorigcol; /* column's number in source table */
    bool resjunk;          /* set to true to eliminate the attribute from
                            * final target list */
} TargetEntry;

下面介绍下TargetEntry的几个字段:

  • resno: 表示目标属性在查询结果中的位置编号。

  • resname: 表示目标属性的名称。

  • ressortgroupref: 表示目标属性所属的分组。

  • resorigtbl: 表示目标属性所属的原始表。

  • resorigcol: 表示目标属性所属的原始列。

TargetEntry结构体的主要作用之一是在查询执行过程中,帮助标识和处理目标属性。它可以通过指定resno来确定目标属性在查询结果中的位置,通过resname来获取目标属性的名称。同时,它可以通过ressortgroupref、resorigtbl和resorigcol等成员变量来帮助进行分组、关联和连接操作。

FromExpr & JoinExpr

FromExpr结构体是连接操作语法树的顶层结点,其定义也在文件/src/include/nodes/primnodes.h中。

typedef struct FromExpr {
    NodeTag type;
    List* fromlist; /* List of join subtrees */
    Node* quals;    /* qualifiers on join, if any */
} FromExpr;

此处简单介绍其各个字段:

  • FromExpr的字段 type 用来标识结点类型,其值为T_FromExpr。

  • 成员 fromlist 是一个List * 类型指针,其指向连接树的子树。具体地说,其通常指向一组JoinExpr类型的结点,这是因为通常在连接操作的语法树中FROM操作是JOIN操作的父结点。

  • 字段 quals 是用于存储连接的条件表达式树的。它是一个指向Node类型的指针,用于表示连接操作的条件。这个字段可以用于指定连接操作的过滤条件,以确定连接的结果集。

而JoinExpr是连接树中表示连接操作的语法结点,其定义也在/src/include/nodes/primnodes.h中。

typedef struct JoinExpr {
    NodeTag type;
    JoinType jointype; /* type of join */
    bool isNatural;    /* Natural join? Will need to shape table */
    Node* larg;        /* left subtree */
    Node* rarg;        /* right subtree */
    List* usingClause; /* USING clause, if any (list of String) */
    Node* quals;       /* qualifiers on join, if any */
    Alias* alias;      /* user-written alias clause, if any */
    int rtindex;       /* RT index assigned for join, or 0 */
} JoinExpr;

简单介绍几个比较重要的字段:

  • jointype:表示连接类型,包括左连接、右连接、内连接等等,可参考 SQL optimizer解读(3)—— 子链接提升。

  • larg & rarg:这是两个Node * 类型的指针,其指向参与连接操作的左右两个参数的RTE引用。说的具体些,larg和rarg各自指向一个RTE引用结点,即其指向的RTE结点的类型type字段并不为T_RangeTblEntry,而是T_RangeTblRef;这表示其指向的RTE结点并不为实体表,而是通过某些字段与一个实体关系表结点RTE相关联。总之,JoinExpr的larg和rarg字段可以帮助我们找到参与连接操作的两个关系表。

  • rtindex:RTE结点也拥有这个字段,其表示range table中对应的某个实体RTE结点的索引值,上面所述的T_RangeTblRef类型的RTE结点也是通过这个字段来实现与range table中某个实体RTE的一对一绑定。事实上,range table中对于连接操作JOIN也有一个实体RTE结点,因此JoinExpr也具有这一字段,用来与这个RTE结点相关联。

  • quals:存储连接操作的条件表达式树。这个字段可以用于指定连接操作的过滤条件,以确定连接的结果集。

举个例子,比如下面这个FROM-WHERE 语句:

SELECT … FROM table1 LEFT JOIN table2; 

其对应连接部分的语法树,即连接树表示如下:

openGauss学习——解析树结构补充_第1张图片

而其结构体之间的关联关系表示如下。

openGauss学习——解析树结构补充_第2张图片

接下来我们把前面介绍的内容串起来,举个简单的例子方便理解。例如如下两个十分简单的实体表table1、table2:

openGauss学习——解析树结构补充_第3张图片

基于这两个表的查询语句 SELECT table1.a as c1, table1.b as c2, table3.d as c3 FROM table1,table2 WHERE table1.b == table2.c;所对应的各个结构体之间的关联关系,以及FROM语句生成的RangeTblEntry结点、TargetEntry结点以及作用于FROM语句的连接操作条件树就可以总结绘制如下图:

openGauss学习——解析树结构补充_第4张图片

你可能感兴趣的:(学习,数据库)