根据 <PostgreSQL 数据库内核分析>200和201页的说法,
ResTarget 应该指向 ColumnRef 。这是如何实现的呢?
复制代码
target_list:
target_el { $$ = list_make1($1); }
| target_list ',' target_el { $$ = lappend($1, $3); }
;
target_el: a_expr AS ColLabel
{
$$ = makeNode(ResTarget);
$$->name = $3;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
/*
* We support omitting AS only for column labels that aren't
* any known keyword. There is an ambiguity against postfix
* operators: is "a ! b" an infix expression, or a postfix
* expression and a column label? We prefer to resolve this
* as an infix expression, which we accomplish by assigning
* IDENT a precedence higher than POSTFIXOP.
*/
| a_expr IDENT
{
$$ = makeNode(ResTarget);
$$->name = $2;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
| a_expr
{
$$ = makeNode(ResTarget);
$$->name = NULL;
$$->indirection = NIL;
$$->val = (Node *)$1;
$$->location = @1;
}
| '*'
{
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;
}
;
复制代码
和
复制代码
a_expr: c_expr
{ $$ = $1; }
| a_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3, @2); }
| a_expr COLLATE any_name
{
CollateClause *n = makeNode(CollateClause);
n->arg = $1;
n->collname = $3;
n->location = @2;
$$ = (Node *) n;
}
...
复制代码
和
复制代码
c_expr: columnref { $$ = $1; }
| AexprConst { $$ = $1; }
| PARAM opt_indirection
{
ParamRef *p = makeNode(ParamRef);
p->number = $1;
p->location = @1;
if ($2)
{
A_Indirection *n = makeNode(A_Indirection);
n->arg = (Node *) p;
n->indirection = check_indirection($2, yyscanner);
$$ = (Node *) n;
}
else
$$ = (Node *) p;
}
| '(' a_expr ')' opt_indirection
{
if ($4)
{
A_Indirection *n = makeNode(A_Indirection);
n->arg = $2;
n->indirection = check_indirection($4, yyscanner);
$$ = (Node *)n;
}
else
$$ = $2;
}
| case_expr
{ $$ = $1; }
| func_expr
{ $$ = $1; }
| select_with_parens %prec UMINUS
{
SubLink *n = makeNode(SubLink);
n->subLinkType = EXPR_SUBLINK;
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $1;
n->location = @1;
$$ = (Node *)n;
}
| EXISTS select_with_parens
{
SubLink *n = makeNode(SubLink);
n->subLinkType = EXISTS_SUBLINK;
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
n->location = @1;
$$ = (Node *)n;
}
| ARRAY select_with_parens
{
SubLink *n = makeNode(SubLink);
n->subLinkType = ARRAY_SUBLINK;
n->testexpr = NULL;
n->operName = NIL;
n->subselect = $2;
n->location = @1;
$$ = (Node *)n;
}
| ARRAY array_expr
{
A_ArrayExpr *n = (A_ArrayExpr *) $2;
Assert(IsA(n, A_ArrayExpr));
/* point outermost A_ArrayExpr to the ARRAY keyword */
n->location = @1;
$$ = (Node *)n;
}
| row
{
RowExpr *r = makeNode(RowExpr);
r->args = $1;
r->row_typeid = InvalidOid; /* not analyzed yet */
r->location = @1;
$$ = (Node *)r;
}
;
复制代码
这个时候,距离ColumnRef 就已经不远了。
然后挑选最简单的情况:
复制代码
columnref: ColId
{
$$ = makeColumnRef($1, NIL, @1, yyscanner);
}
| ColId indirection
{
$$ = makeColumnRef($1, $2, @1, yyscanner);
}
;
复制代码
查了一下, 原来 makeColumnRef 就在 gram.y 里面:
复制代码
static Node *
makeColumnRef(char *colname, List *indirection,
int location, core_yyscan_t yyscanner)
{
/*
* Generate a ColumnRef node, with an A_Indirection node added if there
* is any subscripting in the specified indirection list. However,
* any field selection at the start of the indirection list must be
* transposed into the "fields" part of the ColumnRef node.
*/
ColumnRef *c = makeNode(ColumnRef);
int nfields = 0;
ListCell *l;
c->location = location;
foreach(l, indirection)
{
if (IsA(lfirst(l), A_Indices))
{
A_Indirection *i = makeNode(A_Indirection);
if (nfields == 0)
{
/* easy case - all indirection goes to A_Indirection */
c->fields = list_make1(makeString(colname));
i->indirection = check_indirection(indirection, yyscanner);
}
else
{
/* got to split the list in two */
i->indirection = check_indirection(
list_copy_tail(indirection, nfields),yyscanner);
indirection = list_truncate(indirection, nfields);
c->fields = lcons(makeString(colname), indirection);
}
i->arg = (Node *) c;
return (Node *) i;
}
else if (IsA(lfirst(l), A_Star))
{
/* We only allow '*' at the end of a ColumnRef */
if (lnext(l) != NULL)
parser_yyerror("improper use of \"*\"");
}
nfields++;
}
/* No subscripting, so all indirection gets added to field list */
c->fields = lcons(makeString(colname), indirection);
return (Node *) c;
}
复制代码
这个
ColumnRef *c = makeNode(ColumnRef);
和
c->fields = list_make1(makeString(colname)); 将 字段 赋予了 ColumnRef。
可以看出,语法分析是一层套着一层。而整个语法分析的目的,就是逐层地构建一个语法分析树形结构。
本文转自健哥的数据花园博客园博客,原文链接:http://www.cnblogs.com/gaojian/archive/2012/09/10/2678905.html,如需转载请自行联系原作者