Skip to content

Commit

Permalink
Add support for chained expressions in CASE
Browse files Browse the repository at this point in the history
Adds logic that implements CASE in chained expressions.

Adds regression tests for CASE chained expression logic.
  • Loading branch information
dehowef committed Dec 1, 2023
1 parent b2d616d commit 2cb310d
Show file tree
Hide file tree
Showing 3 changed files with 303 additions and 0 deletions.
185 changes: 185 additions & 0 deletions regress/expected/expr.out
Original file line number Diff line number Diff line change
Expand Up @@ -6635,6 +6635,191 @@ $$ ) AS (case_statement agtype);
{"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', $$
Expand Down
95 changes: 95 additions & 0 deletions regress/sql/expr.sql
Original file line number Diff line number Diff line change
Expand Up @@ -2742,6 +2742,101 @@ SELECT * FROM cypher('case_statement', $$
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(*)
Expand Down
23 changes: 23 additions & 0 deletions src/backend/parser/cypher_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1493,6 +1493,17 @@ static Node *transform_CaseExpr(cypher_parsestate *cpstate, CaseExpr
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,
Expand All @@ -1506,6 +1517,18 @@ static Node *transform_CaseExpr(cypher_parsestate *cpstate, CaseExpr
"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;

Expand Down

0 comments on commit 2cb310d

Please sign in to comment.