Skip to content

Commit

Permalink
Add support for chained expressions in CASE (apache#1431)
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 c9e313f commit b8eb016
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 @@ -6457,6 +6457,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 @@ -2673,6 +2673,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 @@ -1368,6 +1368,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 @@ -1381,6 +1392,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 b8eb016

Please sign in to comment.