You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by de...@apache.org on 2021/10/25 23:15:55 UTC
[incubator-age] branch master updated: Implement XOR Operator
This is an automated email from the ASF dual-hosted git repository.
dehowef pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-age.git
The following commit(s) were added to refs/heads/master by this push:
new 163e064 Implement XOR Operator
163e064 is described below
commit 163e064086eac52eb68dbc55a77897a74df01ce6
Author: Dehowe Feng <de...@gmail.com>
AuthorDate: Fri Oct 22 17:40:19 2021 -0700
Implement XOR Operator
Implemented XOR in the grammar using logical and, or and not.
This is ticket AGE2-478
Added regression tests.
---
regress/expected/expr.out | 34 +++++++++++++++++++++++++++++++++-
regress/sql/expr.sql | 18 +++++++++++++++++-
src/backend/parser/cypher_gram.y | 22 ++++++++++++++++++++++
src/backend/parser/cypher_keywords.c | 3 ++-
4 files changed, 74 insertions(+), 3 deletions(-)
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index 33a72aa..b90d4eb 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -492,7 +492,7 @@ $$) AS r(result boolean);
(1 row)
--
--- Test transform logic for AND, OR, and NOT
+-- Test transform logic for AND, OR, NOT and XOR
--
SELECT * FROM cypher('expr', $$
RETURN NOT false
@@ -582,6 +582,38 @@ $$) AS r(result boolean);
f
(1 row)
+SELECT * FROM cypher('expr', $$
+RETURN true XOR true
+$$) AS r(result boolean);
+ result
+--------
+ f
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+RETURN true XOR false
+$$) AS r(result boolean);
+ result
+--------
+ t
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+RETURN false XOR true
+$$) AS r(result boolean);
+ result
+--------
+ t
+(1 row)
+
+SELECT * FROM cypher('expr', $$
+RETURN false XOR false
+$$) AS r(result boolean);
+ result
+--------
+ f
+(1 row)
+
--
-- Test indirection transform logic for object.property, object["property"],
-- and array[element]
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index f26ba14..f2f5b8e 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -256,7 +256,7 @@ RETURN null IS NOT NULL
$$) AS r(result boolean);
--
--- Test transform logic for AND, OR, and NOT
+-- Test transform logic for AND, OR, NOT and XOR
--
SELECT * FROM cypher('expr', $$
@@ -303,6 +303,22 @@ SELECT * FROM cypher('expr', $$
RETURN NOT ((true OR false) AND (false OR true))
$$) AS r(result boolean);
+SELECT * FROM cypher('expr', $$
+RETURN true XOR true
+$$) AS r(result boolean);
+
+SELECT * FROM cypher('expr', $$
+RETURN true XOR false
+$$) AS r(result boolean);
+
+SELECT * FROM cypher('expr', $$
+RETURN false XOR true
+$$) AS r(result boolean);
+
+SELECT * FROM cypher('expr', $$
+RETURN false XOR false
+$$) AS r(result boolean);
+
--
-- Test indirection transform logic for object.property, object["property"],
-- and array[element]
diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y
index 3298456..6c1591b 100644
--- a/src/backend/parser/cypher_gram.y
+++ b/src/backend/parser/cypher_gram.y
@@ -93,6 +93,7 @@
THEN TRUE_P
VERBOSE
WHEN WHERE WITH
+ XOR
/* query */
%type <list> single_query query_part_init query_part_last
@@ -148,6 +149,7 @@
/* precedence: lowest to highest */
%left OR
%left AND
+%left XOR
%right NOT
%nonassoc '=' NOT_EQ '<' LT_EQ '>' GT_EQ
%left '+' '-'
@@ -164,6 +166,7 @@
// logical operators
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);
// arithmetic operators
@@ -1010,6 +1013,10 @@ expr:
{
$$ = make_and_expr($1, $3, @2);
}
+ | expr XOR expr
+ {
+ $$ = make_xor_expr($1, $3, @2);
+ }
| NOT expr
{
$$ = make_not_expr($2, @1);
@@ -1607,6 +1614,7 @@ safe_keywords:
| VERBOSE { $$ = pnstrdup($1, 7); }
| WHERE { $$ = pnstrdup($1, 5); }
| WITH { $$ = pnstrdup($1, 4); }
+ | XOR { $$ = pnstrdup($1, 3); }
;
conflicted_keywords:
@@ -1658,6 +1666,20 @@ static Node *make_and_expr(Node *lexpr, Node *rexpr, int location)
return (Node *)makeBoolExpr(AND_EXPR, list_make2(lexpr, rexpr), location);
}
+static Node *make_xor_expr(Node *lexpr, Node *rexpr, int location)
+{
+ Expr *aorb;
+ Expr *notaandb;
+
+ // XOR is (A OR B) AND (NOT (A AND B))
+ aorb = makeBoolExpr(OR_EXPR, list_make2(lexpr, rexpr), location);
+
+ notaandb = makeBoolExpr(AND_EXPR, list_make2(lexpr, rexpr), location);
+ notaandb = makeBoolExpr(NOT_EXPR, list_make1(notaandb), location);
+
+ return (Node *)makeBoolExpr(AND_EXPR, list_make2(aorb, notaandb), location);
+}
+
static Node *make_not_expr(Node *expr, int location)
{
return (Node *)makeBoolExpr(NOT_EXPR, list_make1(expr), location);
diff --git a/src/backend/parser/cypher_keywords.c b/src/backend/parser/cypher_keywords.c
index 64c6711..350683e 100644
--- a/src/backend/parser/cypher_keywords.c
+++ b/src/backend/parser/cypher_keywords.c
@@ -73,7 +73,8 @@ const ScanKeyword cypher_keywords[] = {
{"verbose", VERBOSE, RESERVED_KEYWORD},
{"when", WHEN, RESERVED_KEYWORD},
{"where", WHERE, RESERVED_KEYWORD},
- {"with", WITH, RESERVED_KEYWORD}
+ {"with", WITH, RESERVED_KEYWORD},
+ {"xor", XOR, RESERVED_KEYWORD}
};
const int num_cypher_keywords = lengthof(cypher_keywords);