查询代码-caluse解析

文件路径

src/common/backend/parser/parse_clause.cpp

文件内容

宏常量

Java
/* clause types for findTargetlistEntrySQL92 */
#define ORDER_CLAUSE 0
#define GROUP_CLAUSE 1
#define DISTINCT_ON_CLAUSE 2
 
static const
char* const clauseText[] = {"ORDER BY", "GROUP BY", "DISTINCT ON"};

 三个宏常量分别表示三种不同的SQL子句类型:ORDER_CLAUSE、GROUP_CLAUSE和DISTINCT_ON_CLAUSE。这些常量用于在解析SQL查询语句时识别和处理不同的子句。

  1. ORDER_CLAUSE(ORDER  BY子句):用于对查询结果进行排序。按照指定的列或表达式的值升序或降序排列结果集。在SQL查询中,ORDER  BY子句通常出现在SELECT语句的末尾。
  1. GROUP_CLAUSE(GROUP  BY子句):用于对查询结果进行分组。根据指定的列或表达式的值将结果集分成不同的组。在SQL查询中,GROUP  BY子句也通常出现在SELECT语句的末尾。
  1. DISTINCT_ON_CLAUSE(DISTINCT  ON子句):用于过滤重复的数据行。与GROUP  BY子句类似,但是DISTINCT  ON子句可以根据多个列或表达式的值来过滤重复行。这个子句在SQL查询中也很常见。

clauseText是一个长度为3的字符串数组,其中包含了与每个子句类型对应的文本表示

关系语句查询和处理函数解析

Java
//
处理两个列表中共同的列名的情况
static void extractRemainingColumns(
    List* common_colnames, List* src_colnames, List* src_colvars, List** res_colnames, List** res_colvars);
//转换使用USING子句的JOIN操作
static Node* transformJoinUsingClause(
    ParseState* pstate, RangeTblEntry* leftRTE, RangeTblEntry* rightRTE, List* leftVars, List* rightVars);
转换关系表条目
static RangeTblEntry* transformTableEntry(
    ParseState* pstate, RangeVar* r, bool isFirstNode = true, bool isCreateView = false);
//转换公共表达式引用(CTEReference)的关系表条目
static RangeTblEntry* transformCTEReference(ParseState* pstate, RangeVar* r, CommonTableExpr* cte, Index levelsup);
//转换子查询(RangeSubselect)的关系表条目
static RangeTblEntry* transformRangeSubselect(ParseState* pstate, RangeSubselect* r);
//转换函数(RangeFunction)的关系表条目
static RangeTblEntry* transformRangeFunction(ParseState* pstate, RangeFunction* r);
//转换表抽样(RangeTableSample)的表抽样子句
static TableSampleClause* transformRangeTableSample(ParseState* pstate, RangeTableSample* rts);
//转换时间胶囊(RangeTimeCapsule)的时间胶囊子句
static TimeCapsuleClause* transformRangeTimeCapsule(ParseState* pstate, RangeTimeCapsule* rtc);

函数解析摘选:

transformJoinUsingClause()

Java
/* 从部分转换的使用列表构建完整的ON子句
* 其中,我们有左边和右边匹配列的节点列表
* 函数的返回值是一个经过转换的限定表达式*/
static Node* transformJoinUsingClause(
    ParseState* pstate, RangeTblEntry* leftRTE, RangeTblEntry* rightRTE, List* leftVars, List* rightVars)
{
    Node* result = NULL;
    ListCell* lvars = NULL;
    ListCell* rvars = NULL;

    /*
     * 通过构建一个未转换的操作符树来处理已经转换过的变量,以此进行一些简化处理
     * 但是这也意味着我们需要自己标记这些列需要SELECT权限,因为transformExpr()函数不会自动处理这个标记
     */
    forboth(lvars, leftVars, rvars, rightVars)
    {
        Var* lvar = (Var*)lfirst(lvars);
        Var* rvar = (Var*)lfirst(rvars);
        A_Expr* e = NULL;

        /* Require read access to the join variables */
        markVarForSelectPriv(pstate, lvar, leftRTE);
        markVarForSelectPriv(pstate, rvar, rightRTE);

        /* Now create the lvar = rvar join condition */
        e = makeSimpleA_Expr(AEXPR_OP, "=", (Node*)copyObject(lvar), (Node*)copyObject(rvar), -1);

        /* And combine into an AND clause, if multiple join columns */
        if (result == NULL)
            result = (Node*)e;
        else {
            A_Expr* a = NULL;

            a = makeA_Expr(AEXPR_AND, NIL, result, (Node*)e, -1);
            result = (Node*)a;
        }
    }

    /*
     * 由于引用已经是 Vars,并且肯定来自输入关系
     * 所以我们不必像 transformJoinOnClause() 一样进行额外的操作。
     * 只需要调用 transformExpr() 来修复运算符,就完成了。
     */
    result = transformExpr(pstate, result, EXPR_KIND_JOIN_USING);

    result = coerce_to_boolean(pstate, result, "JOIN/USING");

    return result;
}

函数功能:将 JOIN USING 子句转换为一个等值比较的表达式

入口参数:

  • ParseState* pstate表示查询的解析状态,
  • RangeTblEntry* leftRTE 和 RangeTblEntry* rightRTE分别表示左表达式和右表达式的关系表达式项,
  • List* leftVars 和 List* rightVars分别表示左表达式和右表达式的字段变量列表

出口参数:

  • Node* 类型的指针,表示转换后的等值比较表达式

函数内部逻辑:

  1. 遍历左表达式和右表达式的字段变量列表,对于每一对字段变量
  1. 首先标记这些变量可以被查询读取
  1. 然后创建一个等值比较操作符节点(A_Expr),将左字段变量和右字段变量作为操作数,并指定操作符为 =。如果存在多个字段变量,将它们的等值比较节点通过逻辑“AND”操作符 (A_Expr) 组合起来。
  1. 最后,将转换后的表达式作为参数传递给 transformExpr() 函数进行进一步的转换和验证,并使用 coerce_to_boolean() 函数将结果转换为布尔类型。

transformJoinUsingClause()

Java
/* 从部分转换的使用列表构建完整的ON子句。
 * 我们得到表示左侧和右侧匹配列的节点列表。
*  结果是一个转换后的条件表达式
 */
static Node* transformJoinUsingClause(
    ParseState* pstate, RangeTblEntry* leftRTE, RangeTblEntry* rightRTE, List* leftVars, List* rightVars)
{
    Node* result = NULL;
    ListCell* lvars = NULL;
    ListCell* rvars = NULL;

    /*
     * 构建一个未转换的操作树,其叶子节点是已经转换的变量
     * 这意味着我们必须标记列需要我们自己的SELECT权限;transformExpr()不会这样做
     */
    forboth(lvars, leftVars, rvars, rightVars)
    {
        Var* lvar = (Var*)lfirst(lvars);
        Var* rvar = (Var*)lfirst(rvars);
        A_Expr* e = NULL;

        /* Require read access to the join variables */
        markVarForSelectPriv(pstate, lvar, leftRTE);
        markVarForSelectPriv(pstate, rvar, rightRTE);

        /* Now create the lvar = rvar join condition */
        e = makeSimpleA_Expr(AEXPR_OP, "=", (Node*)copyObject(lvar), (Node*)copyObject(rvar), -1);

        /* And combine into an AND clause, if multiple join columns */
        if (result == NULL)
            result = (Node*)e;
        else {
            A_Expr* a = NULL;

            a = makeA_Expr(AEXPR_AND, NIL, result, (Node*)e, -1);
            result = (Node*)a;
        }
    }

    result = transformExpr(pstate, result, EXPR_KIND_JOIN_USING);

    result = coerce_to_boolean(pstate, result, "JOIN/USING");

    return result;
}

函数功能:根据给定的左右关系表条目(RangeTblEntry)、左侧变量列表和右侧变量列表,构建一个用于JOIN USING子句的操作树。该操作树的叶子节点是已经转换的变量,表示要进行连接的列

入口参数:

  • ParseState* pstate:解析状态,包含了当前查询的解析状态信息
  • RangeTblEntry* leftRTE:左侧关系表条目
  • RangeTblEntry* rightRTE:右侧关系表条目
  • List* leftVars:左侧变量列表
  • List* rightVars:右侧变量列表

出口参数:

  • Node*:表示JOIN USING子句的操作树

函数内部逻辑:

  1. 遍历左侧变量列表和右侧变量列表,对每一对变量进行以下操作:
  • 标记列需要进行SELECT权限,即调用markVarForSelectPriv()函数标记变量需要SELECT权限
  • 创建一个简单的A_Expr节点,表示lvar = rvar的连接条件
  • 如果已经存在result,则将新的A_Expr节点与之前的result组合成AND条件
  1. 对得到的result进行表达式转换,调用transformExpr()函数进行转换
  1. 对转换后的result进行强制转换为布尔类型,调用coerce_to_boolean()函数进行转换
  1. 返回转换后的result作为JOIN USING子句的操作树

transformTableEntry()

Java
static RangeTblEntry* transformTableEntry(ParseState* pstate, RangeVar* r, bool isFirstNode, bool isCreateView)
{
    RangeTblEntry* rte = NULL;

    rte = addRangeTableEntry(pstate, r, r->alias, interpretInhOption(r->inhOpt), true, isFirstNode, isCreateView, true);

    return rte;
}

在SQL中,目标列表只能引用FROM子句中指定的范围变量,但是在这里,我们遵循更强大的POSTQUEL语义,并在没有指定范围变量的情况下自动生成范围变量。然而,有时我们需要知道条目是否合法。在这里,isSupportSynonym选项为true,表示这个条目是一个同义词对象。

函数功能:功能是将一个RangeVar转换为RangeTblEntry,RangeVar是一个表的名称或别名,而RangeTblEntry是一个查询中的表的条目。

入口参数:

  • pstate是解析状态的指针
  • r是要转换的RangeVar
  • isFirstNode表示是否为查询中的第一个节点
  • isCreateView表示是否为创建视图操作

出口参数:

  • RangeTblEntry指针rte,表示转换后的表条目

transformCTEReference()

Java
static RangeTblEntry* transformCTEReference(ParseState* pstate, RangeVar* r, CommonTableExpr* cte, Index levelsup)
{
    RangeTblEntry* rte = NULL;

    if (r->ispartition || r->issubpartition || list_length(r->partitionNameList) > 0) {
        ereport(
            ERROR, (errcode(ERRCODE_UNDEFINED_TABLE), errmsg("relation \"%s\" is not partitioned table", r->relname)));
    }

    rte = addRangeTableEntryForCTE(pstate, cte, levelsup, r, true);

    return rte;
}

在关系型数据库中,通用表达式可以在查询中定义并命名,然后在查询的其他部分引用

函数功能:将通用表达式(Common Table Expression,CTE)引用转换为一个范围表条目(RangeTblEntry),以便在查询中使用

入口参数:

  • 解析状态(ParseState* pstate)
  • 范围变量(RangeVar* r)
  • 通用表达式(CommonTableExpr* cte)
  • 引用层级(Index levelsup)

出口参数:

  • 转换后的范围表条目(RangeTblEntry* rte)

函数内部逻辑:

首先检查范围变量是否是分区表或子分区表,如果是,则报错。然后调用addRangeTableEntryForCTE函数将通用表达式转换为范围表条目,并返回转换后的范围表条目。

评论
添加红包

请填写红包祝福语或标题

红包个数最小为10个

红包金额最低5元

当前余额3.43前往充值 >
需支付:10.00
成就一亿技术人!
领取后你会自动成为博主和红包主的粉丝 规则
hope_wisdom
发出的红包
实付
使用余额支付
点击重新获取
扫码支付
钱包余额 0

抵扣说明:

1.余额是钱包充值的虚拟货币,按照1:1的比例进行支付金额的抵扣。
2.余额无法直接购买下载,可以购买VIP、付费专栏及课程。

余额充值