We could do something like this.  Is this good?

I tried to merge WITH and WITHOUT with the precedence class immediately
above, but that failed: the main grammar compiles fine and no tests
fail, but ECPG does fail to compile the sqljson.pgc test, so there's
some problem there.  Now, the ecpg grammar stuff *is* absolute black
magic to me, so I have no idea what to do about that.

(TBH I don't think the added comments really explain the problems fully.
That's most likely because I don't actually understand what the problems
are.)

-- 
Álvaro Herrera               48°01'N 7°57'E  —  https://www.EnterpriseDB.com/
Thou shalt study thy libraries and strive not to reinvent them without
cause, that thy code may be short and readable and thy days pleasant
and productive. (7th Commandment for C Programmers)
>From 3499494625a59e2b5bda85c207b2d0e1181d703d Mon Sep 17 00:00:00 2001
From: Alvaro Herrera <alvhe...@alvh.no-ip.org>
Date: Mon, 27 Nov 2023 18:01:44 +0100
Subject: [PATCH v1] Merge JSON-related grammar keyword precedence classes

Some of these classes were unnecessary.  Grouping them this way also
helps us document the reason for these to exist at all.
---
 src/backend/parser/gram.y | 20 ++++++++++++++------
 1 file changed, 14 insertions(+), 6 deletions(-)

diff --git a/src/backend/parser/gram.y b/src/backend/parser/gram.y
index 8c00b119ec..3060dc88f8 100644
--- a/src/backend/parser/gram.y
+++ b/src/backend/parser/gram.y
@@ -821,11 +821,6 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
 %nonassoc	BETWEEN IN_P LIKE ILIKE SIMILAR NOT_LA
 %nonassoc	ESCAPE			/* ESCAPE must be just above LIKE/ILIKE/SIMILAR */
 
-/* SQL/JSON related keywords */
-%nonassoc	UNIQUE JSON
-%nonassoc	KEYS OBJECT_P SCALAR VALUE_P
-%nonassoc	WITH WITHOUT
-
 /*
  * To support target_el without AS, it used to be necessary to assign IDENT an
  * explicit precedence just less than Op.  While that's not really necessary
@@ -850,9 +845,22 @@ static Node *makeRecursiveViewSelect(char *relname, List *aliases, Node *query);
  * an explicit priority lower than '(', so that a rule with CUBE '(' will shift
  * rather than reducing a conflicting rule that takes CUBE as a function name.
  * Using the same precedence as IDENT seems right for the reasons given above.
+ *
+ * We also need to support WITH UNIQUE KEYS and WITHOUT UNIQUE KEYS, where
+ * KEYS is optional and the whole rule is also optional.  We can do this by
+ * putting UNIQUE above KEYS, and that one above WITH and WITHOUT.  We also
+ * have to declare the precedence of the empty production to be that of KEYS.
+ * We arbitrarily choose to put UNIQUE together with UNBOUNDED, and KEYS
+ * together with IDENT, then WITH and WITHOUT in a class of their own.
+ *
+ * For IS JSON {VALUE,OBJECT,SCALAR}, we need to split out the latter three
+ * from JSON; we put JSON with UNBOUNDED and the other three keywords in the
+ * group below.
  */
-%nonassoc	UNBOUNDED		/* ideally would have same precedence as IDENT */
+%nonassoc	UNBOUNDED UNIQUE JSON		/* ideally would have same precedence as IDENT */
 %nonassoc	IDENT PARTITION RANGE ROWS GROUPS PRECEDING FOLLOWING CUBE ROLLUP
+			KEYS OBJECT_P SCALAR VALUE_P
+%nonassoc	WITH WITHOUT
 %left		Op OPERATOR		/* multi-character ops and user-defined operators */
 %left		'+' '-'
 %left		'*' '/' '%'
-- 
2.39.2

Reply via email to