Remove precedence labeling of keywords TRUE, FALSE, UNKNOWN, and ZONE.
authorTom Lane <[email protected]>
Fri, 6 May 2011 00:38:52 +0000 (20:38 -0400)
committerTom Lane <[email protected]>
Fri, 6 May 2011 00:38:52 +0000 (20:38 -0400)
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.

src/backend/parser/gram.y

index 933a1a2ff9f3739529154e6e07aca4f1a06b95ab..dd959618419032acd3df1fa14644c9b2052dd462 100644 (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;