延续上文,我们分别有学生表student以及入职表tyy,现有一条查询语句
学生表:
入职表:
查询语句跟上篇一样,这里就不重复展示了
1. 在scan.l的规则段
{identifier} {
int kwnum;
char *ident;
SET_YYLLOC();
/* Is it a keyword? */
/* yyextra->keywordlist中保存了导入kwlist.h中的所有关键字,可以在
* src\include\parser\kwlist.h中查阅
*/
kwnum = ScanKeywordLookup(yytext,
yyextra->keywordlist);
if (kwnum >= 0)
{
yylval->keyword = GetScanKeyword(kwnum,
yyextra->keywordlist); // 二分法查找关键字
return yyextra->keyword_tokens[kwnum]; // 返回token,这里为SELECT_P
}
/*
* No. Convert the identifier to lower case, and truncate
* if necessary.
*/
ident = downcase_truncate_identifier(yytext, yyleng, true);
yylval->str = ident;
return IDENT;
}
2. 返回SELECT_P后,在gram.y中对该规则进行分析,SelectStmt
---------------------------"select ... order by ..."--------------------------
/* SelectStmt-> select_no_parens-> simple_select && sort_clause */
SelectStmt: select_no_parens %prec UMINUS
| select_with_parens %prec UMINUS
;
select_no_parens:
simple_select { $$ = $1; }
| select_clause sort_clause
{
insertSelectOptions((SelectStmt *) $1, $2, NIL,
NULL, NULL,
yyscanner);
$$ = $1;
}
...
3. select_clause
---------------------------"select ... "--------------------------
/* select_clause-> simple_select-> opt_all_clause && opt_target_list && into_clause && from_clause &&
where_clause && group_clause && having_clause && window_clause */
select_clause:
simple_select { $$ = $1; }
...
simple_select:
SELECT opt_all_clause opt_target_list
into_clause from_clause where_clause
group_clause having_clause window_clause
{
SelectStmt *n = makeNode(SelectStmt);
n->targetList = $3;
n->intoClause = $4;
n->fromClause = $5;
n->whereClause = $6;
n->groupClause = ($7)->list;
n->groupDistinct = ($7)->distinct;
n->havingClause = $8;
n->windowClause = $9;
$$ = (Node *) n;
}
...
4. opt_target_list
---------------------------"name, score"--------------------------
/* opt_target_list-> target_list->target_el->a_expr AS ColLabel &&
a_expr-> c_expr-> columnref-> ColId */
opt_target_list: target_list { $$ = $1; }
| /* EMPTY */ { $$ = NIL; }
;
/* target_list中的的lappend相当于:$1->tail->data.ptr_value = $3
其中$1是一个list,$3是一个ListCell */
target_list:
target_el { $$ = list_make1($1); }
| target_list ',' target_el { $$ = lappend($1, $3); }
;
target_el: ...
| a_expr // name, score
{
$$ = makeNode(ResTarget);
$$->name = NULL;
s$$->indirection = NIL;
$$->val = (Node *) $1;
$$->location = @1;
}
...
;
a_expr: c_expr { $$ = $1; }
...
c_expr: columnref { $$ = $1; }
...
columnref: ColId
{
$$ = makeColumnRef($1, NIL, @1, yyscanner);
}
...
相关结构体:
typedef struct ResTarget
{
NodeTag type;
char *name; /* column name or NULL */
List *indirection; /* subscripts, field names, and '*', or NIL */
Node *val; /* the value expression to compute or assign */
int location; /* token location, or -1 if unknown */
} ResTarget;
typedef struct ColumnRef
{
NodeTag type;
List *fields;
int location;
} ColumnRef;
5. from_clause
--------"from studnet, (select * from tyy where tyy.gno = '2023') as sub"-----------
/* from_clause-> from_list-> table_ref */
from_clause:
from_list { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
from_list:
table_ref { $$ = list_make1($1); }
| from_list ',' table_ref { $$ = lappend($1, $3); }
;
------------------------------"student"--------------------------
/* table_ref-> relation_expr-> qualified_name-> ColId */
table_ref: relation_expr opt_alias_clause // opt_alias_clause可以为EMPTY
{
$1->alias = $2;
$$ = (Node *) $1;
}
...
relation_expr:
qualified_name
{
/* inheritance query, implicitly */
$$ = $1;
$$->inh = true;
$$->alias = NULL;
}
...
qualified_name:
ColId
{
$$ = makeRangeVar(NULL, $1, @1);
}
...
----------------"(select * from tyy where tyy.gno = '2023') as sub"--------------
/* table_ref-> select_with_parens-> select_no_parens-> simple_select
table_ref-> opt_alias_clause*/
table_ref: ...
| select_with_parens opt_alias_clause
{
RangeSubselect *n = makeNode(RangeSubselect);
n->lateral = false;
n->subquery = $1;
n->alias = $2;
...
$$ = (Node *) n;
}
select_with_parens:
'(' select_no_parens ')' { $$ = $2; }
| '(' select_with_parens ')' { $$ = $2; }
;
select_no_parens:
simple_select { $$ = $1; }
...
----------------"select * from class where class.gno = '2023"--------------
simple_select:
SELECT opt_all_clause opt_target_list
into_clause from_clause where_clause
group_clause having_clause window_clause
{
SelectStmt *n = makeNode(SelectStmt);
n->targetList = $3;
n->intoClause = $4;
n->fromClause = $5;
n->whereClause = $6;
n->groupClause = ($7)->list;
n->groupDistinct = ($7)->distinct;
n->havingClause = $8;
n->windowClause = $9;
$$ = (Node *) n;
}
...
----------------"*"--------------
/* simple_select-> opt_target_list-> target_list-> target_el */
opt_target_list: target_list { $$ = $1; }
| /* EMPTY */ { $$ = NIL; }
;
target_list:
target_el { $$ = list_make1($1); }
| target_list ',' target_el { $$ = lappend($1, $3); }
;
target_el: ...
| '*'
{
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;
}
;
----------------'class'--------------
/* simple_select-> from_clause-> from_list-> table_ref-> relation_expr-> qualified_name */
from_clause:
FROM from_list { $$ = $2; }
| /*EMPTY*/ { $$ = NIL; }
;
from_list:
table_ref { $$ = list_make1($1); }
| from_list ',' table_ref { $$ = lappend($1, $3); }
;
table_ref: relation_expr opt_alias_clause
{
$1->alias = $2;
$$ = (Node *) $1;
}
...
relation_expr:
qualified_name
{
/* inheritance query, implicitly */
$$ = $1;
$$->inh = true;
$$->alias = NULL;
}
...
qualified_name:
ColId
{
$$ = makeRangeVar(NULL, $1, @1);
}
...
----------------'tyy.gno = '2023''--------------
/* simple_select-> where_clause-> a_expr-> c_expr-> columnref-> columnref-> indirection-> indirection_el-> attr_name-> ColLabel */
from_clause:
where_clause:
WHERE a_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
a_expr: ...
| a_expr '=' a_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
a_expr: c_expr { $$ = $1; }
...
c_expr: columnref { $$ = $1; }
...
columnref: ...
| ColId indirection
{
$$ = makeColumnRef($1, $2, @1, yyscanner);
}
;
indirection:
indirection_el { $$ = list_make1($1); }
| indirection indirection_el { $$ = lappend($1, $2); }
;
indirection_el:
'.' attr_name
{
$$ = (Node *) makeString($2);
}
...
attr_name: ColLabel { $$ = $1; };
ColLabel: IDENT { $$ = $1; }
| unreserved_keyword { $$ = pstrdup($1); }
| col_name_keyword { $$ = pstrdup($1); }
| type_func_name_keyword { $$ = pstrdup($1); }
| reserved_keyword { $$ = pstrdup($1); }
;
----------------" as sub"--------------
/* opt_alias_clause-> alias_clause-> ColId */
opt_alias_clause: alias_clause { $$ = $1; }
| /*EMPTY*/ { $$ = NULL; }
;
alias_clause:
...
| AS ColId
{
$$ = makeNode(Alias);
$$->aliasname = $2;
}
相关结构体:
typedef struct RangeVar
{
NodeTag type;
char *catalogname; /* the catalog (database) name, or NULL */
char *schemaname; /* the schema name, or NULL */
char *relname; /* the relation/sequence name */
bool inh; /* expand rel by inheritance? recursively act
* on children? */
char relpersistence; /* see RELPERSISTENCE_* in pg_class.h */
Alias *alias; /* table alias & optional column aliases */
int location; /* token location, or -1 if unknown */
} RangeVar;
typedef struct RangeSubselect
{
NodeTag type;
bool lateral; /* does it have LATERAL prefix? */
Node *subquery; /* the untransformed sub-select clause */
Alias *alias; /* table alias & optional column aliases */
} RangeSubselect;
typedef struct A_Expr
{
NodeTag type;
A_Expr_Kind kind; /* see above */
List *name; /* possibly-qualified name of operator */
Node *lexpr; /* left argument, or NULL if none */
Node *rexpr; /* right argument, or NULL if none */
int location; /* token location, or -1 if unknown */
} A_Expr;
typedef struct Alias
{
NodeTag type;
char *aliasname; /* aliased rel name (never qualified) */
List *colnames; /* optional list of column aliases */
} Alias;
6. where_clause
--------"where student.sno = sub.sno and sub.department = '数据库'"-----------
----------------"WHERE ... AND ... "--------------
/* where_clause-> a_expr */
where_clause:
WHERE a_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
a_expr: ...
| a_expr AND a_expr
{ $$ = makeAndExpr($1, $3, @2); }
--------"student.sno = sub.sno"-----------
/* simple_select-> where_clause-> a_expr-> c_expr-> columnref->
indirection-> indirection_el-> attr_name-> ColLabel */
where_clause:
WHERE a_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
a_expr: ...
| a_expr '=' a_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
a_expr: c_expr { $$ = $1; }
...
c_expr: columnref { $$ = $1; }
...
columnref: ...
| ColId indirection
{
$$ = makeColumnRef($1, $2, @1, yyscanner);
}
;
indirection:
indirection_el { $$ = list_make1($1); }
| indirection indirection_el { $$ = lappend($1, $2); }
;
indirection_el:
'.' attr_name
{
$$ = (Node *) makeString($2);
}
...
attr_name: ColLabel { $$ = $1; };
ColLabel: IDENT { $$ = $1; }
| unreserved_keyword { $$ = pstrdup($1); }
| col_name_keyword { $$ = pstrdup($1); }
| type_func_name_keyword { $$ = pstrdup($1); }
| reserved_keyword { $$ = pstrdup($1); }
;
--------" sub.department = '数据库' "-----------
/* simple_select-> where_clause-> a_expr-> c_expr-> columnref */
where_clause:
WHERE a_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
a_expr: ...
| a_expr '=' a_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
a_expr: c_expr { $$ = $1; }
...
c_expr: columnref { $$ = $1; }
...
columnref: ColId
{
$$ = makeColumnRef($1, NIL, @1, yyscanner);
}
...
7. group_clause
----------------"group by name, score "--------------
/* group_clause-> group_by_list-> group_by_item-> a_expr-> c_expr-> columnref-> ColId */
group_clause:
GROUP_P BY set_quantifier group_by_list
{
GroupClause *n = (GroupClause *) palloc(sizeof(GroupClause));
n->distinct = $3 == SET_QUANTIFIER_DISTINCT;
n->list = $4;
$$ = n;
}
...
group_by_list:
group_by_item { $$ = list_make1($1); }
| group_by_list ',' group_by_item { $$ = lappend($1,$3); }
;
group_by_item:
a_expr { $$ = $1; }
...
a_expr: c_expr { $$ = $1; }
...
c_expr: columnref { $$ = $1; }
...
columnref: ColId
{
$$ = makeColumnRef($1, NIL, @1, yyscanner);
}
...
8. having_clause
----------------"having score > 80 "--------------
/* having_clause-> a_expr*/
having_clause:
HAVING a_expr { $$ = $2; }
| /*EMPTY*/ { $$ = NULL; }
;
a_expr: ...
| a_expr '>' a_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
/* 后面为重复操作 */
9. sort_clause
----------------"order by score DESC; "--------------
/* sort_clause-> sortby_list-> sortby-> a_expr && opt_asc_desc
a_expr-> c_expr-> columnref */
sort_clause:
ORDER BY sortby_list { $$ = $3; }
;
sortby_list:
sortby { $$ = list_make1($1); }
| sortby_list ',' sortby { $$ = lappend($1, $3); }
;
sortby: ...
| a_expr opt_asc_desc opt_nulls_order // "opt_asc_desc" 对应ASC、DESC
{
$$ = makeNode(SortBy);
$$->node = $1;
$$->sortby_dir = $2;
$$->sortby_nulls = $3;
$$->useOp = NIL;
$$->location = -1; /* no operator */
}
;
a_expr: c_expr { $$ = $1; }
c_expr: columnref { $$ = $1; }
...
columnref: ColId
{
$$ = makeColumnRef($1, NIL, @1, yyscanner);
}
...
opt_asc_desc: ASC { $$ = SORTBY_ASC; }
| DESC { $$ = SORTBY_DESC; }
| /*EMPTY*/ { $$ = SORTBY_DEFAULT; }
10. stmtmulti
/* stmtmulit-> toplevel_stmt-> stmt-> SelectStmt */
stmtmulti: stmtmulti ';' toplevel_stmt
{
if ($1 != NIL)
{
/* update length of previous stmt */
updateRawStmtEnd(llast_node(RawStmt, $1), @2);
}
if ($3 != NULL)
$$ = lappend($1, makeRawStmt($3, @2 + 1));
else
$$ = $1;
}
| toplevel_stmt
{
if ($1 != NULL)
$$ = list_make1(makeRawStmt($1, 0));
else
$$ = NIL;
}
;
toplevel_stmt:
stmt
| TransactionStmtLegacy
;
stmt:
AlterEventTrigStmt
| AlterCollationStmt
| AlterDatabaseStmt
| AlterDatabaseSetStmt
...
| DeleteStmt
...
| SelectStmt
...
| /*EMPTY*/
{ $$ = NULL; }
;
*******完成对查询语句的语法解析*******