On Tue, Mar 24, 2026 at 6:35 AM Henson Choi <[email protected]> wrote: > > Hi Ashutosh, > >> I have also added a few tests. I didn't add queries with all the >> patterns you mentioned above. I tested a few by hand and all of them >> worked as expected. Can you please check? > > > > I tested all the patterns and they all work correctly. No crashes, > correct results. >
Thanks a lot for the confirmation. > One thing I noticed while reviewing the rewriter changes: the Assert > at generate_queries_for_path_pattern() that checks alternating > implicit/explicit elements doesn't actually work: > > #ifdef USE_ASSERT_CHECKING > GraphElementPattern *prev_gep = NULL; > #endif > ... > Assert(!prev_gep || prev_gep->implicit != gep->implicit); > > prev_gep is never updated in the loop -- it stays NULL throughout, > so the Assert is always trivially true. It needs a > "prev_gep = gep;" at the end of the loop body to actually perform > the intended check. > Ah. Thanks for catching it. I think the Assertion is also not doing what it mentions in the comment. It just checks whether the two consecutive elements are not implicit ones; that doesn't necessarily lead to an infinite or very long chain of implicit element patterns. I have removed the assertion for now. We will add it if necessary, e.g. when we start adding implicit edge patterns in which case the possibility of long chains of implicit element patterns becomes real. >> >> Yes. That's a grammar issue. gram.y doesn't support it. Peter, do you >> remember or know the reason why we don't support full edge left or >> right? In fact, I am wondering what's the difference between full edge >> left or right and full edge any direction? > > > > I looked into this. The lexer tokenizes "]->` as "]" + RIGHT_ARROW, > so gram.y needs two alternatives -- just like the existing full edge > right rule already does. The full edge left or right was simply > missing both forms. Adding them fixes it: > > | '<' '-' '[' ... ']' '-' '>' > | '<' '-' '[' ... ']' RIGHT_ARROW > > Per the standard, <-[]-> matches left or right direction while -[]- > matches any direction. For simple directed graphs the results are > the same, so EDGE_PATTERN_ANY seems like a reasonable mapping. Our grammar is pretty tricky in this area especially because we can treat a string of operators as a SQL operator. Peter may have intentionally left it unsupported. Here's the updated patchset. -- Best Wishes, Ashutosh Bapat
From c65f230cce1df1d4bc8c19444bd5a35c5b28cc48 Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat <[email protected]> Date: Wed, 18 Mar 2026 19:27:38 +0530 Subject: [PATCH v20260324 1/3] Cross variable references in graph pattern causes segfault When converting the WHERE clause in an element pattern, generate_query_for_graph_path() calls replace_property_refs() to replace the property references in it. Only the current graph element pattern is passed as the context for replacement. If there are references to variables from other element patterns, it causes a segmentation fault (an assertion failure in an Assert enabled build) since it does not find path_element object corresponding to those variables. Fix the issue by passing all the path elements in the graph pattern as context for replacement. Author: Ashutosh Bapat <[email protected]> Reported by: Man Zeng <[email protected]> Investigated by: Henson Choi <[email protected]> Reviewed by: Junwang Zhao <[email protected]> --- src/backend/rewrite/rewriteGraphTable.c | 2 +- src/test/regress/expected/graph_table.out | 14 ++++++++++++++ src/test/regress/sql/graph_table.sql | 4 ++++ 3 files changed, 19 insertions(+), 1 deletion(-) diff --git a/src/backend/rewrite/rewriteGraphTable.c b/src/backend/rewrite/rewriteGraphTable.c index 06f2f3442d8..d3f382573fd 100644 --- a/src/backend/rewrite/rewriteGraphTable.c +++ b/src/backend/rewrite/rewriteGraphTable.c @@ -519,7 +519,7 @@ generate_query_for_graph_path(RangeTblEntry *rte, List *graph_path) { Node *tr; - tr = replace_property_refs(rte->relid, pf->whereClause, list_make1(pe)); + tr = replace_property_refs(rte->relid, pf->whereClause, graph_path); qual_exprs = lappend(qual_exprs, tr); } diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out index 27c81ec6e42..eeaf1b85121 100644 --- a/src/test/regress/expected/graph_table.out +++ b/src/test/regress/expected/graph_table.out @@ -395,6 +395,20 @@ SELECT * FROM GRAPH_TABLE (g1 MATCH (v1 IS vl2)-(v2) COLUMNS (v1.vname AS v1name v22 | v32 (3 rows) +-- cross variable references +SELECT * FROM GRAPH_TABLE (g1 MATCH (a)-[b WHERE a.vprop1 = 10]->(c) COLUMNS (a.vname AS aname, a.vprop1 AS ap1, b.ename AS bname, b.eprop1 AS bp1, c.vname AS cname, c.vprop1 AS cp1)) ORDER BY aname, bname, cname; + aname | ap1 | bname | bp1 | cname | cp1 +-------+-----+-------+-------+-------+------ + v11 | 10 | e121 | 10001 | v22 | 1020 + v11 | 10 | e131 | 10003 | v33 | 2030 + v11 | 10 | e132 | 10004 | v31 | 2010 +(3 rows) + +-- forward variable reference, not supported +SELECT * FROM GRAPH_TABLE (g1 MATCH (a WHERE b.eprop1 = 10001)-[b]->(c) COLUMNS (a.vname AS aname, a.vprop1 AS ap1, b.ename AS bname, b.eprop1 AS bp1, c.vname AS cname, c.vprop1 AS cp1)) ORDER BY aname, bname, cname; +ERROR: missing FROM-clause entry for table "b" +LINE 1: SELECT * FROM GRAPH_TABLE (g1 MATCH (a WHERE b.eprop1 = 1000... + ^ -- Errors -- vl1 is not associated with property vprop2 SELECT src, src_vprop2, conn, dest FROM GRAPH_TABLE (g1 MATCH (a IS vl1)-[b IS el1]->(c IS vl2 | vl3) COLUMNS (a.vname AS src, a.vprop2 AS src_vprop2, b.ename AS conn, c.vname AS dest)); diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql index 6d2b08b997b..c3a35b69e92 100644 --- a/src/test/regress/sql/graph_table.sql +++ b/src/test/regress/sql/graph_table.sql @@ -274,6 +274,10 @@ SELECT src, conn, dest, lprop1, vprop2, vprop1 FROM GRAPH_TABLE (g1 MATCH (a IS -- edges directed in both ways - to and from v2 SELECT * FROM GRAPH_TABLE (g1 MATCH (v1 IS vl2)-[conn]-(v2) COLUMNS (v1.vname AS v1name, conn.ename AS cname, v2.vname AS v2name)); SELECT * FROM GRAPH_TABLE (g1 MATCH (v1 IS vl2)-(v2) COLUMNS (v1.vname AS v1name, v2.vname AS v2name)); +-- cross variable references +SELECT * FROM GRAPH_TABLE (g1 MATCH (a)-[b WHERE a.vprop1 = 10]->(c) COLUMNS (a.vname AS aname, a.vprop1 AS ap1, b.ename AS bname, b.eprop1 AS bp1, c.vname AS cname, c.vprop1 AS cp1)) ORDER BY aname, bname, cname; +-- forward variable reference, not supported +SELECT * FROM GRAPH_TABLE (g1 MATCH (a WHERE b.eprop1 = 10001)-[b]->(c) COLUMNS (a.vname AS aname, a.vprop1 AS ap1, b.ename AS bname, b.eprop1 AS bp1, c.vname AS cname, c.vprop1 AS cp1)) ORDER BY aname, bname, cname; -- Errors -- vl1 is not associated with property vprop2 base-commit: 570e2fcc041a55ba8991a640cc3f3f0e122feac3 -- 2.34.1
From b8d66edb934057ecf1b4be3ede17eea7a974deba Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat <[email protected]> Date: Tue, 17 Mar 2026 14:30:16 +0530 Subject: [PATCH v20260324 3/3] Cleanup and other cosmetic fixes ... collected over time TODO: provide a proper commit message Author: Man Zeng <[email protected]> Author: Ashutosh Bapat <[email protected]> --- src/backend/parser/parse_graphtable.c | 21 ++++++++-------- src/backend/rewrite/rewriteGraphTable.c | 32 ++++++++++++------------- 2 files changed, 26 insertions(+), 27 deletions(-) diff --git a/src/backend/parser/parse_graphtable.c b/src/backend/parser/parse_graphtable.c index 1590f4f9cde..50e279335c9 100644 --- a/src/backend/parser/parse_graphtable.c +++ b/src/backend/parser/parse_graphtable.c @@ -94,14 +94,14 @@ transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref) { if (pstate->p_expr_kind == EXPR_KIND_SELECT_TARGET) ereport(ERROR, - errcode(ERRCODE_FEATURE_NOT_SUPPORTED), - errmsg("\"*\" is not supported here"), - parser_errposition(pstate, cref->location)); + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("\"*\" is not supported here"), + parser_errposition(pstate, cref->location))); else ereport(ERROR, - errcode(ERRCODE_SYNTAX_ERROR), - errmsg("\"*\" not allowed here"), - parser_errposition(pstate, cref->location)); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("\"*\" not allowed here"), + parser_errposition(pstate, cref->location))); } elvarname = strVal(field1); @@ -116,8 +116,8 @@ transformGraphTablePropertyRef(ParseState *pstate, ColumnRef *cref) pgptup = SearchSysCache2(PROPGRAPHPROPNAME, ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(propname)); if (!HeapTupleIsValid(pgptup)) ereport(ERROR, - errcode(ERRCODE_SYNTAX_ERROR), - errmsg("property \"%s\" does not exist", propname)); + (errcode(ERRCODE_SYNTAX_ERROR), + errmsg("property \"%s\" does not exist", propname))); pgpform = (Form_pg_propgraph_property) GETSTRUCT(pgptup); gpr->location = cref->location; @@ -172,8 +172,9 @@ transformLabelExpr(GraphTableParseState *gpstate, Node *labelexpr) labelid = GetSysCacheOid2(PROPGRAPHLABELNAME, Anum_pg_propgraph_label_oid, ObjectIdGetDatum(gpstate->graphid), CStringGetDatum(labelname)); if (!labelid) ereport(ERROR, - errcode(ERRCODE_UNDEFINED_OBJECT), - errmsg("label \"%s\" does not exist in property graph \"%s\"", labelname, get_rel_name(gpstate->graphid))); + (errcode(ERRCODE_UNDEFINED_OBJECT), + errmsg("label \"%s\" does not exist in property graph \"%s\"", + labelname, get_rel_name(gpstate->graphid)))); lref = makeNode(GraphLabelRef); lref->labelid = labelid; diff --git a/src/backend/rewrite/rewriteGraphTable.c b/src/backend/rewrite/rewriteGraphTable.c index 028b1841531..e748246b6a9 100644 --- a/src/backend/rewrite/rewriteGraphTable.c +++ b/src/backend/rewrite/rewriteGraphTable.c @@ -33,7 +33,6 @@ #include "parser/parse_oper.h" #include "parser/parse_relation.h" #include "parser/parsetree.h" -#include "parser/parse_relation.h" #include "parser/parse_graphtable.h" #include "rewrite/rewriteGraphTable.h" #include "rewrite/rewriteHandler.h" @@ -247,16 +246,14 @@ generate_queries_for_path_pattern(RangeTblEntry *rte, List *path_pattern) if (!pf) { - { - pf = palloc0_object(struct path_factor); - pf->factorpos = factorpos++; - pf->kind = gep->kind; - pf->labelexpr = gep->labelexpr; - pf->variable = gep->variable; - pf->whereClause = gep->whereClause; - - path_factors = lappend(path_factors, pf); - } + pf = palloc0_object(struct path_factor); + pf->factorpos = factorpos++; + pf->kind = gep->kind; + pf->labelexpr = gep->labelexpr; + pf->variable = gep->variable; + pf->whereClause = gep->whereClause; + + path_factors = lappend(path_factors, pf); } /* @@ -280,7 +277,7 @@ generate_queries_for_path_pattern(RangeTblEntry *rte, List *path_pattern) * be merged even though they have different variables. Such element * patterns form a walk of graph where vertex and edges are repeated. * For example, in (a)-[b]->(c)<-[b]-(d), (a) and (d) represent the - * same vertex element. This is slighly harder to implement and + * same vertex element. This is slightly harder to implement and * probably less useful. Hence not supported for now. */ if (prev_pf) @@ -433,7 +430,7 @@ generate_query_for_graph_path(RangeTblEntry *rte, List *graph_path) Assert(pf->kind == VERTEX_PATTERN || IS_EDGE_PATTERN(pf->kind)); - /* Add conditions representing edge connnections. */ + /* Add conditions representing edge connections. */ if (IS_EDGE_PATTERN(pf->kind)) { struct path_element *src_pe; @@ -746,7 +743,7 @@ generate_setop_from_pathqueries(List *pathqueries, List **rtable, List **targetl /* * Construct a path_element object for the graph element given by `elemoid` - * statisfied by the path factor `pf`. + * satisfied by the path factor `pf`. * * If the type of graph element does not fit the element pattern kind, the * function returns NULL. @@ -946,7 +943,7 @@ get_path_elements_for_path_factor(Oid propgraphid, struct path_factor *pf) } /* - * Rememeber qualified and unqualified elements processed so + * Remember qualified and unqualified elements processed so * far to avoid processing already processed elements again. */ elem_oids_seen = lappend_oid(elem_oids_seen, label_elem->pgelelid); @@ -1115,8 +1112,9 @@ replace_property_refs_mutator(Node *node, struct replace_property_refs_context * * The property is associated with at least one of the labels * that satisfy given element pattern. If it's associated with * the given element (through some other label), use - * correspondig value expression. Otherwise NULL. Ref. SQL/PGQ - * standard section 6.5 Property Reference, General Rule 2.b. + * corresponding value expression. Otherwise NULL. Ref. + * SQL/PGQ standard section 6.5 Property Reference, General + * Rule 2.b. */ n = get_element_property_expr(found_mapping->elemoid, gpr->propid, mapping_factor->factorpos + 1); -- 2.34.1
From 2d6266aaf6b9765546c746ce45cf4836147e3d31 Mon Sep 17 00:00:00 2001 From: Ashutosh Bapat <[email protected]> Date: Mon, 23 Mar 2026 19:29:21 +0530 Subject: [PATCH v20260324 2/3] Implicit vertex patterns When a path pattern contains two consecutive edge patterns without a vertex pattern in between, we implicitly add a vertex pattern between them in accordance with the syntax rule 13, subclause 10.6 of SQL/PGQ standard. On the other hand, consecutive vertex patterns without an edge pattern in between is not supported. Author: Ashutosh Bapat <[email protected]> Reported by: Alexander Lakhin <[email protected]> Investigation by: Henson Choi <[email protected]> Reviewed by: Henson Choi <[email protected]> --- src/backend/parser/parse_graphtable.c | 66 +++++++++++++++++++++-- src/backend/rewrite/rewriteGraphTable.c | 10 ++++ src/backend/utils/adt/ruleutils.c | 4 ++ src/include/nodes/parsenodes.h | 3 ++ src/test/regress/expected/graph_table.out | 28 ++++++++++ src/test/regress/sql/graph_table.sql | 6 +++ 6 files changed, 112 insertions(+), 5 deletions(-) diff --git a/src/backend/parser/parse_graphtable.c b/src/backend/parser/parse_graphtable.c index bf805b4beb6..1590f4f9cde 100644 --- a/src/backend/parser/parse_graphtable.c +++ b/src/backend/parser/parse_graphtable.c @@ -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), @@ -246,6 +241,23 @@ transformGraphElementPattern(ParseState *pstate, GraphElementPattern *gep) return (Node *) gep; } +/* + * Create an implicit element patterns of the given kind. + * + * An implicit element pattern is an empty element pattern of given kind. + */ +static GraphElementPattern * +createImplicitElementPattern(ParseState *pstate, GraphElementPatternKind kind) +{ + GraphElementPattern *gep = makeNode(GraphElementPattern); + + gep->kind = kind; + gep->implicit = true; + gep->location = -1; + + return gep; +} + /* * Transform a path term (list of GraphElementPattern's). */ @@ -253,10 +265,54 @@ 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)) + { + /* + * Add an implicit vertex pattern at the beginning if the given + * path starts with an edge or add an implicit vertex pattern + * between two consecutive edge patterns. + */ + if (!prev_gep || prev_gep->kind != VERTEX_PATTERN) + { + GraphElementPattern *empty_vertex_pattern = createImplicitElementPattern(pstate, VERTEX_PATTERN); + + result = lappend(result, transformGraphElementPattern(pstate, empty_vertex_pattern)); + } + } + else + { + if (prev_gep && !IS_EDGE_PATTERN(prev_gep->kind)) + ereport(ERROR, + (errcode(ERRCODE_FEATURE_NOT_SUPPORTED), + errmsg("path pattern with two consecutive vertex patterns without an edge pattern in between is not supported"), + parser_errposition(pstate, gep->location))); + } + result = lappend(result, transformGraphElementPattern(pstate, gep)); + prev_gep = gep; + } + + /* + * Add an implicit vertex pattern at the end if the last element is an + * edge pattern. + */ + if (prev_gep && IS_EDGE_PATTERN(prev_gep->kind)) + { + GraphElementPattern *empty_vertex_pattern = createImplicitElementPattern(pstate, VERTEX_PATTERN); + + result = lappend(result, transformGraphElementPattern(pstate, empty_vertex_pattern)); + } return (Node *) result; } diff --git a/src/backend/rewrite/rewriteGraphTable.c b/src/backend/rewrite/rewriteGraphTable.c index d3f382573fd..028b1841531 100644 --- a/src/backend/rewrite/rewriteGraphTable.c +++ b/src/backend/rewrite/rewriteGraphTable.c @@ -303,6 +303,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) { @@ -322,6 +327,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; diff --git a/src/backend/utils/adt/ruleutils.c b/src/backend/utils/adt/ruleutils.c index 7bc12589e40..99e7cf4406c 100644 --- a/src/backend/utils/adt/ruleutils.c +++ b/src/backend/utils/adt/ruleutils.c @@ -8030,6 +8030,10 @@ get_path_pattern_expr_def(List *path_pattern_expr, deparse_context *context) GraphElementPattern *gep = lfirst_node(GraphElementPattern, lc); const char *sep = ""; + /* Ignore implicitly added elements */ + if (gep->implicit) + continue; + switch (gep->kind) { case VERTEX_PATTERN: diff --git a/src/include/nodes/parsenodes.h b/src/include/nodes/parsenodes.h index df431220ac5..95f7cce1812 100644 --- a/src/include/nodes/parsenodes.h +++ b/src/include/nodes/parsenodes.h @@ -1049,6 +1049,9 @@ typedef struct GraphElementPattern List *subexpr; Node *whereClause; List *quantifier; + bool implicit pg_node_attr(query_jumble_ignore); /* True if implicitly + * added during + * transformation. */ ParseLoc location; } GraphElementPattern; diff --git a/src/test/regress/expected/graph_table.out b/src/test/regress/expected/graph_table.out index eeaf1b85121..4f951b15d0f 100644 --- a/src/test/regress/expected/graph_table.out +++ b/src/test/regress/expected/graph_table.out @@ -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" @@ -434,6 +436,10 @@ 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... ^ +SELECT * FROM GRAPH_TABLE (g1 MATCH (a IS vl1 WHERE a.vprop1 in (10, 30))(b IS vl2 WHERE b.vprop2 >= 1200) COLUMNS (a.vname AS aname, b.vname AS bname)); +ERROR: path pattern with two consecutive vertex patterns without an edge pattern in between is not supported +LINE 1: ...LE (g1 MATCH (a IS vl1 WHERE a.vprop1 in (10, 30))(b IS vl2 ... + ^ -- 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)); @@ -580,6 +586,20 @@ SELECT * FROM GRAPH_TABLE (g1 MATCH (a)->(b)->(a IS vl1) COLUMNS (a.vname AS sel v13 | v23 | 30 | 1030 (2 rows) +-- implicitly added vertex pattern +SELECT * FROM GRAPH_TABLE (g1 MATCH -[c IS el2 ]-> COLUMNS (c.ename AS cname)); + cname +------- + e231 + e321 +(2 rows) + +SELECT count(*) FROM GRAPH_TABLE (g1 MATCH (a IS vl2 WHERE a.vname = 'v22')-[]- COLUMNS (1 AS one)); + count +------- + 3 +(1 row) + -- add loop to test edge patterns with same variable name CREATE TABLE e3_3 ( src_id int, @@ -897,6 +917,14 @@ SELECT pg_get_viewdef('customers_us'::regclass); ORDER BY customer_name, product_name; (1 row) +CREATE VIEW implicit_vertex AS SELECT * FROM GRAPH_TABLE (g1 MATCH -[c is el1]-> COLUMNS (c.ename AS cname)); +SELECT pg_get_viewdef('implicit_vertex'::regclass); + pg_get_viewdef +-------------------------------------------------------------------------- + SELECT cname + + FROM GRAPH_TABLE (g1 MATCH -[c IS el1]-> COLUMNS (c.ename AS cname)); +(1 row) + -- test view/graph nesting CREATE VIEW customers_view AS SELECT customer_id, 'redacted' || customer_id AS name_redacted, address FROM customers; SELECT * FROM customers; diff --git a/src/test/regress/sql/graph_table.sql b/src/test/regress/sql/graph_table.sql index c3a35b69e92..ed4eeee534b 100644 --- a/src/test/regress/sql/graph_table.sql +++ b/src/test/regress/sql/graph_table.sql @@ -293,6 +293,7 @@ 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)); +SELECT * FROM GRAPH_TABLE (g1 MATCH (a IS vl1 WHERE a.vprop1 in (10, 30))(b IS vl2 WHERE b.vprop2 >= 1200) COLUMNS (a.vname AS aname, b.vname AS bname)); -- select all the properties across all the labels associated with a given type -- of graph element @@ -355,6 +356,9 @@ SELECT * FROM GRAPH_TABLE (g1 MATCH (a IS l1)-[a IS l1]->(b IS l1) COLUMNS (a.en SELECT * FROM GRAPH_TABLE (g1 MATCH (a IS vl1)->(b)->(a IS vl2) WHERE a.vname <> b.vname COLUMNS (a.vname AS self, b.vname AS through, a.vprop1 AS self_p1, b.vprop1 AS through_p1)) ORDER BY self, through; -- error SELECT * FROM GRAPH_TABLE (g1 MATCH (a IS vl1)->(b)->(a) COLUMNS (a.vname AS self, b.vname AS through, a.vprop1 AS self_p1, b.vprop1 AS through_p1)) ORDER BY self, through; SELECT * FROM GRAPH_TABLE (g1 MATCH (a)->(b)->(a IS vl1) COLUMNS (a.vname AS self, b.vname AS through, a.vprop1 AS self_p1, b.vprop1 AS through_p1)) ORDER BY self, through; +-- implicitly added vertex pattern +SELECT * FROM GRAPH_TABLE (g1 MATCH -[c IS el2 ]-> COLUMNS (c.ename AS cname)); +SELECT count(*) FROM GRAPH_TABLE (g1 MATCH (a IS vl2 WHERE a.vname = 'v22')-[]- COLUMNS (1 AS one)); -- add loop to test edge patterns with same variable name CREATE TABLE e3_3 ( @@ -513,6 +517,8 @@ SELECT * FROM GRAPH_TABLE (g4 MATCH (s WHERE s.id = 3)-[e]-(d) COLUMNS (s.val, e -- ruleutils reverse parsing CREATE VIEW customers_us AS SELECT * FROM GRAPH_TABLE (myshop MATCH (c IS customers WHERE c.address = 'US')-[IS customer_orders | customer_wishlists ]->(l IS orders | wishlists)-[ IS list_items]->(p IS products) COLUMNS (c.name AS customer_name, p.name AS product_name)) ORDER BY customer_name, product_name; SELECT pg_get_viewdef('customers_us'::regclass); +CREATE VIEW implicit_vertex AS SELECT * FROM GRAPH_TABLE (g1 MATCH -[c is el1]-> COLUMNS (c.ename AS cname)); +SELECT pg_get_viewdef('implicit_vertex'::regclass); -- test view/graph nesting -- 2.34.1
