Add fast functions for checking edge uniqueness (#2227)

Added fast functions for checking edge uniqueness. This will help
improve performance for MATCH queries with paths longer than 3 but
less than 11. The normal edge uniqueness function will deal with
any path 11 and over.

    modified:   age--1.6.0--y.y.y.sql
    modified:   sql/agtype_graphid.sql
    modified:   src/backend/parser/cypher_clause.c
    modified:   src/backend/utils/adt/age_vle.c
diff --git a/age--1.6.0--y.y.y.sql b/age--1.6.0--y.y.y.sql
index d781be9..2d693a4 100644
--- a/age--1.6.0--y.y.y.sql
+++ b/age--1.6.0--y.y.y.sql
@@ -31,3 +31,23 @@
 --* file. We need to keep the order of these changes.
 --* REMOVE ALL LINES ABOVE, and this one, that start with --*
 
+CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness2(graphid, graphid)
+    RETURNS bool
+    LANGUAGE c
+    STABLE
+PARALLEL SAFE
+as 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness3(graphid, graphid, graphid)
+    RETURNS bool
+    LANGUAGE c
+    STABLE
+PARALLEL SAFE
+as 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness4(graphid, graphid, graphid, graphid)
+    RETURNS bool
+    LANGUAGE c
+    STABLE
+PARALLEL SAFE
+as 'MODULE_PATHNAME';
diff --git a/sql/agtype_graphid.sql b/sql/agtype_graphid.sql
index 4e05943..0887db8 100644
--- a/sql/agtype_graphid.sql
+++ b/sql/agtype_graphid.sql
@@ -77,6 +77,27 @@
 PARALLEL SAFE
 AS 'MODULE_PATHNAME';
 
+CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness2(graphid, graphid)
+    RETURNS bool
+    LANGUAGE c
+    STABLE
+PARALLEL SAFE
+as 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness3(graphid, graphid, graphid)
+    RETURNS bool
+    LANGUAGE c
+    STABLE
+PARALLEL SAFE
+as 'MODULE_PATHNAME';
+
+CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness4(graphid, graphid, graphid, graphid)
+    RETURNS bool
+    LANGUAGE c
+    STABLE
+PARALLEL SAFE
+as 'MODULE_PATHNAME';
+
 CREATE FUNCTION ag_catalog._ag_enforce_edge_uniqueness(VARIADIC "any")
     RETURNS bool
     LANGUAGE c
diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c
index 93e710a..468706a 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -3276,13 +3276,13 @@
 {
     List *edges = NIL;
     ListCell *lc;
-    List *qualified_function_name;
-    String *ag_catalog, *edge_fn;
+    List *qualified_function_name = NULL;
+    String *ag_catalog;
+    String *edge_fn = NULL;
+    bool is_vle_edge = false;
+    int nentities = list_length(entities);
 
     ag_catalog = makeString("ag_catalog");
-    edge_fn = makeString("_ag_enforce_edge_uniqueness");
-
-    qualified_function_name = list_make2(ag_catalog, edge_fn);
 
     /* iterate through each entity, collecting the access node for each edge */
     foreach (lc, entities)
@@ -3298,10 +3298,33 @@
         }
         else if (entity->type == ENT_VLE_EDGE)
         {
+            is_vle_edge = true;
             edges = lappend(edges, entity->expr);
         }
     }
 
+    if (!is_vle_edge && (nentities >= 5 && nentities <= 9))
+    {
+        if (nentities == 5)
+        {
+            edge_fn = makeString("_ag_enforce_edge_uniqueness2");
+        }
+        else if (nentities == 7)
+        {
+            edge_fn = makeString("_ag_enforce_edge_uniqueness3");
+        }
+        else
+        {
+            edge_fn = makeString("_ag_enforce_edge_uniqueness4");
+        }
+    }
+    else
+    {
+        edge_fn = makeString("_ag_enforce_edge_uniqueness");
+    }
+
+    qualified_function_name = list_make2(ag_catalog, edge_fn);
+
     return makeFuncCall(qualified_function_name, edges, COERCE_SQL_SYNTAX, -1);
 }
 
diff --git a/src/backend/utils/adt/age_vle.c b/src/backend/utils/adt/age_vle.c
index f0adab2..f9e4c70 100644
--- a/src/backend/utils/adt/age_vle.c
+++ b/src/backend/utils/adt/age_vle.c
@@ -2427,6 +2427,55 @@
     PG_RETURN_POINTER(agtype_value_to_agtype(result.res));
 }
 
+PG_FUNCTION_INFO_V1(_ag_enforce_edge_uniqueness2);
+
+Datum _ag_enforce_edge_uniqueness2(PG_FUNCTION_ARGS)
+{
+    graphid gid1 = AG_GETARG_GRAPHID(0);
+    graphid gid2 = AG_GETARG_GRAPHID(1);
+
+    if (gid1 == gid2)
+    {
+        PG_RETURN_BOOL(false);
+    }
+
+    PG_RETURN_BOOL(true);
+}
+
+PG_FUNCTION_INFO_V1(_ag_enforce_edge_uniqueness3);
+
+Datum _ag_enforce_edge_uniqueness3(PG_FUNCTION_ARGS)
+{
+    graphid gid1 = AG_GETARG_GRAPHID(0);
+    graphid gid2 = AG_GETARG_GRAPHID(1);
+    graphid gid3 = AG_GETARG_GRAPHID(2);
+
+    if (gid1 == gid2 || gid1 == gid3 || gid2 == gid3)
+    {
+        PG_RETURN_BOOL(false);
+    }
+
+    PG_RETURN_BOOL(true);
+}
+
+PG_FUNCTION_INFO_V1(_ag_enforce_edge_uniqueness4);
+
+Datum _ag_enforce_edge_uniqueness4(PG_FUNCTION_ARGS)
+{
+    graphid gid1 = AG_GETARG_GRAPHID(0);
+    graphid gid2 = AG_GETARG_GRAPHID(1);
+    graphid gid3 = AG_GETARG_GRAPHID(2);
+    graphid gid4 = AG_GETARG_GRAPHID(3);
+
+    if (gid1 == gid2 || gid1 == gid3 || gid1 == gid4 ||
+        gid2 == gid3 || gid2 == gid4 || gid3 == gid4)
+    {
+        PG_RETURN_BOOL(false);
+    }
+
+    PG_RETURN_BOOL(true);
+}
+
 /*
  * This function checks the edges in a MATCH clause to see if they are unique or
  * not. Filters out all the paths where the edge uniques rules are not met.