Add support for chained expressions in CASE (#1431)
Adds logic that implements CASE in chained expressions.
Adds regression tests for CASE chained expression logic.
diff --git a/regress/expected/expr.out b/regress/expected/expr.out
index e55285a..651035e 100644
--- a/regress/expected/expr.out
+++ b/regress/expected/expr.out
@@ -6635,6 +6635,191 @@
{"id": 844424930131970, "label": "connected_to", "end_id": 281474976710660, "start_id": 281474976710659, "properties": {"k": 1, "id": 2}}::edge
(2 rows)
+--CASE chained expressions
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+-------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"i": 1, "id": 1}}::vertex
+ "none"
+ "none"
+ "none"
+ "none"
+ "none"
+(6 rows)
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE
+ WHEN null THEN 'should not return me'
+ WHEN n.i = (1 = 1) THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+----------------------------------------------------------------------------------------------
+ "none"
+ "none"
+ "none"
+ {"id": 281474976710660, "label": "", "properties": {"i": true, "j": false, "id": 4}}::vertex
+ "none"
+ "none"
+(6 rows)
+
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+----------------
+ "none"
+ "none"
+ "none"
+ "none"
+ "none"
+ "none"
+(6 rows)
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n = 1
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+------------------------------------------------------------------------------------------------
+ "none"
+ {"id": 281474976710658, "label": "", "properties": {"i": "a", "j": "b", "id": 2}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"i": 0, "j": 1, "id": 3}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"i": true, "j": false, "id": 4}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"i": [], "j": [0, 1, 2], "id": 5}}::vertex
+ {"id": 281474976710662, "label": "", "properties": {"i": {}, "j": {"i": 1}, "id": 6}}::vertex
+(6 rows)
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n = 1
+ WHEN null THEN 'should not return me'
+ WHEN n.i = (1 = 1) THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+------------------------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"i": 1, "id": 1}}::vertex
+ {"id": 281474976710658, "label": "", "properties": {"i": "a", "j": "b", "id": 2}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"i": 0, "j": 1, "id": 3}}::vertex
+ "none"
+ {"id": 281474976710661, "label": "", "properties": {"i": [], "j": [0, 1, 2], "id": 5}}::vertex
+ {"id": 281474976710662, "label": "", "properties": {"i": {}, "j": {"i": 1}, "id": 6}}::vertex
+(6 rows)
+
+--should return n
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n = 1
+ WHEN null THEN 'should not return me'
+ WHEN n = 1 = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+------------------------------------------------------------------------------------------------
+ {"id": 281474976710657, "label": "", "properties": {"i": 1, "id": 1}}::vertex
+ {"id": 281474976710658, "label": "", "properties": {"i": "a", "j": "b", "id": 2}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"i": 0, "j": 1, "id": 3}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"i": true, "j": false, "id": 4}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"i": [], "j": [0, 1, 2], "id": 5}}::vertex
+ {"id": 281474976710662, "label": "", "properties": {"i": {}, "j": {"i": 1}, "id": 6}}::vertex
+(6 rows)
+
+--chained expression in THEN
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 THEN n.i = 1 = 1
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+----------------
+ true
+ "none"
+ "none"
+ "none"
+ "none"
+ "none"
+(6 rows)
+
+--order of operations in then
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n THEN (n.i = 1) = 1
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+----------------
+ false
+ false
+ false
+ false
+ false
+ false
+(6 rows)
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n THEN n.i = (1 = 1)
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+----------------
+ false
+ false
+ false
+ true
+ false
+ false
+(6 rows)
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n THEN n.i = (1 = 0)
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+ case_statement
+----------------
+ false
+ false
+ false
+ false
+ false
+ false
+(6 rows)
+
--CASE with count()
--count(*)
SELECT * FROM cypher('case_statement', $$
diff --git a/regress/sql/expr.sql b/regress/sql/expr.sql
index 85065e0..738606d 100644
--- a/regress/sql/expr.sql
+++ b/regress/sql/expr.sql
@@ -2742,6 +2742,101 @@
END
$$ ) AS (case_statement agtype);
+--CASE chained expressions
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE
+ WHEN null THEN 'should not return me'
+ WHEN n.i = (1 = 1) THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n = 1
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n = 1
+ WHEN null THEN 'should not return me'
+ WHEN n.i = (1 = 1) THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+--should return n
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n = 1
+ WHEN null THEN 'should not return me'
+ WHEN n = 1 = 1 THEN n
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+--chained expression in THEN
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE
+ WHEN null THEN 'should not return me'
+ WHEN n.i = 1 THEN n.i = 1 = 1
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+--order of operations in then
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n THEN (n.i = 1) = 1
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n THEN n.i = (1 = 1)
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
+SELECT * FROM cypher('case_statement', $$
+ MATCH (n)
+ RETURN CASE n
+ WHEN null THEN 'should not return me'
+ WHEN n THEN n.i = (1 = 0)
+ ELSE 'none'
+ END
+$$ ) AS (case_statement agtype);
+
--CASE with count()
--count(*)
diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c
index ac08164..0efd448 100644
--- a/src/backend/parser/cypher_expr.c
+++ b/src/backend/parser/cypher_expr.c
@@ -1493,6 +1493,17 @@
warg = (Node *) w->expr;
if (placeholder)
{
+ if(is_ag_node(warg, cypher_comparison_aexpr) ||
+ is_ag_node(warg, cypher_comparison_boolexpr) )
+ {
+ List *funcname = list_make1(makeString("ag_catalog"));
+ funcname = lappend(funcname, makeString("bool_to_agtype"));
+
+ warg = (Node *) makeFuncCall(funcname, list_make1(warg),
+ COERCE_EXPLICIT_CAST,
+ cexpr->location);
+ }
+
/* shorthand form was specified, so expand... */
warg = (Node *) makeSimpleA_Expr(AEXPR_OP, "=",
(Node *) placeholder,
@@ -1506,6 +1517,18 @@
"CASE/WHEN");
warg = (Node *) w->result;
+
+ if(is_ag_node(warg, cypher_comparison_aexpr) ||
+ is_ag_node(warg, cypher_comparison_boolexpr) )
+ {
+ List *funcname = list_make1(makeString("ag_catalog"));
+ funcname = lappend(funcname, makeString("bool_to_agtype"));
+
+ warg = (Node *) makeFuncCall(funcname, list_make1(warg),
+ COERCE_EXPLICIT_CAST,
+ cexpr->location);
+ }
+
neww->result = (Expr *) transform_cypher_expr_recurse(cpstate, warg);
neww->location = w->location;