Skip to content
Merged
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
8 changes: 4 additions & 4 deletions age--1.2.0.sql
Original file line number Diff line number Diff line change
Expand Up @@ -4162,10 +4162,10 @@ IMMUTABLE
PARALLEL SAFE
AS 'MODULE_PATHNAME';

CREATE FUNCTION ag_catalog.age_unnest(agtype, block_types boolean = false)
RETURNS SETOF agtype
LANGUAGE c
IMMUTABLE
CREATE FUNCTION ag_catalog.age_unnest(agtype)
RETURNS SETOF agtype
LANGUAGE c
IMMUTABLE
PARALLEL SAFE
AS 'MODULE_PATHNAME';

Expand Down
155 changes: 141 additions & 14 deletions regress/expected/cypher_unwind.out
Original file line number Diff line number Diff line change
Expand Up @@ -25,25 +25,48 @@ NOTICE: graph "cypher_unwind" has been created

(1 row)

-- Create nodes and relations
SELECT * FROM cypher('cypher_unwind', $$
UNWIND [1, 2, 3] AS i RETURN i
CREATE (n {name: 'node1', a: [1, 2, 3]}),
(m {name: 'node2', a: [4, 5, 6]}),
(o {name: 'node3', a: [7, 8, 9]}),
(n)-[:KNOWS]->(m),
(m)-[:KNOWS]->(o)
$$) as (i agtype);
i
---
1
2
3
(0 rows)

SELECT * FROM cypher('cypher_unwind', $$
MATCH (n)
RETURN n
$$) as (i agtype);
i
-----------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [1, 2, 3], "name": "node1"}}::vertex
{"id": 281474976710658, "label": "", "properties": {"a": [4, 5, 6], "name": "node2"}}::vertex
{"id": 281474976710659, "label": "", "properties": {"a": [7, 8, 9], "name": "node3"}}::vertex
(3 rows)

--
-- Test UNWIND clause
--
SELECT * FROM cypher('cypher_unwind', $$
CREATE ({a: [1, 2, 3]}), ({a: [4, 5, 6]})
UNWIND [1, 2, 3] AS i
RETURN i
$$) as (i agtype);
i
---
(0 rows)
1
2
3
(3 rows)

SELECT * FROM cypher('cypher_unwind', $$
MATCH (n) WITH n.a AS a UNWIND a AS i RETURN *
MATCH (n)
WITH n.a AS a
UNWIND a AS i
RETURN *
$$) as (i agtype, j agtype);
i | j
-----------+---
Expand All @@ -53,7 +76,10 @@ $$) as (i agtype, j agtype);
[4, 5, 6] | 4
[4, 5, 6] | 5
[4, 5, 6] | 6
(6 rows)
[7, 8, 9] | 7
[7, 8, 9] | 8
[7, 8, 9] | 9
(9 rows)

SELECT * FROM cypher('cypher_unwind', $$
WITH [[1, 2], [3, 4], 5] AS nested
Expand All @@ -70,17 +96,118 @@ $$) as (i agtype);
5
(5 rows)

-- UNWIND vertices
SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND nodes(p) as node
RETURN node
$$) as (i agtype);
i
-----------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [1, 2, 3], "name": "node1"}}::vertex
{"id": 281474976710658, "label": "", "properties": {"a": [4, 5, 6], "name": "node2"}}::vertex
{"id": 281474976710658, "label": "", "properties": {"a": [4, 5, 6], "name": "node2"}}::vertex
{"id": 281474976710659, "label": "", "properties": {"a": [7, 8, 9], "name": "node3"}}::vertex
(4 rows)

SELECT * FROM cypher('cypher_unwind', $$
WITH [{id: 0, label:'', properties:{}}::vertex, {id: 1, label:'', properties:{}}::vertex] as n
UNWIND n as a
SET a.i = 1
RETURN a
MATCH p=(n)-[:KNOWS]->(m)
UNWIND nodes(p) as node
RETURN node.name
$$) as (i agtype);
ERROR: UNWIND clause does not support agtype vertex
i
---------
"node1"
"node2"
"node2"
"node3"
(4 rows)

-- UNWIND edges
SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND relationships(p) as relation
RETURN relation
$$) as (i agtype);
i
---------------------------------------------------------------------------------------------------------------------------
{"id": 844424930131969, "label": "KNOWS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge
{"id": 844424930131970, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge
(2 rows)

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND relationships(p) as relation
RETURN type(relation)
$$) as (i agtype);
i
---------
"KNOWS"
"KNOWS"
(2 rows)

-- UNWIND paths (vle)
SELECT * FROM cypher('cypher_unwind', $$
MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
UNWIND [p] as path
RETURN path
$$) as (i agtype);
i
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id": 281474976710657, "label": "_ag_label_vertex", "properties": {"a": [1, 2, 3], "name": "node1"}}::vertex, {"id": 844424930131969, "label": "KNOWS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 281474976710658, "label": "_ag_label_vertex", "properties": {"a": [4, 5, 6], "name": "node2"}}::vertex, {"id": 844424930131970, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge, {"id": 281474976710659, "label": "_ag_label_vertex", "properties": {"a": [7, 8, 9], "name": "node3"}}::vertex]::path
(1 row)

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
UNWIND [p] as path
RETURN relationships(path)
$$) as (i agtype);
i
--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
[{"id": 844424930131969, "label": "KNOWS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge, {"id": 844424930131970, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge]
(1 row)

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
UNWIND [p] as path
UNWIND relationships(path) as edge
RETURN edge
$$) as (i agtype);
i
---------------------------------------------------------------------------------------------------------------------------
{"id": 844424930131969, "label": "KNOWS", "end_id": 281474976710658, "start_id": 281474976710657, "properties": {}}::edge
{"id": 844424930131970, "label": "KNOWS", "end_id": 281474976710659, "start_id": 281474976710658, "properties": {}}::edge
(2 rows)

-- Unwind with SET clause
SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND nodes(p) as node
SET node.type = 'vertex'
$$) as (i agtype);
i
---
(0 rows)

SELECT * FROM cypher('cypher_unwind', $$
MATCH (n)
RETURN n
$$) as (i agtype);
i
-----------------------------------------------------------------------------------------------------------------
{"id": 281474976710657, "label": "", "properties": {"a": [1, 2, 3], "name": "node1", "type": "vertex"}}::vertex
{"id": 281474976710658, "label": "", "properties": {"a": [4, 5, 6], "name": "node2", "type": "vertex"}}::vertex
{"id": 281474976710659, "label": "", "properties": {"a": [7, 8, 9], "name": "node3", "type": "vertex"}}::vertex
(3 rows)

--
-- Clean up
--
SELECT drop_graph('cypher_unwind', true);
NOTICE: drop cascades to 2 other objects
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table cypher_unwind._ag_label_vertex
drop cascades to table cypher_unwind._ag_label_edge
drop cascades to table cypher_unwind."KNOWS"
NOTICE: graph "cypher_unwind" has been dropped
drop_graph
------------
Expand Down
92 changes: 85 additions & 7 deletions regress/sql/cypher_unwind.sql
Original file line number Diff line number Diff line change
Expand Up @@ -22,16 +22,35 @@ SET search_path TO ag_catalog;

SELECT create_graph('cypher_unwind');

-- Create nodes and relations

SELECT * FROM cypher('cypher_unwind', $$
UNWIND [1, 2, 3] AS i RETURN i
CREATE (n {name: 'node1', a: [1, 2, 3]}),
(m {name: 'node2', a: [4, 5, 6]}),
(o {name: 'node3', a: [7, 8, 9]}),
(n)-[:KNOWS]->(m),
(m)-[:KNOWS]->(o)
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
CREATE ({a: [1, 2, 3]}), ({a: [4, 5, 6]})
MATCH (n)
RETURN n
$$) as (i agtype);

--
-- Test UNWIND clause
--

SELECT * FROM cypher('cypher_unwind', $$
UNWIND [1, 2, 3] AS i
RETURN i
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
MATCH (n) WITH n.a AS a UNWIND a AS i RETURN *
MATCH (n)
WITH n.a AS a
UNWIND a AS i
RETURN *
$$) as (i agtype, j agtype);

SELECT * FROM cypher('cypher_unwind', $$
Expand All @@ -41,11 +60,70 @@ SELECT * FROM cypher('cypher_unwind', $$
RETURN y
$$) as (i agtype);

-- UNWIND vertices

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND nodes(p) as node
RETURN node
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND nodes(p) as node
RETURN node.name
$$) as (i agtype);

-- UNWIND edges

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND relationships(p) as relation
RETURN relation
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND relationships(p) as relation
RETURN type(relation)
$$) as (i agtype);

-- UNWIND paths (vle)

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
UNWIND [p] as path
RETURN path
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
UNWIND [p] as path
RETURN relationships(path)
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
WITH [{id: 0, label:'', properties:{}}::vertex, {id: 1, label:'', properties:{}}::vertex] as n
UNWIND n as a
SET a.i = 1
RETURN a
MATCH p=({name:'node1'})-[e:KNOWS*]->({name:'node3'})
UNWIND [p] as path
UNWIND relationships(path) as edge
RETURN edge
$$) as (i agtype);

-- Unwind with SET clause

SELECT * FROM cypher('cypher_unwind', $$
MATCH p=(n)-[:KNOWS]->(m)
UNWIND nodes(p) as node
SET node.type = 'vertex'
$$) as (i agtype);

SELECT * FROM cypher('cypher_unwind', $$
MATCH (n)
RETURN n
$$) as (i agtype);

--
-- Clean up
--

SELECT drop_graph('cypher_unwind', true);
2 changes: 1 addition & 1 deletion src/backend/parser/cypher_clause.c
Original file line number Diff line number Diff line change
Expand Up @@ -1331,7 +1331,7 @@ static Query *transform_cypher_unwind(cypher_parsestate *cpstate,
old_expr_kind = pstate->p_expr_kind;
pstate->p_expr_kind = EXPR_KIND_SELECT_TARGET;
funcexpr = ParseFuncOrColumn(pstate, unwind->funcname,
list_make2(expr, makeBoolConst(true, false)),
list_make1(expr),
pstate->p_last_srf, unwind, false,
target_syntax_loc);

Expand Down
14 changes: 1 addition & 13 deletions src/backend/utils/adt/agtype.c
Original file line number Diff line number Diff line change
Expand Up @@ -10031,14 +10031,11 @@ Datum age_range(PG_FUNCTION_ARGS)
PG_FUNCTION_INFO_V1(age_unnest);
/*
* Function to convert the Array type of Agtype into each row. It is used for
* Cypher `UNWIND` clause, but considering the situation in which the user can
* directly use this function in vanilla PGSQL, put a second parameter related
* to this.
* Cypher `UNWIND` clause.
*/
Datum age_unnest(PG_FUNCTION_ARGS)
{
agtype *agtype_arg = AG_GET_ARG_AGTYPE_P(0);
bool block_types = PG_GETARG_BOOL(1);
ReturnSetInfo *rsi;
Tuplestorestate *tuple_store;
TupleDesc tupdesc;
Expand Down Expand Up @@ -10090,15 +10087,6 @@ Datum age_unnest(PG_FUNCTION_ARGS)
bool nulls[1] = {false};
agtype *val = agtype_value_to_agtype(&v);

if (block_types && (
v.type == AGTV_VERTEX || v.type == AGTV_EDGE || v.type == AGTV_PATH))
{
ereport(ERROR,
(errcode(ERRCODE_INVALID_PARAMETER_VALUE),
errmsg("UNWIND clause does not support agtype %s",
agtype_value_type_to_string(v.type))));
}

/* use the tmp context so we can clean up after each tuple is done */
old_cxt = MemoryContextSwitchTo(tmp_cxt);

Expand Down