Skip to content
Open
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
37 changes: 32 additions & 5 deletions src/backend/parser/parse_cypher_expr.c
Original file line number Diff line number Diff line change
Expand Up @@ -1888,12 +1888,33 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
a->location);
break;
default:
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("CypherList is expected but %s",
format_type_be(exprType(rexpr))),
parser_errposition(pstate, exprLocation(a->rexpr))));
{
/*
* For other expr types, check if the result type is compatible
* with JSONB containment.
*/
Oid rtype = exprType(rexpr);

if (rtype == JSONBOID || type_is_array(rtype) || rtype == ANYARRAYOID)
{
/* Coerce anyarray to jsonb for containment operator */
if (rtype == ANYARRAYOID || type_is_array(rtype))
rexpr = coerce_to_jsonb(pstate, rexpr, "list");

result = (Node *) make_op(pstate, list_make1(makeString("@>")),
rexpr, lexpr, pstate->p_last_srf,
a->location);
}
else
{
ereport(ERROR,
(errcode(ERRCODE_DATATYPE_MISMATCH),
errmsg("CypherList is expected but %s",
format_type_be(rtype)),
parser_errposition(pstate, exprLocation(a->rexpr))));
}
break;
}
}

/*
Expand Down Expand Up @@ -1979,6 +2000,12 @@ transformAExprIn(ParseState *pstate, A_Expr *a)
a->location);
}

/*
* Handle empty list case: value IN [] is always FALSE
*/
if (result == NULL)
result = (Node *) makeBoolConst(false, false);

return result;
}

Expand Down
97 changes: 97 additions & 0 deletions src/test/regress/expected/cypher_expr.out
Original file line number Diff line number Diff line change
Expand Up @@ -936,6 +936,103 @@ EXPLAIN VERBOSE MATCH (n:tc) return n.s::tsvector as n;
Output: (n.properties.'s'::text)::tsvector
(2 rows)

-- AGV2-437
CREATE GRAPH agv2_437;
SET graph_path = agv2_437;
CREATE (:item {id: '1', tags: '1,2,3', name: 'Alice'});
CREATE (:item {id: '2', tags: '4,5,6', name: 'Bob'});
CREATE (:item {id: '3', tags: '1,5,9', name: 'Charlie'});
CREATE (:item)-[:KNOWS]->(:item);
CREATE (:item)-[:LIKES]->(:item);
MATCH (n:item) WHERE n.id IN split(n.tags, ',') RETURN n.id;
id
-----
"1"
(1 row)

MATCH (n:item) WHERE '1' IN split(n.tags, ',') RETURN n.id;
id
-----
"1"
"3"
(2 rows)

MATCH (n:item) WHERE '5' IN split(n.tags, ',') RETURN n.id;
id
-----
"2"
"3"
(2 rows)

RETURN 1 IN split('1,2,3', ',');
?column?
----------
f
(1 row)

RETURN '1' IN split('1,2,3', ',');
?column?
----------
t
(1 row)

RETURN 'x' IN split('a,b,c', ',');
?column?
----------
f
(1 row)

MATCH (n:item) WHERE n.id IN ['1', '2'] RETURN n.id;
id
-----
"1"
"2"
(2 rows)

MATCH (n:item) WHERE n.name IN ['Alice', 'Bob'] RETURN n.name;
name
---------
"Alice"
"Bob"
(2 rows)

MATCH (n:item) WHERE toLower(n.name) IN ['alice', 'charlie'] RETURN n.name;
name
-----------
"Alice"
"Charlie"
(2 rows)

MATCH ()-[r]->() WHERE type(r) IN ['KNOWS', 'LIKES'] RETURN type(r);
type
------
(0 rows)

MATCH ()-[r]->() WHERE type(r) IN ['KNOWS'] RETURN type(r);
type
------
(0 rows)

RETURN 1 IN [];
?column?
----------
f
(1 row)

RETURN 'a' IN [];
?column?
----------
f
(1 row)

DROP GRAPH agv2_437 CASCADE;
NOTICE: drop cascades to 6 other objects
DETAIL: drop cascades to sequence agv2_437.ag_label_seq
drop cascades to vlabel ag_vertex
drop cascades to elabel ag_edge
drop cascades to vlabel item
drop cascades to elabel knows
drop cascades to elabel likes
-- Tear down
DROP TABLE t1;
DROP GRAPH test_cypher_expr CASCADE;
Expand Down
30 changes: 30 additions & 0 deletions src/test/regress/sql/cypher_expr.sql
Original file line number Diff line number Diff line change
Expand Up @@ -352,6 +352,36 @@ EXPLAIN VERBOSE MATCH (n:tc) RETURN n::jsonb::json as n;
EXPLAIN RETURN '08:00:2b:01:02:03'::macaddr as n;
EXPLAIN VERBOSE MATCH (n:tc) return n.s::tsvector as n;

-- AGV2-437
CREATE GRAPH agv2_437;
SET graph_path = agv2_437;

CREATE (:item {id: '1', tags: '1,2,3', name: 'Alice'});
CREATE (:item {id: '2', tags: '4,5,6', name: 'Bob'});
CREATE (:item {id: '3', tags: '1,5,9', name: 'Charlie'});
CREATE (:item)-[:KNOWS]->(:item);
CREATE (:item)-[:LIKES]->(:item);

MATCH (n:item) WHERE n.id IN split(n.tags, ',') RETURN n.id;
MATCH (n:item) WHERE '1' IN split(n.tags, ',') RETURN n.id;
MATCH (n:item) WHERE '5' IN split(n.tags, ',') RETURN n.id;

RETURN 1 IN split('1,2,3', ',');
RETURN '1' IN split('1,2,3', ',');
RETURN 'x' IN split('a,b,c', ',');

MATCH (n:item) WHERE n.id IN ['1', '2'] RETURN n.id;
MATCH (n:item) WHERE n.name IN ['Alice', 'Bob'] RETURN n.name;
MATCH (n:item) WHERE toLower(n.name) IN ['alice', 'charlie'] RETURN n.name;

MATCH ()-[r]->() WHERE type(r) IN ['KNOWS', 'LIKES'] RETURN type(r);
MATCH ()-[r]->() WHERE type(r) IN ['KNOWS'] RETURN type(r);

RETURN 1 IN [];
RETURN 'a' IN [];

DROP GRAPH agv2_437 CASCADE;

-- Tear down
DROP TABLE t1;
DROP GRAPH test_cypher_expr CASCADE;