You are viewing a plain text version of this content. The canonical link for it is here.
Posted to commits@age.apache.org by jo...@apache.org on 2020/10/03 00:53:50 UTC

[incubator-age] branch master updated: Support for Agtype BTree and Hash Indices and Distinct Clause

This is an automated email from the ASF dual-hosted git repository.

joshinnis pushed a commit to branch master
in repository https://gitbox.apache.org/repos/asf/incubator-age.git


The following commit(s) were added to refs/heads/master by this push:
     new 91d4525  Support for Agtype BTree and Hash Indices and Distinct Clause
91d4525 is described below

commit 91d4525edaa42492b2542c200a949f25b4883b71
Author: Josh Innis <jo...@gmail.com>
AuthorDate: Tue Sep 29 13:35:24 2020 -0700

    Support for Agtype BTree and Hash Indices and Distinct Clause
    
    Also fixed a type casting issue with the MATCH clause
---
 age--0.2.0.sql                      |  32 ++++
 regress/expected/agtype.out         | 308 +++++++++++++++++++++++++++++++++++-
 regress/expected/cypher_match.out   |  53 ++++++-
 regress/sql/agtype.sql              |  92 ++++++++++-
 regress/sql/cypher_match.sql        |  28 ++++
 src/backend/parser/cypher_clause.c  |  11 +-
 src/backend/utils/adt/agtype.c      |  70 +++++++-
 src/backend/utils/adt/agtype_util.c |  59 +++++--
 src/include/utils/agtype.h          |   5 +
 9 files changed, 639 insertions(+), 19 deletions(-)

diff --git a/age--0.2.0.sql b/age--0.2.0.sql
index a91615d..92c9ae3 100644
--- a/age--0.2.0.sql
+++ b/age--0.2.0.sql
@@ -557,6 +557,38 @@ CREATE OPERATOR >= (
   JOIN = scalargejoinsel
 );
 
+CREATE FUNCTION agtype_btree_cmp(agtype, agtype)
+RETURNS INTEGER
+LANGUAGE c
+STABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE OPERATOR CLASS agtype_ops_btree
+  DEFAULT
+  FOR TYPE agtype
+  USING btree AS
+  OPERATOR 1 <,
+  OPERATOR 2 <=,
+  OPERATOR 3 =,
+  OPERATOR 4 >,
+  OPERATOR 5 >=,
+  FUNCTION 1 agtype_btree_cmp(agtype, agtype);
+
+CREATE FUNCTION agtype_hash_cmp(agtype)
+RETURNS INTEGER
+LANGUAGE c
+STABLE
+PARALLEL SAFE
+AS 'MODULE_PATHNAME';
+
+CREATE OPERATOR CLASS agtype_ops_hash
+  DEFAULT
+  FOR TYPE agtype
+  USING hash AS
+  OPERATOR 1 =,
+  FUNCTION 1 agtype_hash_cmp(agtype);
+
 --
 -- graph id conversion function
 --
diff --git a/regress/expected/agtype.out b/regress/expected/agtype.out
index 40879d6..ddb3bc9 100644
--- a/regress/expected/agtype.out
+++ b/regress/expected/agtype.out
@@ -1231,7 +1231,7 @@ SELECT agtype_access_operator(
 
 --Edge in a list
 SELECT agtype_build_list(
-	_agtype_build_edge('1'::graphid, '2'::graphid, '3'::graphid, 
+	_agtype_build_edge('1'::graphid, '2'::graphid, '3'::graphid,
 			   $$label_name$$, agtype_build_map()),
 	_agtype_build_edge('2'::graphid, '2'::graphid, '3'::graphid,
 			   $$label_name$$, agtype_build_map()));
@@ -1432,6 +1432,312 @@ SELECT agtype_string_match_contains('"abcdefghijklmnopqrstuvwxyz"', '"hijl"');
  false
 (1 row)
 
+--Agtype Hash Comparison Function
+SELECT agtype_hash_cmp(NULL);
+ agtype_hash_cmp 
+-----------------
+               0
+(1 row)
+
+SELECT agtype_hash_cmp('1'::agtype);
+ agtype_hash_cmp 
+-----------------
+      -123017199
+(1 row)
+
+SELECT agtype_hash_cmp('1.0'::agtype);
+ agtype_hash_cmp 
+-----------------
+       614780178
+(1 row)
+
+SELECT agtype_hash_cmp('"1"'::agtype);
+ agtype_hash_cmp 
+-----------------
+      -888576106
+(1 row)
+
+SELECT agtype_hash_cmp('[1]'::agtype);
+ agtype_hash_cmp 
+-----------------
+       434414509
+(1 row)
+
+SELECT agtype_hash_cmp('[1, 1]'::agtype);
+ agtype_hash_cmp 
+-----------------
+     -1551022880
+(1 row)
+
+SELECT agtype_hash_cmp('[1, 1, 1]'::agtype);
+ agtype_hash_cmp 
+-----------------
+        -3900769
+(1 row)
+
+SELECT agtype_hash_cmp('[1, 1, 1, 1]'::agtype);
+ agtype_hash_cmp 
+-----------------
+      1756986519
+(1 row)
+
+SELECT agtype_hash_cmp('[1, 1, 1, 1, 1]'::agtype);
+ agtype_hash_cmp 
+-----------------
+       -47741579
+(1 row)
+
+SELECT agtype_hash_cmp('[[1]]'::agtype);
+ agtype_hash_cmp 
+-----------------
+       878744030
+(1 row)
+
+SELECT agtype_hash_cmp('[[1, 1]]'::agtype);
+ agtype_hash_cmp 
+-----------------
+     -1254522284
+(1 row)
+
+SELECT agtype_hash_cmp('[[1], 1]'::agtype);
+ agtype_hash_cmp 
+-----------------
+        -1005036
+(1 row)
+
+SELECT agtype_hash_cmp('[1543872]'::agtype);
+ agtype_hash_cmp 
+-----------------
+     -1925093371
+(1 row)
+
+SELECT agtype_hash_cmp('[1, "abcde", 2.0]'::agtype);
+ agtype_hash_cmp 
+-----------------
+     -1128310748
+(1 row)
+
+SELECT agtype_hash_cmp(agtype_in('null'));
+ agtype_hash_cmp 
+-----------------
+      -505290271
+(1 row)
+
+SELECT agtype_hash_cmp(agtype_in('[null]'));
+ agtype_hash_cmp 
+-----------------
+       505290241
+(1 row)
+
+SELECT agtype_hash_cmp(agtype_in('[null, null]'));
+ agtype_hash_cmp 
+-----------------
+               3
+(1 row)
+
+SELECT agtype_hash_cmp(agtype_in('[null, null, null]'));
+ agtype_hash_cmp 
+-----------------
+      2021160967
+(1 row)
+
+SELECT agtype_hash_cmp(agtype_in('[null, null, null, null]'));
+ agtype_hash_cmp 
+-----------------
+              15
+(1 row)
+
+SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]'));
+ agtype_hash_cmp 
+-----------------
+      -505290721
+(1 row)
+
+SELECT agtype_hash_cmp('{"id":1, "label":"test", "properties":{"id":100}}'::agtype);
+ agtype_hash_cmp 
+-----------------
+      1116453668
+(1 row)
+
+SELECT agtype_hash_cmp('{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype);
+ agtype_hash_cmp 
+-----------------
+      1848106598
+(1 row)
+
+SELECT agtype_hash_cmp('{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}'::agtype);
+ agtype_hash_cmp 
+-----------------
+      1064722414
+(1 row)
+
+SELECT agtype_hash_cmp('{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge'::agtype);
+ agtype_hash_cmp 
+-----------------
+     -1790838958
+(1 row)
+
+SELECT agtype_hash_cmp('
+	[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	 {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	 {"id":5, "label":"vlabel", "properties":{}}::vertex]'::agtype);
+ agtype_hash_cmp 
+-----------------
+      -231467898
+(1 row)
+
+SELECT agtype_hash_cmp('
+	[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	 {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	 {"id":5, "label":"vlabel", "properties":{}}::vertex]::path'::agtype);
+ agtype_hash_cmp 
+-----------------
+       843330291
+(1 row)
+
+--Agtype BTree Comparison Function
+SELECT agtype_btree_cmp('1'::agtype, '1'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp('1'::agtype, '1.0'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp('1'::agtype, '"1"'::agtype);
+ agtype_btree_cmp 
+------------------
+                1
+(1 row)
+
+SELECT agtype_btree_cmp('"string"'::agtype, '"string"'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp('"string"'::agtype, '"string "'::agtype);
+ agtype_btree_cmp 
+------------------
+               -1
+(1 row)
+
+SELECT agtype_btree_cmp(NULL, NULL);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(NULL, '1'::agtype);
+ agtype_btree_cmp 
+------------------
+                1
+(1 row)
+
+SELECT agtype_btree_cmp('1'::agtype, NULL);
+ agtype_btree_cmp 
+------------------
+               -1
+(1 row)
+
+SELECT agtype_btree_cmp(agtype_in('null'), NULL);
+ agtype_btree_cmp 
+------------------
+               -1
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'1'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype);
+ agtype_btree_cmp 
+------------------
+                1
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":100}}'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":200}}'::agtype);
+ agtype_btree_cmp 
+------------------
+               -1
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":200}}::vertex'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge'::agtype,
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{"prop1": 1}}::edge'::agtype,
+	'{"id":2, "start_id":4, "end_id": 5, "label":"elabel", "properties":{"prop2": 2}}::edge'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{"prop1": 1}}::edge'::agtype,
+	'{"id":8, "start_id":4, "end_id": 5, "label":"elabel", "properties":{"prop2": 2}}::edge'::agtype);
+ agtype_btree_cmp 
+------------------
+               -1
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":3, "label":"vlabel", "properties":{}}::vertex]::path'::agtype,
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":3, "label":"vlabel", "properties":{}}::vertex]::path'::agtype);
+ agtype_btree_cmp 
+------------------
+                0
+(1 row)
+
+SELECT agtype_btree_cmp(
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":3, "label":"vlabel", "properties":{}}::vertex]::path'::agtype,
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":4, "label":"vlabel", "properties":{}}::vertex]::path'::agtype);
+ agtype_btree_cmp 
+------------------
+               -1
+(1 row)
+
 --
 -- Cleanup
 --
diff --git a/regress/expected/cypher_match.out b/regress/expected/cypher_match.out
index e7587d1..82c0cc3 100644
--- a/regress/expected/cypher_match.out
+++ b/regress/expected/cypher_match.out
@@ -765,10 +765,58 @@ ERROR:  syntax error at or near ")"
 LINE 2:  $$MATCH (u) WHERE EXISTS(u) RETURN u$$)
                                    ^
 --
+--Distinct
+--
+SELECT * FROM cypher('cypher_match', $$
+	MATCH (u)
+	RETURN DISTINCT u.id
+$$) AS (i agtype);
+     i     
+-----------
+ 
+ "end"
+ "initial"
+ "middle"
+(4 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+	CREATE (u:duplicate)-[:dup_edge {id:1 }]->(:other_v)
+$$) AS (a agtype);
+ a 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+	MATCH (u:duplicate)
+	CREATE (u)-[:dup_edge {id:2 }]->(:other_v)
+$$) AS (a agtype);
+ a 
+---
+(0 rows)
+
+SELECT * FROM cypher('cypher_match', $$
+	MATCH (u:duplicate)-[]-(:other_v)
+	RETURN DISTINCT u
+$$) AS (i agtype);
+ERROR:  function ag_catalog.agtygpe_to_grapghid(agtype) does not exist
+LINE 1: SELECT * FROM cypher('cypher_match', $$
+                                              ^
+HINT:  No function matches the given name and argument types. You might need to add explicit type casts.
+SELECT * FROM cypher('cypher_match', $$
+	MATCH p=(:duplicate)-[]-(:other_v)
+	RETURN DISTINCT p
+$$) AS (i agtype);
+                                                                                                                                                i                                                                                                                                                 
+--------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------
+ [{"id": 3377699720527873, "label": "duplicate", "properties": {}}::vertex, {"id": 3659174697238529, "label": "dup_edge", "end_id": 3940649673949185, "start_id": 3377699720527873, "properties": {"id": 1}}::edge, {"id": 3940649673949185, "label": "other_v", "properties": {}}::vertex]::path
+ [{"id": 3377699720527873, "label": "duplicate", "properties": {}}::vertex, {"id": 3659174697238530, "label": "dup_edge", "end_id": 3940649673949186, "start_id": 3377699720527873, "properties": {"id": 2}}::edge, {"id": 3940649673949186, "label": "other_v", "properties": {}}::vertex]::path
+(2 rows)
+
+--
 -- Clean up
 --
 SELECT drop_graph('cypher_match', true);
-NOTICE:  drop cascades to 11 other objects
+NOTICE:  drop cascades to 14 other objects
 DETAIL:  drop cascades to table cypher_match._ag_label_vertex
 drop cascades to table cypher_match._ag_label_edge
 drop cascades to table cypher_match.v
@@ -780,6 +828,9 @@ drop cascades to table cypher_match.v3
 drop cascades to table cypher_match.e3
 drop cascades to table cypher_match.loop
 drop cascades to table cypher_match.self
+drop cascades to table cypher_match.duplicate
+drop cascades to table cypher_match.dup_edge
+drop cascades to table cypher_match.other_v
 NOTICE:  graph "cypher_match" has been dropped
  drop_graph 
 ------------
diff --git a/regress/sql/agtype.sql b/regress/sql/agtype.sql
index 41ed7b9..821a68d 100644
--- a/regress/sql/agtype.sql
+++ b/regress/sql/agtype.sql
@@ -412,7 +412,7 @@ SELECT agtype_access_operator(
 
 --Edge in a list
 SELECT agtype_build_list(
-	_agtype_build_edge('1'::graphid, '2'::graphid, '3'::graphid, 
+	_agtype_build_edge('1'::graphid, '2'::graphid, '3'::graphid,
 			   $$label_name$$, agtype_build_map()),
 	_agtype_build_edge('2'::graphid, '2'::graphid, '3'::graphid,
 			   $$label_name$$, agtype_build_map()));
@@ -515,6 +515,96 @@ SELECT agtype_string_match_starts_with('"abcdefghijklmnopqrstuvwxyz"', '"bcde"')
 SELECT agtype_string_match_ends_with('"abcdefghijklmnopqrstuvwxyz"', '"vwxy"');
 SELECT agtype_string_match_contains('"abcdefghijklmnopqrstuvwxyz"', '"hijl"');
 
+--Agtype Hash Comparison Function
+SELECT agtype_hash_cmp(NULL);
+SELECT agtype_hash_cmp('1'::agtype);
+SELECT agtype_hash_cmp('1.0'::agtype);
+SELECT agtype_hash_cmp('"1"'::agtype);
+SELECT agtype_hash_cmp('[1]'::agtype);
+SELECT agtype_hash_cmp('[1, 1]'::agtype);
+SELECT agtype_hash_cmp('[1, 1, 1]'::agtype);
+SELECT agtype_hash_cmp('[1, 1, 1, 1]'::agtype);
+SELECT agtype_hash_cmp('[1, 1, 1, 1, 1]'::agtype);
+SELECT agtype_hash_cmp('[[1]]'::agtype);
+SELECT agtype_hash_cmp('[[1, 1]]'::agtype);
+SELECT agtype_hash_cmp('[[1], 1]'::agtype);
+SELECT agtype_hash_cmp('[1543872]'::agtype);
+SELECT agtype_hash_cmp('[1, "abcde", 2.0]'::agtype);
+SELECT agtype_hash_cmp(agtype_in('null'));
+SELECT agtype_hash_cmp(agtype_in('[null]'));
+SELECT agtype_hash_cmp(agtype_in('[null, null]'));
+SELECT agtype_hash_cmp(agtype_in('[null, null, null]'));
+SELECT agtype_hash_cmp(agtype_in('[null, null, null, null]'));
+SELECT agtype_hash_cmp(agtype_in('[null, null, null, null, null]'));
+SELECT agtype_hash_cmp('{"id":1, "label":"test", "properties":{"id":100}}'::agtype);
+SELECT agtype_hash_cmp('{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype);
+
+SELECT agtype_hash_cmp('{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}'::agtype);
+SELECT agtype_hash_cmp('{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge'::agtype);
+
+SELECT agtype_hash_cmp('
+	[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	 {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	 {"id":5, "label":"vlabel", "properties":{}}::vertex]'::agtype);
+
+SELECT agtype_hash_cmp('
+	[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	 {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	 {"id":5, "label":"vlabel", "properties":{}}::vertex]::path'::agtype);
+
+--Agtype BTree Comparison Function
+SELECT agtype_btree_cmp('1'::agtype, '1'::agtype);
+SELECT agtype_btree_cmp('1'::agtype, '1.0'::agtype);
+SELECT agtype_btree_cmp('1'::agtype, '"1"'::agtype);
+
+SELECT agtype_btree_cmp('"string"'::agtype, '"string"'::agtype);
+SELECT agtype_btree_cmp('"string"'::agtype, '"string "'::agtype);
+
+SELECT agtype_btree_cmp(NULL, NULL);
+SELECT agtype_btree_cmp(NULL, '1'::agtype);
+SELECT agtype_btree_cmp('1'::agtype, NULL);
+SELECT agtype_btree_cmp(agtype_in('null'), NULL);
+
+SELECT agtype_btree_cmp(
+	'1'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":100}}'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":200}}'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":1, "label":"test", "properties":{"id":100}}::vertex'::agtype,
+	'{"id":1, "label":"test", "properties":{"id":200}}::vertex'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge'::agtype,
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{"prop1": 1}}::edge'::agtype,
+	'{"id":2, "start_id":4, "end_id": 5, "label":"elabel", "properties":{"prop2": 2}}::edge'::agtype);
+SELECT agtype_btree_cmp(
+	'{"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{"prop1": 1}}::edge'::agtype,
+	'{"id":8, "start_id":4, "end_id": 5, "label":"elabel", "properties":{"prop2": 2}}::edge'::agtype);
+
+SELECT agtype_btree_cmp(
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":3, "label":"vlabel", "properties":{}}::vertex]::path'::agtype,
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":3, "label":"vlabel", "properties":{}}::vertex]::path'::agtype);
+
+SELECT agtype_btree_cmp(
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":3, "label":"vlabel", "properties":{}}::vertex]::path'::agtype,
+	'[{"id":1, "label":"test", "properties":{"id":100}}::vertex,
+	  {"id":2, "start_id":1, "end_id": 3, "label":"elabel", "properties":{}}::edge,
+	  {"id":4, "label":"vlabel", "properties":{}}::vertex]::path'::agtype);
 --
 -- Cleanup
 --
diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql
index 82da895..62334a9 100644
--- a/regress/sql/cypher_match.sql
+++ b/regress/sql/cypher_match.sql
@@ -401,6 +401,34 @@ SELECT * FROM cypher('cypher_match',
 AS (u agtype);
 
 --
+--Distinct
+--
+SELECT * FROM cypher('cypher_match', $$
+	MATCH (u)
+	RETURN DISTINCT u.id
+$$) AS (i agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+	CREATE (u:duplicate)-[:dup_edge {id:1 }]->(:other_v)
+$$) AS (a agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+	MATCH (u:duplicate)
+	CREATE (u)-[:dup_edge {id:2 }]->(:other_v)
+$$) AS (a agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+	MATCH (u:duplicate)-[]-(:other_v)
+	RETURN DISTINCT u
+$$) AS (i agtype);
+
+SELECT * FROM cypher('cypher_match', $$
+	MATCH p=(:duplicate)-[]-(:other_v)
+	RETURN DISTINCT p
+$$) AS (i agtype);
+
+
+--
 -- Clean up
 --
 
diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c
index f73a5e4..dc77bbc 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -35,6 +35,7 @@
 #include "parser/parse_target.h"
 #include "parser/parsetree.h"
 #include "rewrite/rewriteHandler.h"
+#include "utils/typcache.h"
 #include "utils/lsyscache.h"
 #include "utils/rel.h"
 
@@ -965,8 +966,8 @@ static A_Expr *filter_vertices_on_label_id(cypher_parsestate *cpstate,
     label_cache_data *lcd = search_label_name_graph_cache(label,
                                                           cpstate->graph_oid);
     A_Const *n;
-    FuncCall *fc;
-    Value *ag_catalog, *extract_label_id;
+    FuncCall *fc, *conversion_fc;
+    Value *ag_catalog, *extract_label_id, *agtype_to_graphid;
     int32 label_id = lcd->id;
 
     n = makeNode(A_Const);
@@ -976,9 +977,13 @@ static A_Expr *filter_vertices_on_label_id(cypher_parsestate *cpstate,
 
     ag_catalog = makeString("ag_catalog");
     extract_label_id = makeString("_extract_label_id");
+    agtype_to_graphid = makeString("agtygpe_to_grapghid");
+
+    conversion_fc = makeFuncCall(list_make2(ag_catalog, agtype_to_graphid),
+                                 list_make1(id_field), -1);
 
     fc = makeFuncCall(list_make2(ag_catalog, extract_label_id),
-                      list_make1(id_field), -1);
+                      list_make1(conversion_fc), -1);
 
     return makeSimpleA_Expr(AEXPR_OP, "=", (Node *)fc, (Node *)n, -1);
 }
diff --git a/src/backend/utils/adt/agtype.c b/src/backend/utils/adt/agtype.c
index 429b977..e04ae78 100644
--- a/src/backend/utils/adt/agtype.c
+++ b/src/backend/utils/adt/agtype.c
@@ -121,8 +121,6 @@ static bool is_agtype_null(agtype *agt);
 static agtype_value *string_to_agtype_value(char *s);
 static uint64 get_edge_uniqueness_value(Datum d, Oid type, bool is_null,
                                         int index);
-static agtype_value *get_agtype_value_object_value(agtype_value *agtv_object,
-                                             char *key);
 /* graph entity retrieval */
 static Datum get_vertex(const char *graph, const char *vertex_label,
                          int64 graphid);
@@ -2676,6 +2674,71 @@ static bool is_agtype_null(agtype *agt)
     return false;
 }
 
+#define LEFT_ROTATE(n, i) ((n << i) | (n >> (64 - i)))
+#define RIGHT_ROTATE(n, i)  ((n >> i) | (n << (64 - i)))
+
+//Hashing Function for Hash Indexes
+PG_FUNCTION_INFO_V1(agtype_hash_cmp);
+
+Datum agtype_hash_cmp(PG_FUNCTION_ARGS)
+{
+    uint64 hash = 0;
+    agtype *agt;
+    agtype_iterator *it;
+    agtype_iterator_token tok;
+    agtype_value *r;
+    uint64 seed = 0xF0F0F0F0;
+
+    if (PG_ARGISNULL(0))
+        PG_RETURN_INT16(0);
+
+    agt = AG_GET_ARG_AGTYPE_P(0);
+
+    r = palloc(sizeof(agtype_value));
+
+    it = agtype_iterator_init(&agt->root);
+    while ((tok = agtype_iterator_next(&it, r, false)) != WAGT_DONE)
+    {
+        if (IS_A_AGTYPE_SCALAR(r) && AGTYPE_ITERATOR_TOKEN_IS_HASHABLE(tok))
+            agtype_hash_scalar_value_extended(r, &hash, seed);
+        else if (tok == WAGT_BEGIN_ARRAY && !r->val.array.raw_scalar)
+            seed = LEFT_ROTATE(seed, 4);
+        else if (tok == WAGT_BEGIN_OBJECT)
+            seed = LEFT_ROTATE(seed, 6);
+        else if (tok == WAGT_END_ARRAY && !r->val.array.raw_scalar)
+            seed = RIGHT_ROTATE(seed, 4);
+        else if (tok == WAGT_END_OBJECT)
+            seed = RIGHT_ROTATE(seed, 4);
+
+        seed = LEFT_ROTATE(seed, 1);
+    }
+
+    PG_RETURN_INT16(hash);
+}
+
+// Comparision function for btree Indexes
+PG_FUNCTION_INFO_V1(agtype_btree_cmp);
+
+Datum agtype_btree_cmp(PG_FUNCTION_ARGS)
+{
+    agtype *agtype_lhs;
+    agtype *agtype_rhs;
+
+    if (PG_ARGISNULL(0) && PG_ARGISNULL(1))
+        PG_RETURN_INT16(0);
+    else if (PG_ARGISNULL(0))
+        PG_RETURN_INT16(1);
+    else if (PG_ARGISNULL(1))
+        PG_RETURN_INT16(-1);
+
+    agtype_lhs = AG_GET_ARG_AGTYPE_P(0);
+    agtype_rhs = AG_GET_ARG_AGTYPE_P(1);
+
+    PG_RETURN_INT16(compare_agtype_containers_orderability(&agtype_lhs->root,
+                                                     &agtype_rhs->root));
+}
+
+
 PG_FUNCTION_INFO_V1(agtype_typecast_numeric);
 /*
  * Execute function to typecast an agtype to an agtype numeric
@@ -3154,7 +3217,7 @@ Datum _ag_enforce_edge_uniqueness(PG_FUNCTION_ARGS)
 }
 
 /* helper function to retrieve a value, given a key, from an agtype_value */
-static agtype_value *get_agtype_value_object_value(agtype_value *agtv_object,
+agtype_value *get_agtype_value_object_value(const agtype_value *agtv_object,
                                              char *key)
 {
     int i;
@@ -3238,7 +3301,6 @@ Datum id(PG_FUNCTION_ARGS)
     Assert(agtv_result->type = AGTV_INTEGER);
 
     PG_RETURN_POINTER(agtype_value_to_agtype(agtv_result));
-    AG_RETURN_GRAPHID(agtv_result->val.int_value);
 }
 
 PG_FUNCTION_INFO_V1(start_id);
diff --git a/src/backend/utils/adt/agtype_util.c b/src/backend/utils/adt/agtype_util.c
index bf50265..2d32f52 100644
--- a/src/backend/utils/adt/agtype_util.c
+++ b/src/backend/utils/adt/agtype_util.c
@@ -272,6 +272,7 @@ int compare_agtype_containers_orderability(agtype_container *a,
                 case AGTV_FLOAT:
                 case AGTV_EDGE:
                 case AGTV_VERTEX:
+                case AGTV_PATH:
                     res = compare_agtype_scalar_values(&va, &vb);
                     break;
                 case AGTV_ARRAY:
@@ -304,8 +305,6 @@ int compare_agtype_containers_orderability(agtype_container *a,
                         }
                     }
                     break;
-                case AGTV_PATH:
-                    break;
                 case AGTV_OBJECT:
                     break;
                 case AGTV_BINARY:
@@ -1372,7 +1371,7 @@ void agtype_hash_scalar_value(const agtype_value *scalar_val, uint32 *hash)
 void agtype_hash_scalar_value_extended(const agtype_value *scalar_val,
                                        uint64 *hash, uint64 seed)
 {
-    uint64 tmp;
+    uint64 tmp = 0;
 
     switch (scalar_val->type)
     {
@@ -1414,17 +1413,30 @@ void agtype_hash_scalar_value_extended(const agtype_value *scalar_val,
     case AGTV_VERTEX:
     {
         graphid id;
-        id = scalar_val->val.object.pairs[0].value.val.int_value;
+        agtype_value *id_agt = get_agtype_value_object_value(scalar_val, "id");
+        id = id_agt->val.int_value;
         tmp = DatumGetUInt64(DirectFunctionCall2(
-            hashfloat8extended, Float8GetDatum(id), UInt64GetDatum(seed)));
+            hashint8extended, Float8GetDatum(id), UInt64GetDatum(seed)));
         break;
     }
     case AGTV_EDGE:
     {
         graphid id;
-        id = scalar_val->val.object.pairs[0].value.val.int_value;
+        agtype_value *id_agt = get_agtype_value_object_value(scalar_val, "id");
+        id = id_agt->val.int_value;
         tmp = DatumGetUInt64(DirectFunctionCall2(
-            hashfloat8extended, Float8GetDatum(id), UInt64GetDatum(seed)));
+            hashint8extended, Float8GetDatum(id), UInt64GetDatum(seed)));
+        break;
+    }
+    case AGTV_PATH:
+    {
+        int i;
+        for (i = 0; i < scalar_val->val.array.num_elems; i++)
+        {
+            agtype_value v;
+            v = scalar_val->val.array.elems[i];
+            agtype_hash_scalar_value_extended(&v, &tmp, seed);
+        }
         break;
     }
     default:
@@ -1562,10 +1574,16 @@ int compare_agtype_scalar_values(agtype_value *a, agtype_value *b)
             return compare_two_floats_orderability(a->val.float_value,
                                                    b->val.float_value);
         case AGTV_VERTEX:
+        case AGTV_EDGE:
         {
+            agtype_value *a_id, *b_id;
             graphid a_graphid, b_graphid;
-            a_graphid = a->val.object.pairs[0].value.val.int_value;
-            b_graphid = b->val.object.pairs[0].value.val.int_value;
+
+            a_id = get_agtype_value_object_value(a, "id");
+            b_id = get_agtype_value_object_value(b, "id");
+
+            a_graphid = a_id->val.int_value;
+            b_graphid = b_id->val.int_value;
 
             if (a_graphid == b_graphid)
                 return 0;
@@ -1574,6 +1592,29 @@ int compare_agtype_scalar_values(agtype_value *a, agtype_value *b)
             else
                 return -1;
         }
+        case AGTV_PATH:
+        {
+            int i;
+
+            if (a->val.array.num_elems != b->val.array.num_elems)
+                return  a->val.array.num_elems > b->val.array.num_elems ? 1 : -1;
+
+            for (i = 0; i < a->val.array.num_elems; i++)
+            {
+                agtype_value a_elem, b_elem;
+                int res;
+
+                a_elem = a->val.array.elems[i];
+                b_elem = b->val.array.elems[i];
+
+                res = compare_agtype_scalar_values(&a_elem, &b_elem);
+
+                if (res)
+                    return res;
+            }
+
+            return 0;
+        }
         default:
             ereport(ERROR, (errmsg("invalid agtype scalar type %d for compare",
                                    a->type)));
diff --git a/src/include/utils/agtype.h b/src/include/utils/agtype.h
index a6db4b8..0ec7fb8 100644
--- a/src/include/utils/agtype.h
+++ b/src/include/utils/agtype.h
@@ -45,6 +45,9 @@ typedef enum
     WAGT_END_OBJECT
 } agtype_iterator_token;
 
+#define AGTYPE_ITERATOR_TOKEN_IS_HASHABLE(x) \
+    (x > WAGT_DONE && x < WAGT_BEGIN_ARRAY)
+
 /* Strategy numbers for GIN index opclasses */
 #define AGTYPE_CONTAINS_STRATEGY_NUMBER 7
 #define AGTYPE_EXISTS_STRATEGY_NUMBER 9
@@ -442,6 +445,8 @@ Datum get_numeric_datum_from_agtype_value(agtype_value *agtv);
 bool is_numeric_result(agtype_value *lhs, agtype_value *rhs);
 
 /* agtype.c support functions */
+agtype_value *get_agtype_value_object_value(const agtype_value *agtv_object,
+                                            char *key);
 char *agtype_to_cstring(StringInfo out, agtype_container *in,
                         int estimated_len);
 char *agtype_to_cstring_indent(StringInfo out, agtype_container *in,