This is an automated email from the ASF dual-hosted git repository.

rafsun42 pushed a commit to branch PG11
in repository https://gitbox.apache.org/repos/asf/age.git


The following commit(s) were added to refs/heads/PG11 by this push:
     new fb10c9ef Implement chained expression order of operations (#1402) 
(#1410)
fb10c9ef is described below

commit fb10c9eff3d09d2cd6b619674848608749429300
Author: Dehowe Feng <[email protected]>
AuthorDate: Mon Nov 20 08:53:56 2023 -0800

    Implement chained expression order of operations (#1402) (#1410)
    
    Implements functionality for order of operations (parentheses) in
    chained operations.
    
    Added new nodes and functions to accomodate this feature.
    
    Added relevant regression tests for order of operations in chained
    expressions.
    
    Modified a previous regression test case that had its location
    reporting changed by this implementation.
---
 regress/expected/cypher_call.out    |   4 +-
 regress/expected/expr.out           | 129 ++++++++++++++++++++++++++++++++++++
 regress/sql/expr.sql                |  25 +++++++
 src/backend/nodes/ag_nodes.c        |   4 ++
 src/backend/nodes/cypher_outfuncs.c |  22 ++++++
 src/backend/parser/cypher_expr.c    |  47 +++++++++++++
 src/backend/parser/cypher_gram.y    | 110 +++++++++++++++++++++++-------
 src/include/nodes/ag_nodes.h        |   3 +
 src/include/nodes/cypher_nodes.h    |  23 +++++++
 src/include/nodes/cypher_outfuncs.h |   4 ++
 10 files changed, 344 insertions(+), 27 deletions(-)

diff --git a/regress/expected/cypher_call.out b/regress/expected/cypher_call.out
index f7e45a05..b8babb88 100644
--- a/regress/expected/cypher_call.out
+++ b/regress/expected/cypher_call.out
@@ -84,8 +84,8 @@ HINT:  No function matches the given name and argument types. 
You might need to
 /* CALL YIELD WHERE, should fail */
 SELECT * FROM cypher('cypher_call', $$CALL sqrt(64) YIELD sqrt WHERE sqrt > 
1$$) as (sqrt agtype);
 ERROR:  Cannot use standalone CALL with WHERE
-LINE 2: ...r('cypher_call', $$CALL sqrt(64) YIELD sqrt WHERE sqrt > 1$$...
-                                                             ^
+LINE 2: SELECT * FROM cypher('cypher_call', $$CALL sqrt(64) YIELD sq...
+                                             ^
 HINT:  Instead use `CALL ... WITH * WHERE ... RETURN *`
 /*
  * subquery
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index aa7ddfb8..42128ee2 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -740,6 +740,135 @@ SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE 
NOT 35 < u.age + 1 <=
  {"id": 844424930131973, "label": "people", "properties": {"age": 15, "name": 
"David"}}::vertex
 (3 rows)
 
+-- order of operations
+-- expressions
+SELECT * FROM cypher('chained', $$ RETURN 1 = 1 = 1 $$) AS (result agtype);
+ result 
+--------
+ true
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN 1 = 2 = 1 $$) AS (result agtype);
+ result 
+--------
+ false
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN (1 = 1) = 1 $$) AS (result agtype);
+ result 
+--------
+ false
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN 1 = (1 = 1) $$) AS (result agtype);
+ result 
+--------
+ false
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN 1 = 1 = true $$) AS (result agtype);
+ result 
+--------
+ false
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN (1 = 1) = true $$) AS (result 
agtype);
+ result 
+--------
+ true
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN true = ((1 = 1) = true) $$) AS 
(result agtype);
+ result 
+--------
+ true
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN ((1 = 1) = 1) = 1 $$) AS (result 
agtype);
+ result 
+--------
+ false
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN (1 = (1 = 1)) = 1 $$) AS (result 
agtype);
+ result 
+--------
+ false
+(1 row)
+
+SELECT * FROM cypher('chained', $$ RETURN ((1 = (1 = 1)) = 1) = 1 $$) AS 
(result agtype);
+ result 
+--------
+ false
+(1 row)
+
+-- in clause
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE 35 = u.age = 35  
RETURN u $$) AS (result agtype);
+                                              result                           
                    
+---------------------------------------------------------------------------------------------------
+ {"id": 844424930131971, "label": "people", "properties": {"age": 35, "name": 
"Samantha"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (35 = u.age) = 35  
RETURN u $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (35 = 35) = u.age  
RETURN u $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = u.age = 
u.age  RETURN u $$) AS (result agtype);
+                                              result                           
                    
+---------------------------------------------------------------------------------------------------
+ {"id": 844424930131969, "label": "people", "properties": {"age": 50, "name": 
"Jason"}}::vertex
+ {"id": 844424930131970, "label": "people", "properties": {"age": 25, "name": 
"Amy"}}::vertex
+ {"id": 844424930131971, "label": "people", "properties": {"age": 35, "name": 
"Samantha"}}::vertex
+ {"id": 844424930131972, "label": "people", "properties": {"age": 40, "name": 
"Mark"}}::vertex
+ {"id": 844424930131973, "label": "people", "properties": {"age": 15, "name": 
"David"}}::vertex
+(5 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (u.age = u.age) = 
u.age  RETURN u $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = (u.age = 
u.age)  RETURN u $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (u.age = u.age) = 
(u.age = u.age)  RETURN u $$) AS (result agtype);
+                                              result                           
                    
+---------------------------------------------------------------------------------------------------
+ {"id": 844424930131969, "label": "people", "properties": {"age": 50, "name": 
"Jason"}}::vertex
+ {"id": 844424930131970, "label": "people", "properties": {"age": 25, "name": 
"Amy"}}::vertex
+ {"id": 844424930131971, "label": "people", "properties": {"age": 35, "name": 
"Samantha"}}::vertex
+ {"id": 844424930131972, "label": "people", "properties": {"age": 40, "name": 
"Mark"}}::vertex
+ {"id": 844424930131973, "label": "people", "properties": {"age": 15, "name": 
"David"}}::vertex
+(5 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = (u.age = 
(u.age = u.age))  RETURN u $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = 35 = ((u.age 
= u.age) = u.age) RETURN u $$) AS (result agtype);
+ result 
+--------
+(0 rows)
+
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE ((u.age = u.age) = 
(u.age = u.age)) = (u.age = u.age)  RETURN u $$) AS (result agtype);
+                                              result                           
                    
+---------------------------------------------------------------------------------------------------
+ {"id": 844424930131969, "label": "people", "properties": {"age": 50, "name": 
"Jason"}}::vertex
+ {"id": 844424930131970, "label": "people", "properties": {"age": 25, "name": 
"Amy"}}::vertex
+ {"id": 844424930131971, "label": "people", "properties": {"age": 35, "name": 
"Samantha"}}::vertex
+ {"id": 844424930131972, "label": "people", "properties": {"age": 40, "name": 
"Mark"}}::vertex
+ {"id": 844424930131973, "label": "people", "properties": {"age": 15, "name": 
"David"}}::vertex
+(5 rows)
+
 --
 -- Test transform logic for IS NULL & IS NOT NULL
 --
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index f801c448..649b3d32 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -309,6 +309,31 @@ SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE 
35 < u.age + 1 <= 50 R
 -- should return 3
 SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE NOT 35 < u.age + 1 
<= 50 RETURN u $$) AS (result agtype);
 
+-- order of operations
+-- expressions
+SELECT * FROM cypher('chained', $$ RETURN 1 = 1 = 1 $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ RETURN 1 = 2 = 1 $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ RETURN (1 = 1) = 1 $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ RETURN 1 = (1 = 1) $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ RETURN 1 = 1 = true $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ RETURN (1 = 1) = true $$) AS (result 
agtype);
+SELECT * FROM cypher('chained', $$ RETURN true = ((1 = 1) = true) $$) AS 
(result agtype);
+SELECT * FROM cypher('chained', $$ RETURN ((1 = 1) = 1) = 1 $$) AS (result 
agtype);
+SELECT * FROM cypher('chained', $$ RETURN (1 = (1 = 1)) = 1 $$) AS (result 
agtype);
+SELECT * FROM cypher('chained', $$ RETURN ((1 = (1 = 1)) = 1) = 1 $$) AS 
(result agtype);
+
+-- in clause
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE 35 = u.age = 35  
RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (35 = u.age) = 35  
RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (35 = 35) = u.age  
RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = u.age = 
u.age  RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (u.age = u.age) = 
u.age  RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = (u.age = 
u.age)  RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE (u.age = u.age) = 
(u.age = u.age)  RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = (u.age = 
(u.age = u.age))  RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE u.age = 35 = ((u.age 
= u.age) = u.age) RETURN u $$) AS (result agtype);
+SELECT * FROM cypher('chained', $$ MATCH (u:people) WHERE ((u.age = u.age) = 
(u.age = u.age)) = (u.age = u.age)  RETURN u $$) AS (result agtype);
+
 --
 -- Test transform logic for IS NULL & IS NOT NULL
 --
diff --git a/src/backend/nodes/ag_nodes.c b/src/backend/nodes/ag_nodes.c
index 14715bd2..dee460b3 100644
--- a/src/backend/nodes/ag_nodes.c
+++ b/src/backend/nodes/ag_nodes.c
@@ -48,6 +48,8 @@ const char *node_names[] = {
     "cypher_param",
     "cypher_map",
     "cypher_list",
+    "cypher_comparison_aexpr",
+    "cypher_comparison_boolexpr",
     "cypher_string_match",
     "cypher_typecast",
     "cypher_integer_const",
@@ -111,6 +113,8 @@ const ExtensibleNodeMethods node_methods[] = {
     DEFINE_NODE_METHODS(cypher_param),
     DEFINE_NODE_METHODS(cypher_map),
     DEFINE_NODE_METHODS(cypher_list),
+    DEFINE_NODE_METHODS(cypher_comparison_aexpr),
+    DEFINE_NODE_METHODS(cypher_comparison_boolexpr),
     DEFINE_NODE_METHODS(cypher_string_match),
     DEFINE_NODE_METHODS(cypher_typecast),
     DEFINE_NODE_METHODS(cypher_integer_const),
diff --git a/src/backend/nodes/cypher_outfuncs.c 
b/src/backend/nodes/cypher_outfuncs.c
index d7fc791b..8ca1df0e 100644
--- a/src/backend/nodes/cypher_outfuncs.c
+++ b/src/backend/nodes/cypher_outfuncs.c
@@ -259,6 +259,28 @@ void out_cypher_list(StringInfo str, const ExtensibleNode 
*node)
     WRITE_LOCATION_FIELD(location);
 }
 
+// serialization function for the cypher_comparison_aexpr ExtensibleNode.
+void out_cypher_comparison_aexpr(StringInfo str, const ExtensibleNode *node)
+{
+    DEFINE_AG_NODE(cypher_comparison_aexpr);
+
+    WRITE_ENUM_FIELD(kind, A_Expr_Kind);
+    WRITE_NODE_FIELD(name);
+    WRITE_NODE_FIELD(lexpr);
+    WRITE_NODE_FIELD(rexpr);
+    WRITE_LOCATION_FIELD(location);
+}
+
+// serialization function for the cypher_comparison_boolexpr ExtensibleNode.
+void out_cypher_comparison_boolexpr(StringInfo str, const ExtensibleNode *node)
+{
+    DEFINE_AG_NODE(cypher_comparison_boolexpr);
+
+    WRITE_ENUM_FIELD(boolop, BoolExprType);
+    WRITE_NODE_FIELD(args);
+    WRITE_LOCATION_FIELD(location);
+}
+
 // serialization function for the cypher_string_match ExtensibleNode.
 void out_cypher_string_match(StringInfo str, const ExtensibleNode *node)
 {
diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c
index b44c06bc..7c31dde9 100644
--- a/src/backend/parser/cypher_expr.c
+++ b/src/backend/parser/cypher_expr.c
@@ -71,7 +71,11 @@ static Node *transform_ColumnRef(cypher_parsestate *cpstate, 
ColumnRef *cref);
 static Node *transform_A_Indirection(cypher_parsestate *cpstate,
                                      A_Indirection *a_ind);
 static Node *transform_AEXPR_OP(cypher_parsestate *cpstate, A_Expr *a);
+static Node *transform_cypher_comparison_aexpr_OP(cypher_parsestate *cpstate,
+                                                  cypher_comparison_aexpr *a);
 static Node *transform_BoolExpr(cypher_parsestate *cpstate, BoolExpr *expr);
+static Node *transform_cypher_comparison_boolexpr(cypher_parsestate *cpstate,
+                                                  cypher_comparison_boolexpr 
*b);
 static Node *transform_cypher_bool_const(cypher_parsestate *cpstate,
                                          cypher_bool_const *bc);
 static Node *transform_cypher_integer_const(cypher_parsestate *cpstate,
@@ -190,6 +194,12 @@ static Node 
*transform_cypher_expr_recurse(cypher_parsestate *cpstate,
         if (is_ag_node(expr, cypher_typecast))
             return transform_cypher_typecast(cpstate,
                                              (cypher_typecast *)expr);
+        if (is_ag_node(expr, cypher_comparison_aexpr))
+            return transform_cypher_comparison_aexpr_OP(cpstate,
+                                             (cypher_comparison_aexpr *)expr);
+        if (is_ag_node(expr, cypher_comparison_boolexpr))
+            return transform_cypher_comparison_boolexpr(cpstate,
+                                             (cypher_comparison_boolexpr 
*)expr);
         ereport(ERROR,
                 (errmsg_internal("unrecognized ExtensibleNode: %s",
                                  ((ExtensibleNode *)expr)->extnodename)));
@@ -466,6 +476,25 @@ static Node *transform_AEXPR_OP(cypher_parsestate 
*cpstate, A_Expr *a)
                            a->location);
 }
 
+/*
+ * function for transforming cypher comparision A_Expr. Since this node is a
+ * wrapper to let us know when a comparison occurs in a chained comparison,
+ * we convert it to a regular A_expr and transform it.
+ */
+static Node *transform_cypher_comparison_aexpr_OP(cypher_parsestate *cpstate,
+                                                  cypher_comparison_aexpr *a)
+{
+    A_Expr *n = makeNode(A_Expr);
+    n->kind = a->kind;
+    n->name = a->name;
+    n->lexpr = a->lexpr;
+    n->rexpr = a->rexpr;
+    n->location = a->location;
+
+    return (Node *)transform_AEXPR_OP(cpstate, n);
+}
+
+
 static Node *transform_AEXPR_IN(cypher_parsestate *cpstate, A_Expr *a)
 {
     Oid func_in_oid;
@@ -524,6 +553,24 @@ static Node *transform_BoolExpr(cypher_parsestate 
*cpstate, BoolExpr *expr)
     return (Node *)makeBoolExpr(expr->boolop, args, expr->location);
 }
 
+/*
+ * function for transforming cypher_comparison_boolexpr. Since this node is a
+ * wrapper to let us know when a comparison occurs in a chained comparison,
+ * we convert it to a PG BoolExpr and transform it.
+ */
+static Node *transform_cypher_comparison_boolexpr(cypher_parsestate *cpstate,
+                                                  cypher_comparison_boolexpr 
*b)
+{
+    BoolExpr *n = makeNode(BoolExpr);
+
+    n->boolop = b->boolop;
+    n->args = b->args;
+    n->location = b->location;
+
+    return transform_BoolExpr(cpstate, n);
+}
+
+
 static Node *transform_cypher_bool_const(cypher_parsestate *cpstate,
                                          cypher_bool_const *bc)
 {
diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y
index 273ae6d4..419170e3 100644
--- a/src/backend/parser/cypher_gram.y
+++ b/src/backend/parser/cypher_gram.y
@@ -205,6 +205,12 @@ static Node *make_or_expr(Node *lexpr, Node *rexpr, int 
location);
 static Node *make_and_expr(Node *lexpr, Node *rexpr, int location);
 static Node *make_xor_expr(Node *lexpr, Node *rexpr, int location);
 static Node *make_not_expr(Node *expr, int location);
+static Node *make_comparison_and_expr(Node *lexpr, Node *rexpr, int location);
+static Node *make_cypher_comparison_aexpr(A_Expr_Kind kind, char *name,
+                                          Node *lexpr, Node *rexpr,
+                                          int location);
+static Node *make_cypher_comparison_boolexpr(BoolExprType boolop, List *args,
+                                               int location);
 
 // arithmetic operators
 static Node *do_negate(Node *n, int location);
@@ -240,7 +246,7 @@ static cypher_relationship *build_VLE_relation(List 
*left_arg,
                                                int left_arg_location,
                                                int cr_location);
 // comparison
-static bool is_A_Expr_a_comparison_operation(A_Expr *a);
+static bool is_A_Expr_a_comparison_operation(cypher_comparison_aexpr *a);
 static Node *build_comparison_expression(Node *left_grammar_node,
                                          Node *right_grammar_node,
                                          char *opr_name, int location);
@@ -1762,7 +1768,14 @@ expr_atom:
         }
     | '(' expr ')'
         {
-            $$ = $2;
+            Node *n = $2;
+
+            if (is_ag_node(n, cypher_comparison_aexpr) ||
+                is_ag_node(n, cypher_comparison_boolexpr))
+            {
+                n = (Node *)node_to_agtype(n, "boolean", @2);
+            }
+            $$ = n;
         }
     | expr_case
     | expr_var
@@ -2101,6 +2114,51 @@ static Node *make_not_expr(Node *expr, int location)
     return (Node *)makeBoolExpr(NOT_EXPR, list_make1(expr), location);
 }
 
+/*
+ * chained expression comparison operators
+ */
+
+static Node *make_cypher_comparison_aexpr(A_Expr_Kind kind, char *name,
+                 Node *lexpr, Node *rexpr, int location)
+{
+    cypher_comparison_aexpr *a = make_ag_node(cypher_comparison_aexpr);
+
+    a->kind = kind;
+    a->name = list_make1(makeString((char *) name));
+    a->lexpr = lexpr;
+    a->rexpr = rexpr;
+    a->location = location;
+    return (Node *)a;
+}
+
+static Node *make_cypher_comparison_boolexpr(BoolExprType boolop, List *args, 
int location)
+{
+    cypher_comparison_boolexpr *b = make_ag_node(cypher_comparison_boolexpr);
+
+    b->boolop = boolop;
+    b->args = args;
+    b->location = location;
+    return (Node *)b;
+}
+
+static Node *make_comparison_and_expr(Node *lexpr, Node *rexpr, int location)
+{
+    // flatten "a AND b AND c ..." to a single BoolExpr on sight
+    if (is_ag_node(lexpr, cypher_comparison_boolexpr))
+    {
+        cypher_comparison_boolexpr *bexpr = (cypher_comparison_boolexpr 
*)lexpr;
+
+        if (bexpr->boolop == AND_EXPR)
+        {
+            bexpr->args = lappend(bexpr->args, rexpr);
+
+            return (Node *)bexpr;
+        }
+    }
+
+    return (Node *)make_cypher_comparison_boolexpr(AND_EXPR, list_make2(lexpr, 
rexpr), location);
+}
+
 /*
  * arithmetic operators
  */
@@ -2512,7 +2570,7 @@ static Node *make_set_op(SetOperation op, bool 
all_or_distinct, List *larg,
 }
 
 /* check if A_Expr is a comparison expression */
-static bool is_A_Expr_a_comparison_operation(A_Expr *a)
+static bool is_A_Expr_a_comparison_operation(cypher_comparison_aexpr *a)
 {
     Value *v = NULL;
     char *opr_name = NULL;
@@ -2578,75 +2636,77 @@ static Node *build_comparison_expression(Node 
*left_grammar_node,
 
     /*
      * Case 1:
-     *    If the previous expression is an A_Expr and it is also a
+     *    If the left expression is an A_Expr and it is also a
      *    comparison, then this is part of a chained comparison. In this
      *    specific case, the second chained element.
      */
-    if (IsA(left_grammar_node, A_Expr) &&
-        is_A_Expr_a_comparison_operation((A_Expr *)left_grammar_node))
+    if (is_ag_node(left_grammar_node, cypher_comparison_aexpr) &&
+        is_A_Expr_a_comparison_operation((cypher_comparison_aexpr 
*)left_grammar_node))
     {
-        A_Expr *aexpr = NULL;
+        cypher_comparison_aexpr *aexpr = NULL;
         Node *lexpr = NULL;
         Node *n = NULL;
 
         /* get the A_Expr on the left side */
-        aexpr = (A_Expr *) left_grammar_node;
+        aexpr = (cypher_comparison_aexpr *)left_grammar_node;
         /* get its rexpr which will be our lexpr */
         lexpr = aexpr->rexpr;
         /* build our comparison operator */
-        n = (Node *)makeSimpleA_Expr(AEXPR_OP, opr_name, lexpr,
+        n = (Node *)make_cypher_comparison_aexpr(AEXPR_OP, opr_name, lexpr,
                                      right_grammar_node, location);
 
         /* now add it (AND) to the other comparison */
-        result_expr = make_and_expr(left_grammar_node, n, location);
+        result_expr = make_comparison_and_expr(left_grammar_node, n, location);
     }
 
     /*
      * Case 2:
-     *    If the previous expression is a boolean AND and its right most
+     *    If the left expression is a boolean AND and its right most
      *    expression is an A_Expr and a comparison, then this is part of
      *    a chained comparison. In this specific case, the third and
      *    beyond chained element.
      */
-    if (IsA(left_grammar_node, BoolExpr) &&
-        ((BoolExpr*)left_grammar_node)->boolop == AND_EXPR)
+    else if (is_ag_node(left_grammar_node, cypher_comparison_boolexpr) &&
+        ((cypher_comparison_boolexpr*)left_grammar_node)->boolop == AND_EXPR)
     {
-        BoolExpr *bexpr = NULL;
+        cypher_comparison_boolexpr *bexpr = NULL;
         Node *last = NULL;
 
         /* cast the left to a boolean */
-        bexpr = (BoolExpr *)left_grammar_node;
+        bexpr = (cypher_comparison_boolexpr *)left_grammar_node;
         /* extract the last node - ANDs are chained in a flat list */
         last = llast(bexpr->args);
 
         /* is the last node an A_Expr and a comparison operator */
-        if (IsA(last, A_Expr) &&
-            is_A_Expr_a_comparison_operation((A_Expr *)last))
+        if (is_ag_node(last, cypher_comparison_aexpr) &&
+            is_A_Expr_a_comparison_operation((cypher_comparison_aexpr *)last))
         {
-            A_Expr *aexpr = NULL;
+            cypher_comparison_aexpr *aexpr = NULL;
             Node *lexpr = NULL;
             Node *n = NULL;
 
             /* get the last expressions right expression */
-            aexpr = (A_Expr *) last;
+            aexpr = (cypher_comparison_aexpr *) last;
             lexpr = aexpr->rexpr;
             /* make our comparison operator */
-            n = (Node *)makeSimpleA_Expr(AEXPR_OP, opr_name, lexpr,
+            n = (Node *)make_cypher_comparison_aexpr(AEXPR_OP, opr_name, lexpr,
                                          right_grammar_node, location);
 
             /* now add it (AND) to the other comparisons */
-            result_expr = make_and_expr(left_grammar_node, n, location);
+            result_expr = make_comparison_and_expr(left_grammar_node, n, 
location);
         }
     }
 
+
     /*
      * Case 3:
-     *    The previous expression isn't a chained comparison. So, treat
-     *    it as a regular comparison expression.
+     *    The left expression isn't a chained comparison. So, treat
+     *    it as a regular comparison expression. This is usually an initial
+     *    comparison expression.
      */
-    if (result_expr == NULL)
+    else if (result_expr == NULL)
     {
-        result_expr = (Node *)makeSimpleA_Expr(AEXPR_OP, opr_name,
+        result_expr = (Node *)make_cypher_comparison_aexpr(AEXPR_OP, opr_name,
                                                left_grammar_node,
                                                right_grammar_node, location);
     }
diff --git a/src/include/nodes/ag_nodes.h b/src/include/nodes/ag_nodes.h
index e51a8de4..481c75b5 100644
--- a/src/include/nodes/ag_nodes.h
+++ b/src/include/nodes/ag_nodes.h
@@ -51,6 +51,9 @@ typedef enum ag_node_tag
     cypher_param_t,
     cypher_map_t,
     cypher_list_t,
+    // comparison expression
+    cypher_comparison_aexpr_t,
+    cypher_comparison_boolexpr_t,
     // string match
     cypher_string_match_t,
     // typecast
diff --git a/src/include/nodes/cypher_nodes.h b/src/include/nodes/cypher_nodes.h
index d6d8c02d..9fbf27b6 100644
--- a/src/include/nodes/cypher_nodes.h
+++ b/src/include/nodes/cypher_nodes.h
@@ -239,6 +239,29 @@ typedef struct cypher_create_path
     char *var_name;
 } cypher_create_path;
 
+/*
+ * comparison expressions
+ */
+
+typedef struct cypher_comparison_aexpr
+{
+    ExtensibleNode extensible;
+    A_Expr_Kind kind; /* see above */
+    List *name; /* possibly-qualified name of operator */
+    Node *lexpr; /* left argument, or NULL if none */
+    Node *rexpr; /* right argument, or NULL if none */
+    int location; /* token location, or -1 if unknown */
+} cypher_comparison_aexpr;
+
+typedef struct cypher_comparison_boolexpr
+{
+    ExtensibleNode extensible;
+    BoolExprType boolop;
+    List       *args;           /* arguments to this expression */
+    int         location;       /* token location, or -1 if unknown */
+} cypher_comparison_boolexpr;
+
+
 /*
  * procedure call
  */
diff --git a/src/include/nodes/cypher_outfuncs.h 
b/src/include/nodes/cypher_outfuncs.h
index 836765bc..4071b28d 100644
--- a/src/include/nodes/cypher_outfuncs.h
+++ b/src/include/nodes/cypher_outfuncs.h
@@ -53,6 +53,10 @@ void out_cypher_param(StringInfo str, const ExtensibleNode 
*node);
 void out_cypher_map(StringInfo str, const ExtensibleNode *node);
 void out_cypher_list(StringInfo str, const ExtensibleNode *node);
 
+// comparison expression
+void out_cypher_comparison_aexpr(StringInfo str, const ExtensibleNode *node);
+void out_cypher_comparison_boolexpr(StringInfo str, const ExtensibleNode 
*node);
+
 // string match
 void out_cypher_string_match(StringInfo str, const ExtensibleNode *node);
 

Reply via email to