Remove precedence labeling of keywords TRUE, FALSE, UNKNOWN, and ZONE.

These were labeled with precedences just to avoid attaching explicit
precedences to the productions in which they were the last terminal symbol.
Since a terminal symbol precedence marking can affect many other things
too, it seems like better practice to attach precedence labels to the
productions, and not mark the terminal symbols.

Ideally we'd also remove the precedence attached to NULL_P, but it turns
out that we are actually depending on that having a precedence higher than
POSTFIXOP, else we get a shift/reduce conflict for postfix operators in
b_expr.  (Which more or less proves my point about these markings having a
high risk of unexpected consequences.)  For the moment, move NULL_P into
the set of keywords grouped with IDENT, so that at least it will act
similarly to non-keywords; and document the interaction.
This commit is contained in:
Tom Lane 2011-05-05 20:38:52 -04:00
parent 27525b1831
commit 12b7164578

View File

@ -597,7 +597,8 @@ static void SplitColQualList(List *qualList,
* have any bad effects since obviously the keywords will still behave the
* same as if they weren't keywords). We need to do this for PARTITION,
* RANGE, ROWS to support opt_existing_window_name; and for RANGE, ROWS
* so that they can follow a_expr without creating
* so that they can follow a_expr without creating postfix-operator problems;
* and for NULL so that it can follow b_expr in ColQualList without creating
* postfix-operator problems.
*
* The frame_bound productions UNBOUNDED PRECEDING and UNBOUNDED FOLLOWING
@ -610,16 +611,16 @@ static void SplitColQualList(List *qualList,
* blame any funny behavior of UNBOUNDED on the SQL standard, though.
*/
%nonassoc UNBOUNDED /* ideally should have same precedence as IDENT */
%nonassoc IDENT PARTITION RANGE ROWS PRECEDING FOLLOWING
%nonassoc IDENT NULL_P PARTITION RANGE ROWS PRECEDING FOLLOWING
%left Op OPERATOR /* multi-character ops and user-defined operators */
%nonassoc NOTNULL
%nonassoc ISNULL
%nonassoc IS NULL_P TRUE_P FALSE_P UNKNOWN /* sets precedence for IS NULL, etc */
%nonassoc IS /* sets precedence for IS NULL, etc */
%left '+' '-'
%left '*' '/' '%'
%left '^'
/* Unary Operators */
%left AT ZONE /* sets precedence for AT TIME ZONE */
%left AT /* sets precedence for AT TIME ZONE */
%left COLLATE
%right UMINUS
%left '[' ']'
@ -9705,7 +9706,7 @@ a_expr: c_expr { $$ = $1; }
n->location = @2;
$$ = (Node *) n;
}
| a_expr AT TIME ZONE a_expr
| a_expr AT TIME ZONE a_expr %prec AT
{
FuncCall *n = makeNode(FuncCall);
n->funcname = SystemFuncName("timezone");
@ -9887,7 +9888,7 @@ a_expr: c_expr { $$ = $1; }
* a ISNULL
* a NOTNULL
*/
| a_expr IS NULL_P
| a_expr IS NULL_P %prec IS
{
NullTest *n = makeNode(NullTest);
n->arg = (Expr *) $1;
@ -9901,7 +9902,7 @@ a_expr: c_expr { $$ = $1; }
n->nulltesttype = IS_NULL;
$$ = (Node *)n;
}
| a_expr IS NOT NULL_P
| a_expr IS NOT NULL_P %prec IS
{
NullTest *n = makeNode(NullTest);
n->arg = (Expr *) $1;
@ -9919,42 +9920,42 @@ a_expr: c_expr { $$ = $1; }
{
$$ = (Node *)makeOverlaps($1, $3, @2, yyscanner);
}
| a_expr IS TRUE_P
| a_expr IS TRUE_P %prec IS
{
BooleanTest *b = makeNode(BooleanTest);
b->arg = (Expr *) $1;
b->booltesttype = IS_TRUE;
$$ = (Node *)b;
}
| a_expr IS NOT TRUE_P
| a_expr IS NOT TRUE_P %prec IS
{
BooleanTest *b = makeNode(BooleanTest);
b->arg = (Expr *) $1;
b->booltesttype = IS_NOT_TRUE;
$$ = (Node *)b;
}
| a_expr IS FALSE_P
| a_expr IS FALSE_P %prec IS
{
BooleanTest *b = makeNode(BooleanTest);
b->arg = (Expr *) $1;
b->booltesttype = IS_FALSE;
$$ = (Node *)b;
}
| a_expr IS NOT FALSE_P
| a_expr IS NOT FALSE_P %prec IS
{
BooleanTest *b = makeNode(BooleanTest);
b->arg = (Expr *) $1;
b->booltesttype = IS_NOT_FALSE;
$$ = (Node *)b;
}
| a_expr IS UNKNOWN
| a_expr IS UNKNOWN %prec IS
{
BooleanTest *b = makeNode(BooleanTest);
b->arg = (Expr *) $1;
b->booltesttype = IS_UNKNOWN;
$$ = (Node *)b;
}
| a_expr IS NOT UNKNOWN
| a_expr IS NOT UNKNOWN %prec IS
{
BooleanTest *b = makeNode(BooleanTest);
b->arg = (Expr *) $1;