]> git.ipfire.org Git - thirdparty/postgresql.git/commitdiff
Reject consecutive element patterns of same kind
authorPeter Eisentraut <peter@eisentraut.org>
Fri, 27 Mar 2026 09:30:01 +0000 (10:30 +0100)
committerPeter Eisentraut <peter@eisentraut.org>
Fri, 27 Mar 2026 09:31:53 +0000 (10:31 +0100)
Adding an implicit empty vertex pattern when a path pattern starts or
ends with an edge pattern or when two consecutive edge patterns appear
in the pattern is not supported right now.  Prohibit such path
patterns.

Author: Ashutosh Bapat <ashutosh.bapat.oss@gmail.com>
Reported-by: Alexander Lakhin <exclusion@gmail.com>
Reviewed-by: Henson Choi <assam258@gmail.com>
Discussion: https://www.postgresql.org/message-id/flat/72a23702-6d96-4103-a54b-057c2352e885%2540eisentraut.org

src/backend/parser/parse_graphtable.c
src/backend/rewrite/rewriteGraphTable.c
src/test/regress/expected/graph_table.out
src/test/regress/sql/graph_table.sql

index bf805b4beb61b5cb4bedf2837e14fd0b71af1633..136d87e61cf4f6e048e88ca34136db4d4a4bb892 100644 (file)
@@ -225,11 +225,6 @@ transformGraphElementPattern(ParseState *pstate, GraphElementPattern *gep)
 {
        GraphTableParseState *gpstate = pstate->p_graph_table_pstate;
 
-       if (gep->kind != VERTEX_PATTERN && !IS_EDGE_PATTERN(gep->kind))
-               ereport(ERROR,
-                               errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
-                               errmsg("unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind)));
-
        if (gep->quantifier)
                ereport(ERROR,
                                (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
@@ -253,10 +248,53 @@ static Node *
 transformPathTerm(ParseState *pstate, List *path_term)
 {
        List       *result = NIL;
+       GraphElementPattern *prev_gep = NULL;
 
        foreach_node(GraphElementPattern, gep, path_term)
+       {
+               if (gep->kind != VERTEX_PATTERN && !IS_EDGE_PATTERN(gep->kind))
+                       ereport(ERROR,
+                                       (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                        errmsg("unsupported element pattern kind: \"%s\"", get_gep_kind_name(gep->kind)),
+                                        parser_errposition(pstate, gep->location)));
+
+               if (IS_EDGE_PATTERN(gep->kind))
+               {
+                       if (!prev_gep)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("path pattern cannot start with an edge pattern"),
+                                                parser_errposition(pstate, gep->location)));
+                       else if (prev_gep->kind != VERTEX_PATTERN)
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("edge pattern must be preceded by a vertex pattern"),
+                                                parser_errposition(pstate, gep->location)));
+               }
+               else
+               {
+                       if (prev_gep && !IS_EDGE_PATTERN(prev_gep->kind))
+                               ereport(ERROR,
+                                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                                errmsg("adjacent vertex patterns are not supported"),
+                                                parser_errposition(pstate, gep->location)));
+               }
+
                result = lappend(result,
                                                 transformGraphElementPattern(pstate, gep));
+               prev_gep = gep;
+       }
+
+       /* Path pattern should have at least one element pattern. */
+       Assert(prev_gep);
+
+       if (IS_EDGE_PATTERN(prev_gep->kind))
+       {
+               ereport(ERROR,
+                               (errcode(ERRCODE_FEATURE_NOT_SUPPORTED),
+                                errmsg("path pattern cannot end with an edge pattern"),
+                                parser_errposition(pstate, prev_gep->location)));
+       }
 
        return (Node *) result;
 }
index 9c293586e44d9080c3e2ae959b7fd3ebeea29853..2c3199d32302a3db40bef76adfbd5c958dfd26b2 100644 (file)
@@ -300,6 +300,11 @@ generate_queries_for_path_pattern(RangeTblEntry *rte, List *path_pattern)
                                                        errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
                                prev_pf->src_pf = pf;
                        }
+                       else
+                       {
+                               Assert(prev_pf->kind == VERTEX_PATTERN);
+                               Assert(IS_EDGE_PATTERN(pf->kind));
+                       }
 
                        if (pf->kind == EDGE_PATTERN_RIGHT || pf->kind == EDGE_PATTERN_ANY)
                        {
@@ -319,6 +324,11 @@ generate_queries_for_path_pattern(RangeTblEntry *rte, List *path_pattern)
                                                        errmsg("an edge cannot connect more than two vertexes even in a cyclic pattern"));
                                pf->dest_pf = prev_pf;
                        }
+                       else
+                       {
+                               Assert(pf->kind == VERTEX_PATTERN);
+                               Assert(IS_EDGE_PATTERN(prev_pf->kind));
+                       }
                }
 
                prev_pf = pf;
index 27c81ec6e42bed6d3c1bb0038fc1590361b23cad..2fc5a2e8c5acafc34f99bba4729948347bcc671a 100644 (file)
@@ -103,6 +103,8 @@ SELECT customer_name FROM GRAPH_TABLE (myshop MATCH (c IS customers)->{1,2}(o IS
 ERROR:  element pattern quantifier is not supported
 SELECT * FROM GRAPH_TABLE (myshop MATCH ((c IS customers)->(o IS orders)) COLUMNS (c.name));
 ERROR:  unsupported element pattern kind: "nested path pattern"
+LINE 1: SELECT * FROM GRAPH_TABLE (myshop MATCH ((c IS customers)->(...
+                                                ^
 -- a property graph can be referenced only from within GRAPH_TABLE clause.
 SELECT * FROM myshop; -- error
 ERROR:  cannot open relation "myshop"
@@ -420,6 +422,23 @@ SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.* IS NOT NULL)-[
 ERROR:  "*" not allowed here
 LINE 1: ...M GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.* IS NOT...
                                                              ^
+-- consecutive element patterns with same kind
+SELECT * FROM GRAPH_TABLE (g1 MATCH ()() COLUMNS (1 as one));
+ERROR:  adjacent vertex patterns are not supported
+LINE 1: SELECT * FROM GRAPH_TABLE (g1 MATCH ()() COLUMNS (1 as one))...
+                                              ^
+SELECT * FROM GRAPH_TABLE (g1 MATCH -> COLUMNS (1 AS one));
+ERROR:  path pattern cannot start with an edge pattern
+LINE 1: SELECT * FROM GRAPH_TABLE (g1 MATCH -> COLUMNS (1 AS one));
+                                            ^
+SELECT * FROM GRAPH_TABLE (g1 MATCH ()-[]- COLUMNS (1 AS one));
+ERROR:  path pattern cannot end with an edge pattern
+LINE 1: SELECT * FROM GRAPH_TABLE (g1 MATCH ()-[]- COLUMNS (1 AS one...
+                                              ^
+SELECT * FROM GRAPH_TABLE (g1 MATCH ()-> ->() COLUMNS (1 AS one));
+ERROR:  edge pattern must be preceded by a vertex pattern
+LINE 1: SELECT * FROM GRAPH_TABLE (g1 MATCH ()-> ->() COLUMNS (1 AS ...
+                                                 ^
 -- select all the properties across all the labels associated with a given type
 -- of graph element
 SELECT * FROM GRAPH_TABLE (g1 MATCH (src)-[conn]->(dest) COLUMNS (src.vname AS svname, conn.ename AS cename, dest.vname AS dvname, src.vprop1 AS svp1, src.vprop2 AS svp2, src.lprop1 AS slp1, dest.vprop1 AS dvp1, dest.vprop2 AS dvp2, dest.lprop1 AS dlp1, conn.eprop1 AS cep1, conn.lprop2 AS clp2));
index 6d2b08b997bf940f4c3e445443897b84c6468d2b..7c2438e84a3e35daac7afacb5ea6e6cfc20c4111 100644 (file)
@@ -289,6 +289,12 @@ SELECT * FROM GRAPH_TABLE (g1 MATCH (src IS el1 | vl1)-[conn]->(dest) COLUMNS (c
 SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US')-[IS customer_orders]->(o IS orders) COLUMNS (c.*));
 -- star anywhere else is not allowed as a property reference
 SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.* IS NOT NULL)-[IS customer_orders]->(o IS orders) COLUMNS (c.name));
+-- consecutive element patterns with same kind
+SELECT * FROM GRAPH_TABLE (g1 MATCH ()() COLUMNS (1 as one));
+SELECT * FROM GRAPH_TABLE (g1 MATCH -> COLUMNS (1 AS one));
+SELECT * FROM GRAPH_TABLE (g1 MATCH ()-[]- COLUMNS (1 AS one));
+SELECT * FROM GRAPH_TABLE (g1 MATCH ()-> ->() COLUMNS (1 AS one));
+
 
 -- select all the properties across all the labels associated with a given type
 -- of graph element