General expressions语法规则定义在src/backend/parser/gram.y文件中,其是表达式语法的核心。有两种表达式类型:a_expr
是不受限制的类型,b_expr
是必须在某些地方使用的子集,以避免移位/减少冲突。例如,我们不能将BETWEEN
作为BETWEEN a_expr AND a_exp
,因为AND
的使用与AND
作为布尔运算符冲突。因此,b_expr
在BETWEEN
中使用,我们从b_expr
中删除布尔关键字。请注意,( a_expr )
是b_expr
,因此始终可以使用无限制表达式,方法是用括号将其括起来。c_expr
是a_expr
和b_expr
共同的所有乘积;它被分解出来只是为了消除冗余编码。注意涉及多个terminal token的产出productions。默认情况下,bison将为此类productions分配其最后一个terminal的优先级,但在几乎所有情况下,您都希望它是第一个terminal的优先权;否则你不会得到你期望的行为!因此,我们可以自由使用%prec
注释来设置优先级。
b_expr
代表Restricted expressions,它是复杂表达式a_expr
的子集,AND, NOT, IS, and IN是a_expr
的关键字,这些关键字在b_expr
使用会存在歧义。b_expr is a subset of the complete expression syntax defined by a_expr. Presently, AND, NOT, IS, and IN are the a_expr keywords that would cause trouble in the places where b_expr is used. For simplicity, we just eliminate all the boolean-keyword-operator productions from b_expr.
b_expr: c_expr
{ $$ = $1; }
| b_expr TYPECAST Typename
{ $$ = makeTypeCast($1, $3, @2); }
| '+' b_expr %prec UMINUS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' b_expr %prec UMINUS
{ $$ = doNegate($2, @1); }
| b_expr '+' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
| b_expr '-' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
| b_expr '*' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
| b_expr '/' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
| b_expr '%' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
| b_expr '^' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
| b_expr '<' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
| b_expr '>' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
| b_expr '=' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
| b_expr LESS_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $3, @2); }
| b_expr GREATER_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
| b_expr NOT_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
| b_expr qual_Op b_expr %prec Op
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
| qual_Op b_expr %prec Op
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
| b_expr qual_Op %prec POSTFIXOP
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
| b_expr IS DISTINCT FROM b_expr %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2); }
| b_expr IS NOT DISTINCT FROM b_expr %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2); }
| b_expr IS OF '(' type_list ')' %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2); }
| b_expr IS NOT OF '(' type_list ')' %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2); }
| b_expr IS DOCUMENT_P %prec IS
{ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1), @2); }
| b_expr IS NOT DOCUMENT_P %prec IS
{ $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1), @2), @2); }
表达式强转
b_expr TYPECAST Typename
是表达式强转的规则,其中主要关注SimpleTypename所代表的规则。除了GenericType之外的规则和PostgreSQL查询引擎——General Expressions Grammar之AexprConst中介绍的常量类型强转类似,这里仅仅关注GenericType。
SimpleTypename:
GenericType { $$ = $1; }
| Numeric { $$ = $1; }
| Bit { $$ = $1; }
| Character { $$ = $1; }
| ConstDatetime { $$ = $1; }
| ConstInterval opt_interval
{ $$ = $1; $$->typmods = $2; }
| ConstInterval '(' Iconst ')'
{ $$ = $1; $$->typmods = list_make2(makeIntConst(INTERVAL_FULL_RANGE, -1), makeIntConst($3, @3)); }
;
GenericType涵盖所有没有标准规定的特殊语法的类型名称,包括限定名称。我们还允许类型修饰符。为了避免对函数调用的解析冲突,这里必须将修饰符显示为expr_list,但解析分析只接受它们的常量。GenericType covers all type names that don’t have special syntax mandated by the standard, including qualified names. We also allow type modifiers. To avoid parsing conflicts against function invocations, the modifiers have to be shown as expr_list here, but parse analysis will only accept constants for them.
GenericType:
type_function_name opt_type_modifiers
{ $$ = makeTypeName($1); $$->typmods = $2; $$->location = @1; }
| type_function_name attrs opt_type_modifiers
{ $$ = makeTypeNameFromNameList(lcons(makeString($1), $2)); $$->typmods = $3; $$->location = @1; }
opt_type_modifiers: '(' expr_list ')' { $$ = $2; }
| /* EMPTY */ { $$ = NIL; }
表达式强转的规则不同之处在于opt_array_bounds和ARRAY对于arrayBounds成员取值的影响,以及使用SETOF需要将setof成员设置为true。
Typename: SimpleTypename opt_array_bounds
{ $$ = $1; $$->arrayBounds = $2; }
| SETOF SimpleTypename opt_array_bounds
{ $$ = $2; $$->arrayBounds = $3; $$->setof = true; }
/* SQL standard syntax, currently only one-dimensional */
| SimpleTypename ARRAY '[' Iconst ']'
{ $$ = $1; $$->arrayBounds = list_make1(makeInteger($4)); }
| SETOF SimpleTypename ARRAY '[' Iconst ']'
{ $$ = $2; $$->arrayBounds = list_make1(makeInteger($5)); $$->setof = true; }
| SimpleTypename ARRAY
{ $$ = $1; $$->arrayBounds = list_make1(makeInteger(-1)); }
| SETOF SimpleTypename ARRAY
{ $$ = $2; $$->arrayBounds = list_make1(makeInteger(-1)); $$->setof = true; }
opt_array_bounds:
opt_array_bounds '[' ']'
{ $$ = lappend($1, makeInteger(-1)); }
| opt_array_bounds '[' Iconst ']'
{ $$ = lappend($1, makeInteger($3)); }
| /*EMPTY*/
{ $$ = NIL; }
运算符
| '+' b_expr %prec UMINUS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", NULL, $2, @1); }
| '-' b_expr %prec UMINUS
{ $$ = doNegate($2, @1); }
| b_expr '+' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "+", $1, $3, @2); }
| b_expr '-' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "-", $1, $3, @2); }
| b_expr '*' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "*", $1, $3, @2); }
| b_expr '/' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "/", $1, $3, @2); }
| b_expr '%' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "%", $1, $3, @2); }
| b_expr '^' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "^", $1, $3, @2); }
| b_expr '<' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<", $1, $3, @2); }
| b_expr '>' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">", $1, $3, @2); }
| b_expr '=' b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "=", $1, $3, @2); }
| b_expr LESS_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<=", $1, $3, @2); }
| b_expr GREATER_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, ">=", $1, $3, @2); }
| b_expr NOT_EQUALS b_expr
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OP, "<>", $1, $3, @2); }
| b_expr qual_Op b_expr %prec Op
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, $3, @2); }
| qual_Op b_expr %prec Op
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $1, NULL, $2, @1); }
| b_expr qual_Op %prec POSTFIXOP
{ $$ = (Node *) makeA_Expr(AEXPR_OP, $2, $1, NULL, @2); }
| b_expr IS DISTINCT FROM b_expr %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_DISTINCT, "=", $1, $5, @2); }
| b_expr IS NOT DISTINCT FROM b_expr %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_NOT_DISTINCT, "=", $1, $6, @2); }
| b_expr IS OF '(' type_list ')' %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "=", $1, (Node *) $5, @2); }
| b_expr IS NOT OF '(' type_list ')' %prec IS
{ $$ = (Node *) makeSimpleA_Expr(AEXPR_OF, "<>", $1, (Node *) $6, @2); }
| b_expr IS DOCUMENT_P %prec IS
{ $$ = makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1), @2); }
| b_expr IS NOT DOCUMENT_P %prec IS
{ $$ = makeNotExpr(makeXmlExpr(IS_DOCUMENT, NULL, NIL, list_make1($1), @2), @2); }
https://www.developerastrid.com/sql/sql-predicates/