1概述
simple-select是一条SELECT语句的最核心部分,从simple-select的语法定义可以看出,它由如下子句组成:去除行重复的DISTINCT (标识符opt-distinct)、目标属性(标识符target-list)、 SELECT INTO子句(标识符into-clause)、FROM子句(标识符from-clause)、 WHERE子句(标识符where_clause) 、 CROUP BY子句(标识符group-clause)、HAVING子句(标识符having-clause)和窗口子句(标识符window-clause)。在成功匹配simple-select语法结构后,将创建一个SelectStmt结构体,并将各子句赋值到结构体中相应的字段。
此外, simple-select还可以定义为其他的形式(见文件Gram. y),如VALUES子句、关系表达式以及多个SELECT语句的交并差等,但这些情况最终都会转化成最基本的simple_select形式来处理。而对于simple-select来说,目标属性(标识符target list)、FROM子句(标识符from-clause)、 WHERE子句(标识符where-clause)以及GROUP BY子句(标识符groupclause)是最重要的部分,下面将结合一个具体实例对这些子句的处理加以详细介绍。
1.simple_select:
2. SELECT opt_distinct target_list
3. into_clause from_clause where_clause
4. group_clause having_clause window_clause
5. {
6. SelectStmt *n = makeNode(SelectStmt);
7. n->targetList = $3;
8. n->intoClause = $4;
9. n->fromClause = $5;
10. n->whereClause = $6;
11. n->groupClause = $7;
12. n->havingClause = $8;
13. n->windowClause = $9;
14. $$ = (Node *)n;
15. }
16. | SELECT distinct_clause target_list
17. into_clause from_clause where_clause
18. group_clause having_clause window_clause
19. {
20. SelectStmt *n = makeNode(SelectStmt);
21. n->distinctClause = $2;
22. n->targetList = $3;
23. n->intoClause = $4;
24. n->fromClause = $5;
25. n->whereClause = $6;
26. n->groupClause = $7;
27. n->havingClause = $8;
28. n->windowClause = $9;
29. $$ = (Node *)n;
30. }
31. | values_clause { $$ = $1; }
2子句
2.1 DISTINCT子句
DISTINCT子句对应语法定义中的标识符opt_distinct。从opt-distinct的语法结构可以看到,它可以匹配DISTINCT, ALL, DISTINCT ON (表达式列表)或者为空,用来决定SELECT语句是否去除重复的行。
当匹配到DISTINCT时, opt_distinct返回一个List,该链表的第一个ListCell的ptr-value字段置为空。
当匹配到DISTINCT ON时, opt_distinct也返回一个List,这个List中包含了跟在DISTINCTON之后的表达式的列表(星号或者表的属性等)。
当匹配到ALL或者空时, opt_distinct返回NIL,表明没有使用DISTINCT。
2.2 目标属性
目标属性是SELECT语句中所要查询的属性列表,对应着语法定义中的标识符targetList, targetList由若干个target_el组成,target_el定义为取别名的表达式、表达式以及“*”等。
1.target_list:
2. target_el { $$ = list_make1($1); }
3. | target_list ',' target_el { $$ = lappend($1, $3); }
4. ;
5.
6.target_el: a_expr AS ColLabel
7. {
8. $$ = makeNode(ResTarget);
9. $$->name = $3;
10. $$->indirection = NIL;
11. $$->val = (Node *)$1;
12. $$->location = @1;
13. }
14. /*
15. * We support omitting AS only for column labels that aren't
16. * any known keyword. There is an ambiguity against postfix
17. * operators: is "a ! b" an infix expression, or a postfix
18. * expression and a column label? We prefer to resolve this
19. * as an infix expression, which we accomplish by assigning
20. * IDENT a precedence higher than POSTFIXOP.
21. */
22. | a_expr IDENT
23. {
24. $$ = makeNode(ResTarget);
25. $$->name = $2;
26. $$->indirection = NIL;
27. $$->val = (Node *)$1;
28. $$->location = @1;
29. }
30. | a_expr
31. {
32. $$ = makeNode(ResTarget);
33. $$->name = NULL;
34. $$->indirection = NIL;
35. $$->val = (Node *)$1;
36. $$->location = @1;
37. }
38. | '*'
39. {
40. ColumnRef *n = makeNode(ColumnRef);
41. n->fields = list_make1(makeNode(A_Star));
42. n->location = @1;
43.
44. $$ = makeNode(ResTarget);
45. $$->name = NULL;
46. $$->indirection = NIL;
47. $$->val = (Node *)n;
48. $$->location = @1;
49. }
50. ;
当成功匹配一个targetList时,创建一个ResTarget结构体,该结构体中存储了该属性的全部信息。最终targetList将返回一个由ResTarget构成的List。
targetList包括若干ListCell节点,每个节点中的data字段指向结构体ResTarget,用来表示目标属性中的一项。下图展示了目标属性在内存中的组织结构。当目标属性中的某项涉及函数调用时, ResTarget中的字段val会指向结构体FunCall, FunCall的字段funcname存储函数的名称,字段args指向结构体ColumnRef构成的链表,每一个ColumnRef存储了函数调用中所使用到的表的一个属性。如果没有函数调用,则结构体ResTarget中的字段val直接指向结构体ColumnRef,存储该项目标属性所涉及的表的字段(此种情况没有在图中展示)。
图1 分析树中目标属性的数据组织结构
2.3 FROM子句
文件gram. y中定义的标识符from_clause表示SELECT语句中的FROM子句, from_clause由FROM关键字和fromList组成。而fromlist则由若干个标识符table_ref组成,每一个table_ref表示FROM子句中用逗号分隔的每个子项,它表示在FROM子句中出现的一个表或者一个子查询。
1.from_clause:
2. FROM from_list { $$ = $2; }
3. | /*EMPTY*/ { $$ = NIL; }
4. ;
5.
6.from_list:
7. table_ref { $$ = list_make1($1); }
8. | from_list ',' table_ref { $$ = lappend($1, $3); }
9. ;
标识符table_ref可以定义为关系表达式、取别名的关系表达式、带括号的SELECT语句、表连接等形式。
由于FROM子句中子项(标识符table_ref的最简单和基本的形式是关系表达式(标识符relation_expr)。因此,下面分析relation_expr的语法定义。
1.relation_expr:
2. qualified_name
3. {
4. /* inheritance query, implicitly */
5. $$ = $1;
6. $$->inh = true;
7. $$->alias = NULL;
8. }
9. | qualified_name '*'
10. {
11. /* inheritance query, explicitly */
12. $$ = $1;
13. $$->inh = true;
14. $$->alias = NULL;
15. }
16. | ONLY qualified_name
17. {
18. /* no inheritance */
19. $$ = $2;
20. $$->inh = false;
21. $$->alias = NULL;
22. }
23. | ONLY '(' qualified_name ')'
24. {
25. /* no inheritance, SQL99-style syntax */
26. $$ = $3;
27. $$->inh = false;
28. $$->alias = NULL;
29. }
30. ;
31.
32.
33.relation_expr_list:
34. relation_expr { $$ = list_make1($1); }
35. | relation_expr_list ',' relation_expr { $$ = lappend($1, $3); }
36. ;
关系表达式relation_expr定义成qualified_name、带ONLY关键字的qualified_name等形式,最后qualified_name定义成relation_name。在成功匹配最终的标识符relation_name后,创建一个RangeVar结构体用来存储该关系的信息。 如图2所示, from_clause子句在分析树中同样被组织成一个List,每一个ListCell中包含一个RangeVar结构(或者其他结构)。
图2 分析树中from子句的数据结构
2.4 WHERE子句
WHERE子句中定义的是元组约束信息,对应着语法定义中的标识符where_clause。标识符where_clause定义为关键字WHERE和一个表达式(标识符a_expr)。
1.where_clause:
2. WHERE a_expr { $$ = $2; }
3. | /*EMPTY*/ { $$ = NULL; }
4. ;
由于表达式是递归定义的,因此, A_Expr结构体中字段lexpr和rexpr分别代表操作符的左右两个子表达式,字段A-Expr_kind代表操作的类型。如果该表达式是常量或者属性等(表达式树中的叶子节点),则lexpr和rexpr都为NULL。在WHERE子句中,使用到的表的属性信息用ColumnRef结构体来组织。
2.5 GROUP BY子句
GROUP BY子句的作用是根据所指定的属性进行分组,对应着语法定义中的标识符group_clause, GROUP BY子句的语法结构与WHERE子句非常相似,在此不再详细讨论。Group by子句的语法定义如下:
group_clause:
GROUP_P BY group_by_list { $$ = $3; }
| /*EMPTY*/ { $$ = NIL; }
;
expr_list: a_expr
{
$$ = list_make1($1);
}
| expr_list ',' a_expr
{
$$ = lappend($1, $3);
}
;
2.6 HAVING子句和ORDER BY子句
HAVING子句的作用是根据指定的条件对GROUP BY的分组进行过滤,对应于having_clause标识符。ORDER BY子句的作用是根据指定属性对整个查询的结果进行排序,对应于sort_cluse标识符。Having子句和order by子句的语法定义如下:
1.having_clause:
2. HAVING a_expr { $$ = $2; }
3. | /*EMPTY*/ { $$ = NULL; }
4. ;
5.sort_clause:
6. ORDER BY sortby_list { $$ = $3; }
7. ;
8.
9.sortby_list:
10. sortby { $$ = list_make1($1); }
11. | sortby_list ',' sortby { $$ = lappend($1, $3); }
12. ;
13.
14.sortby: a_expr USING qual_all_Op opt_nulls_order
15. {
16. $$ = makeNode(SortBy);
17. $$->node = $1;
18. $$->sortby_dir = SORTBY_USING;
19. $$->sortby_nulls = $4;
20. $$->useOp = $3;
21. $$->location = @3;
22. }
23. | a_expr opt_asc_desc opt_nulls_order
24. {
25. $$ = makeNode(SortBy);
26. $$->node = $1;
27. $$->sortby_dir = $2;
28. $$->sortby_nulls = $3;
29. $$->useOp = NIL;
30. $$->location = -1; /* no operator */
31. }
32. ;