文件路径
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查询语句时识别和处理不同的子句。
- ORDER_CLAUSE(ORDER BY子句):用于对查询结果进行排序。按照指定的列或表达式的值升序或降序排列结果集。在SQL查询中,ORDER BY子句通常出现在SELECT语句的末尾。
- GROUP_CLAUSE(GROUP BY子句):用于对查询结果进行分组。根据指定的列或表达式的值将结果集分成不同的组。在SQL查询中,GROUP BY子句也通常出现在SELECT语句的末尾。
- 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* 类型的指针,表示转换后的等值比较表达式
函数内部逻辑:
- 遍历左表达式和右表达式的字段变量列表,对于每一对字段变量
- 首先标记这些变量可以被查询读取
- 然后创建一个等值比较操作符节点(A_Expr),将左字段变量和右字段变量作为操作数,并指定操作符为 =。如果存在多个字段变量,将它们的等值比较节点通过逻辑“AND”操作符 (A_Expr) 组合起来。
- 最后,将转换后的表达式作为参数传递给 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:右侧关系表条目
出口参数:
函数内部逻辑:
- 遍历左侧变量列表和右侧变量列表,对每一对变量进行以下操作:
- 标记列需要进行SELECT权限,即调用markVarForSelectPriv()函数标记变量需要SELECT权限
- 创建一个简单的A_Expr节点,表示lvar = rvar的连接条件
- 如果已经存在result,则将新的A_Expr节点与之前的result组合成AND条件
- 对得到的result进行表达式转换,调用transformExpr()函数进行转换
- 对转换后的result进行强制转换为布尔类型,调用coerce_to_boolean()函数进行转换
- 返回转换后的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是一个查询中的表的条目。
入口参数:
- isFirstNode表示是否为查询中的第一个节点
出口参数:
- 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),以便在查询中使用
入口参数:
- 通用表达式(CommonTableExpr* cte)
出口参数:
- 转换后的范围表条目(RangeTblEntry* rte)
函数内部逻辑:
首先检查范围变量是否是分区表或子分区表,如果是,则报错。然后调用addRangeTableEntryForCTE函数将通用表达式转换为范围表条目,并返回转换后的范围表条目。