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
5 changes: 3 additions & 2 deletions Makefile
Original file line number Diff line number Diff line change
Expand Up @@ -69,7 +69,8 @@ OBJS = src/backend/age.o \
src/backend/utils/load/ag_load_edges.o \
src/backend/utils/load/age_load.o \
src/backend/utils/load/libcsv.o \
src/backend/utils/name_validation.o
src/backend/utils/name_validation.o \
src/backend/utils/ag_guc.o

EXTENSION = age

Expand Down Expand Up @@ -105,7 +106,7 @@ REGRESS = scan \
srcdir=`pwd`

ag_regress_dir = $(srcdir)/regress
REGRESS_OPTS = --load-extension=age --inputdir=$(ag_regress_dir) --outputdir=$(ag_regress_dir) --temp-instance=$(ag_regress_dir)/instance --port=61958 --encoding=UTF-8
REGRESS_OPTS = --load-extension=age --inputdir=$(ag_regress_dir) --outputdir=$(ag_regress_dir) --temp-instance=$(ag_regress_dir)/instance --port=61958 --encoding=UTF-8 --temp-config $(ag_regress_dir)/age_regression.conf

ag_regress_out = instance/ log/ results/ regression.*
EXTRA_CLEAN = $(addprefix $(ag_regress_dir)/, $(ag_regress_out)) src/backend/parser/cypher_gram.c src/include/parser/cypher_gram_def.h src/include/parser/cypher_kwlist_d.h
Expand Down
1 change: 1 addition & 0 deletions regress/age_regression.conf
Original file line number Diff line number Diff line change
@@ -0,0 +1 @@
#age.enable_containment = on
175 changes: 175 additions & 0 deletions regress/expected/cypher_match.out
Original file line number Diff line number Diff line change
Expand Up @@ -2419,6 +2419,170 @@ SELECT * FROM cypher('cypher_match', $$ MATCH p=(x:r)-[]->(x:R) RETURN p, x $$)
ERROR: multiple labels for variable 'x' are not supported
LINE 1: ...FROM cypher('cypher_match', $$ MATCH p=(x:r)-[]->(x:R) RETUR...
^
--
-- Test age.enable_containment configuration parameter
--
-- Test queries are run before and after switching off this parameter.
-- When on, the containment operator should be used to filter properties.
-- When off, the access operator should be used.
--
SELECT create_graph('test_enable_containment');
NOTICE: graph "test_enable_containment" has been created
create_graph
--------------

(1 row)

SELECT * FROM cypher('test_enable_containment',
$$
CREATE (x:Customer {
name: 'Bob',
school: {
name: 'XYZ College',
program: {
major: 'Psyc',
degree: 'BSc'
}
},
phone: [ 123456789, 987654321, 456987123 ],
addr: [
{city: 'Vancouver', street: 30},
{city: 'Toronto', street: 40}
]
})
RETURN x
$$) as (a agtype);
a
-----------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
{"id": 844424930131969, "label": "Customer", "properties": {"addr": [{"city": "Vancouver", "street": 30}, {"city": "Toronto", "street": 40}], "name": "Bob", "phone": [123456789, 987654321, 456987123], "school": {"name": "XYZ College", "program": {"major": "Psyc", "degree": "BSc"}}}}::vertex
(1 row)

-- With enable_containment on
SET age.enable_containment = on;
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}]}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}, {city: 'Vancouver'}]}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Alberta'}]}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Psyc'}}}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'BSc'}}}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Cs'}}}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'PHd'}}}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[987654321]}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[654765876]}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT * FROM cypher('test_enable_containment', $$ EXPLAIN (COSTS OFF) MATCH (x:Customer {school:{name:'XYZ',program:{degree:'BSc'}},phone:[987654321],parents:{}}) RETURN x $$) as (a agtype);
QUERY PLAN
------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on "Customer" x
Filter: (properties @> '{"phone": [987654321], "school": {"name": "XYZ", "program": {"degree": "BSc"}}, "parents": {}}'::agtype)
(2 rows)

-- Previous set of queries, with enable_containment off
SET age.enable_containment = off;
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}]}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}, {city: 'Vancouver'}]}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Alberta'}]}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Psyc'}}}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'BSc'}}}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Cs'}}}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'PHd'}}}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[987654321]}) RETURN x $$) as (a agtype);
count
-------
1
(1 row)

SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[654765876]}) RETURN x $$) as (a agtype);
count
-------
0
(1 row)

SELECT * FROM cypher('test_enable_containment', $$ EXPLAIN (COSTS OFF) MATCH (x:Customer {school:{name:'XYZ',program:{degree:'BSc'}},phone:[987654321],parents:{}}) RETURN x $$) as (a agtype);
QUERY PLAN
---------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
Seq Scan on "Customer" x
Filter: ((agtype_access_operator(VARIADIC ARRAY[properties, '"school"'::agtype, '"name"'::agtype]) = '"XYZ"'::agtype) AND (agtype_access_operator(VARIADIC ARRAY[properties, '"school"'::agtype, '"program"'::agtype, '"degree"'::agtype]) = '"BSc"'::agtype) AND (agtype_access_operator(VARIADIC ARRAY[properties, '"phone"'::agtype]) @> '[987654321]'::agtype) AND (agtype_access_operator(VARIADIC ARRAY[properties, '"parents"'::agtype]) @> '{}'::agtype))
(2 rows)

--
-- Clean up
--
Expand Down Expand Up @@ -2460,6 +2624,17 @@ NOTICE: graph "test_retrieve_var" has been dropped

(1 row)

SELECT drop_graph('test_enable_containment', true);
NOTICE: drop cascades to 3 other objects
DETAIL: drop cascades to table test_enable_containment._ag_label_vertex
drop cascades to table test_enable_containment._ag_label_edge
drop cascades to table test_enable_containment."Customer"
NOTICE: graph "test_enable_containment" has been dropped
drop_graph
------------

(1 row)

--
-- End
--
56 changes: 56 additions & 0 deletions regress/sql/cypher_match.sql
Original file line number Diff line number Diff line change
Expand Up @@ -1077,11 +1077,67 @@ SELECT * FROM cypher('cypher_match', $$ CREATE () WITH * MATCH (x{n0:x.n1}) RETU
SELECT * FROM cypher('cypher_match', $$ MATCH p=(x)-[]->(x:R) RETURN p, x $$) AS (p agtype, x agtype);
SELECT * FROM cypher('cypher_match', $$ MATCH p=(x:r)-[]->(x:R) RETURN p, x $$) AS (p agtype, x agtype);

--
-- Test age.enable_containment configuration parameter
--
-- Test queries are run before and after switching off this parameter.
-- When on, the containment operator should be used to filter properties.
-- When off, the access operator should be used.
--

SELECT create_graph('test_enable_containment');
SELECT * FROM cypher('test_enable_containment',
$$
CREATE (x:Customer {
name: 'Bob',
school: {
name: 'XYZ College',
program: {
major: 'Psyc',
degree: 'BSc'
}
},
phone: [ 123456789, 987654321, 456987123 ],
addr: [
{city: 'Vancouver', street: 30},
{city: 'Toronto', street: 40}
]
})
RETURN x
$$) as (a agtype);

-- With enable_containment on
SET age.enable_containment = on;
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}, {city: 'Vancouver'}]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Alberta'}]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Psyc'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'BSc'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Cs'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'PHd'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[987654321]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[654765876]}) RETURN x $$) as (a agtype);
SELECT * FROM cypher('test_enable_containment', $$ EXPLAIN (COSTS OFF) MATCH (x:Customer {school:{name:'XYZ',program:{degree:'BSc'}},phone:[987654321],parents:{}}) RETURN x $$) as (a agtype);

-- Previous set of queries, with enable_containment off
SET age.enable_containment = off;
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Toronto'}, {city: 'Vancouver'}]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {addr:[{city:'Alberta'}]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Psyc'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'BSc'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {school:{program:{major:'Cs'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {name:'Bob',school:{program:{degree:'PHd'}}}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[987654321]}) RETURN x $$) as (a agtype);
SELECT count(*) FROM cypher('test_enable_containment', $$ MATCH (x:Customer {phone:[654765876]}) RETURN x $$) as (a agtype);
SELECT * FROM cypher('test_enable_containment', $$ EXPLAIN (COSTS OFF) MATCH (x:Customer {school:{name:'XYZ',program:{degree:'BSc'}},phone:[987654321],parents:{}}) RETURN x $$) as (a agtype);

--
-- Clean up
--
SELECT drop_graph('cypher_match', true);
SELECT drop_graph('test_retrieve_var', true);
SELECT drop_graph('test_enable_containment', true);

--
-- End
Expand Down
2 changes: 2 additions & 0 deletions src/backend/age.c
Original file line number Diff line number Diff line change
Expand Up @@ -25,6 +25,7 @@
#include "nodes/ag_nodes.h"
#include "optimizer/cypher_paths.h"
#include "parser/cypher_analyze.h"
#include "utils/ag_guc.h"

PG_MODULE_MAGIC;

Expand All @@ -37,6 +38,7 @@ void _PG_init(void)
object_access_hook_init();
process_utility_hook_init();
post_parse_analyze_init();
define_config_params();
}

void _PG_fini(void);
Expand Down
Loading