Location via proxy:   [ UP ]  
[Report a bug]   [Manage cookies]                
Skip to content

Commit a916b47

Browse files
committed
Clean up usage of bison precedence for non-operator keywords.
Assigning a precedence to a keyword that isn't a kind of expression operator is rather dangerous, because it might mask grammar ambiguities that we'd rather know about. It's much safer to attach explicit precedences to individual rules, which will affect the behavior of only that one rule. Moreover, when we do have to give a precedence to a non-operator keyword, we should try to give it the same precedence as IDENT, thereby reducing the risk of surprising side-effects. Apply this hard-won knowledge to SET (which I misassigned ages ago in commit 2647ad6) and some SQL/JSON-related productions (from commits 6ee3020, 71bfd15). Patch HEAD only, since there's no evidence of actual bugs here. Discussion: https://postgr.es/m/CADT4RqBPdbsZW7HS1jJP319TMRHs1hzUiP=iRJYR6UqgHCrgNQ@mail.gmail.com
1 parent c82207a commit a916b47

File tree

1 file changed

+44
-17
lines changed

1 file changed

+44
-17
lines changed

src/backend/parser/gram.y

+44-17
Original file line numberDiff line numberDiff line change
@@ -810,7 +810,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
810810

811811

812812
/* Precedence: lowest to highest */
813-
%nonassoc SET /* see relation_expr_opt_alias */
814813
%left UNION EXCEPT
815814
%left INTERSECT
816815
%left OR
@@ -821,18 +820,23 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
821820
%nonassoc BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
822821
%nonassoc ESCAPE /* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
823822

824-
/* SQL/JSON related keywords */
825-
%nonassoc UNIQUE JSON
826-
%nonassoc KEYS OBJECT_P SCALAR VALUE_P
827-
%nonassoc WITH WITHOUT
828-
829823
/*
830-
* To support target_el without AS, it used to be necessary to assign IDENT an
831-
* explicit precedence just less than Op. While that's not really necessary
832-
* since we removed postfix operators, it's still helpful to do so because
833-
* there are some other unreserved keywords that need precedence assignments.
834-
* If those keywords have the same precedence as IDENT then they clearly act
835-
* the same as non-keywords, reducing the risk of unwanted precedence effects.
824+
* Sometimes it is necessary to assign precedence to keywords that are not
825+
* really part of the operator hierarchy, in order to resolve grammar
826+
* ambiguities. It's best to avoid doing so whenever possible, because such
827+
* assignments have global effect and may hide ambiguities besides the one
828+
* you intended to solve. (Attaching a precedence to a single rule with
829+
* %prec is far safer and should be preferred.) If you must give precedence
830+
* to a new keyword, try very hard to give it the same precedence as IDENT.
831+
* If the keyword has IDENT's precedence then it clearly acts the same as
832+
* non-keywords and other similar keywords, thus reducing the risk of
833+
* unexpected precedence effects.
834+
*
835+
* We used to need to assign IDENT an explicit precedence just less than Op,
836+
* to support target_el without AS. While that's not really necessary since
837+
* we removed postfix operators, we continue to do so because it provides a
838+
* reference point for a precedence level that we can assign to other
839+
* keywords that lack a natural precedence level.
836840
*
837841
* We need to do this for PARTITION, RANGE, ROWS, and GROUPS to support
838842
* opt_existing_window_name (see comment there).
@@ -850,9 +854,18 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
850854
* an explicit priority lower than '(', so that a rule with CUBE '(' will shift
851855
* rather than reducing a conflicting rule that takes CUBE as a function name.
852856
* Using the same precedence as IDENT seems right for the reasons given above.
857+
*
858+
* SET is likewise assigned the same precedence as IDENT, to support the
859+
* relation_expr_opt_alias production (see comment there).
860+
*
861+
* KEYS, OBJECT_P, SCALAR, VALUE_P, WITH, and WITHOUT are similarly assigned
862+
* the same precedence as IDENT. This allows resolving conflicts in the
863+
* json_predicate_type_constraint and json_key_uniqueness_constraint_opt
864+
* productions (see comments there).
853865
*/
854866
%nonassoc UNBOUNDED /* ideally would have same precedence as IDENT */
855867
%nonassoc IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
868+
SET KEYS OBJECT_P SCALAR VALUE_P WITH WITHOUT
856869
%left Op OPERATOR /* multi-character ops and user-defined operators */
857870
%left '+' '-'
858871
%left '*' '/' '%'
@@ -16519,21 +16532,35 @@ json_returning_clause_opt:
1651916532
| /* EMPTY */ { $$ = NULL; }
1652016533
;
1652116534

16535+
/*
16536+
* We must assign the only-JSON production a precedence less than IDENT in
16537+
* order to favor shifting over reduction when JSON is followed by VALUE_P,
16538+
* OBJECT_P, or SCALAR. (ARRAY doesn't need that treatment, because it's a
16539+
* fully reserved word.) Because json_predicate_type_constraint is always
16540+
* followed by json_key_uniqueness_constraint_opt, we also need the only-JSON
16541+
* production to have precedence less than WITH and WITHOUT. UNBOUNDED isn't
16542+
* really related to this syntax, but it's a convenient choice because it
16543+
* already has a precedence less than IDENT for other reasons.
16544+
*/
1652216545
json_predicate_type_constraint:
16523-
JSON { $$ = JS_TYPE_ANY; }
16546+
JSON %prec UNBOUNDED { $$ = JS_TYPE_ANY; }
1652416547
| JSON VALUE_P { $$ = JS_TYPE_ANY; }
1652516548
| JSON ARRAY { $$ = JS_TYPE_ARRAY; }
1652616549
| JSON OBJECT_P { $$ = JS_TYPE_OBJECT; }
1652716550
| JSON SCALAR { $$ = JS_TYPE_SCALAR; }
1652816551
;
1652916552

16530-
/* KEYS is a noise word here */
16553+
/*
16554+
* KEYS is a noise word here. To avoid shift/reduce conflicts, assign the
16555+
* KEYS-less productions a precedence less than IDENT (i.e., less than KEYS).
16556+
* This prevents reducing them when the next token is KEYS.
16557+
*/
1653116558
json_key_uniqueness_constraint_opt:
1653216559
WITH UNIQUE KEYS { $$ = true; }
16533-
| WITH UNIQUE { $$ = true; }
16560+
| WITH UNIQUE %prec UNBOUNDED { $$ = true; }
1653416561
| WITHOUT UNIQUE KEYS { $$ = false; }
16535-
| WITHOUT UNIQUE { $$ = false; }
16536-
| /* EMPTY */ %prec KEYS { $$ = false; }
16562+
| WITHOUT UNIQUE %prec UNBOUNDED { $$ = false; }
16563+
| /* EMPTY */ %prec UNBOUNDED { $$ = false; }
1653716564
;
1653816565

1653916566
json_name_and_value_list:

0 commit comments

Comments
 (0)