This is an automated email from the ASF dual-hosted git repository. jgemignani pushed a commit to branch PG12 in repository https://gitbox.apache.org/repos/asf/age.git
commit ceebd754a193864eb95feecfb95b6a1eb5567bf3 Author: Muhammad Taha Naveed <[email protected]> AuthorDate: Sat Feb 25 05:52:21 2023 +0500 Fix WITH ignoring WHERE clause (#646) * Fix WITH ignoring WHERE clause - When transforming WITH clause into return clause, WHERE was getting ignored because that case wasn't handled in tranform_cypher_clause_with_where. - Had to revert to the previous function header of tranform_cypher_clause_with_where which had a explicit parameter of where node, because after tranforming cypher_with into cypher_return, the wrapper clause now has cypher_return and the where node of cypher_with was lost. * Fix WITH clause segmentation fault - When transforming columnrefs in WITH clause, it should only check referenced Columns in its parsestate or parent parsestate. - If only expr_kind is WHERE, try to find the columnRef as a transform_entity and extract the expr. This will happen in case of (MATCH/WHERE). * Add regression tests for cypher_with --- regress/expected/cypher_with.out | 353 ++++++++++++++++++++++++++++++++++++- regress/sql/cypher_with.sql | 211 +++++++++++++++++++++- src/backend/parser/cypher_clause.c | 57 +++--- src/backend/parser/cypher_expr.c | 16 +- 4 files changed, 582 insertions(+), 55 deletions(-) diff --git a/regress/expected/cypher_with.out b/regress/expected/cypher_with.out index 7f5faca3..1166fff3 100644 --- a/regress/expected/cypher_with.out +++ b/regress/expected/cypher_with.out @@ -16,8 +16,12 @@ * specific language governing permissions and limitations * under the License. */ + \! cp -r regress/age_load/data regress/instance/data/age_load LOAD 'age'; SET search_path TO ag_catalog; +-- +-- Load data +-- SELECT create_graph('cypher_with'); NOTICE: graph "cypher_with" has been created create_graph @@ -25,31 +29,366 @@ NOTICE: graph "cypher_with" has been created (1 row) +SELECT create_vlabel('cypher_with','Country'); +NOTICE: VLabel "Country" has been created + create_vlabel +--------------- + +(1 row) + +SELECT load_labels_from_file('cypher_with', 'Country', + 'age_load/countries.csv'); + load_labels_from_file +----------------------- + +(1 row) + +SELECT create_vlabel('cypher_with','City'); +NOTICE: VLabel "City" has been created + create_vlabel +--------------- + +(1 row) + +SELECT load_labels_from_file('cypher_with', 'City', + 'age_load/cities.csv'); + load_labels_from_file +----------------------- + +(1 row) + +SELECT create_elabel('cypher_with','has_city'); +NOTICE: ELabel "has_city" has been created + create_elabel +--------------- + +(1 row) + +SELECT load_edges_from_file('cypher_with', 'has_city', + 'age_load/edges.csv'); + load_edges_from_file +---------------------- + +(1 row) + +-- +-- Test WITH clause +-- +SELECT count(*) FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m,b + RETURN m,b +$$) AS (City agtype, Country agtype); + count +------- + 2361 +(1 row) + +-- WITH/AS +SELECT * FROM cypher('cypher_with', $$ + MATCH (b:Country {iso2 : 'AT'}) + WITH b.name AS name, id(b) AS id + RETURN name,id +$$) AS (Country agtype, Country_id agtype); + country | country_id +-----------+----------------- + "Austria" | 844424930131983 +(1 row) + SELECT * FROM cypher('cypher_with', $$ -WITH true AS b -RETURN b + MATCH (m:City {name: 'Zell'})-[]-(b:Country {iso2 : 'AT'}) + WITH b as country, count(*) AS foaf + WHERE foaf > 1 + RETURN country.name, foaf +$$) as (name agtype, foaf agtype); + name | foaf +-----------+------ + "Austria" | 2 +(1 row) + +SELECT * FROM cypher('cypher_with', $$ + WITH true AS b + RETURN b $$) AS (b bool); b --- t (1 row) +-- WITH/WHERE +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country{iso2:'BE'}) + WITH b,m + WHERE m.name='x' + RETURN m.name,b.iso2 +$$) AS ( "m.name" agtype, "b" agtype); + m.name | b +--------+--- +(0 rows) + +SELECT * FROM cypher('cypher_with', $$ + MATCH (b:Country {iso2 : 'AT'}) + WITH b.name AS name, id(b) AS id + WHERE name = 'Austria' + RETURN name,id +$$) AS (Country agtype, Country_id agtype); + country | country_id +-----------+----------------- + "Austria" | 844424930131983 +(1 row) + +SELECT * FROM cypher('cypher_with', $$ + MATCH (b:Country {iso2 : 'AT'}) + WITH b.name AS name, id(b) AS id + WHERE name = 'Austria' OR name = 'Kosovo' + RETURN name,id +$$) AS (Country agtype, Country_id agtype); + country | country_id +-----------+----------------- + "Austria" | 844424930131983 +(1 row) + +SELECT * FROM cypher('cypher_with', $$ + MATCH p = (m:City)-[:has_city*1..2]->(b:Country {iso2 : 'AT'}) + WITH p, length(p) AS path_length + WHERE path_length > 1 + RETURN p +$$) AS (pattern agtype); + pattern +--------- +(0 rows) + +-- MATCH/WHERE with WITH/WHERE +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WHERE b.name = 'Austria' + WITH m.name AS city,b.name AS country + WHERE city = 'Vienna' + RETURN city,country +$$) AS (City agtype, Country agtype); + city | country +----------+----------- + "Vienna" | "Austria" +(1 row) + +-- WITH/ORDER BY +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + ORDER BY id(m) DESC LIMIT 10 + RETURN id(city),city +$$) AS (id agtype, city agtype); + id | city +------------------+------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------------- + 1125899906986495 | {"id": 1125899906986495, "label": "City", "properties": {"id": "143871", "name": "Zell", "__id__": 143871, "latitude": "46.47222222", "state_id": "2057", "longitude": "14.38888889", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986492 | {"id": 1125899906986492, "label": "City", "properties": {"id": "143868", "name": "Weißenstein", "__id__": 143868, "latitude": "46.68222222", "state_id": "2057", "longitude": "13.72361111", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986491 | {"id": 1125899906986491, "label": "City", "properties": {"id": "143867", "name": "Weißensee", "__id__": 143867, "latitude": "46.71666667", "state_id": "2057", "longitude": "13.3", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986490 | {"id": 1125899906986490, "label": "City", "properties": {"id": "143866", "name": "Weitensfeld im Gurktal", "__id__": 143866, "latitude": "46.84861111", "state_id": "2057", "longitude": "14.19166667", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986489 | {"id": 1125899906986489, "label": "City", "properties": {"id": "143865", "name": "Velden am Wörther See", "__id__": 143865, "latitude": "46.6125", "state_id": "2057", "longitude": "14.04194444", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986488 | {"id": 1125899906986488, "label": "City", "properties": {"id": "143864", "name": "Umberg", "__id__": 143864, "latitude": "46.64833", "state_id": "2057", "longitude": "13.9575", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986487 | {"id": 1125899906986487, "label": "City", "properties": {"id": "143863", "name": "Tschachoritsch", "__id__": 143863, "latitude": "46.55352", "state_id": "2057", "longitude": "14.21461", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986486 | {"id": 1125899906986486, "label": "City", "properties": {"id": "143862", "name": "Treffen", "__id__": 143862, "latitude": "46.66833333", "state_id": "2057", "longitude": "13.85555556", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986484 | {"id": 1125899906986484, "label": "City", "properties": {"id": "143860", "name": "Timenitz", "__id__": 143860, "latitude": "46.68333", "state_id": "2057", "longitude": "14.41667", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex + 1125899906986483 | {"id": 1125899906986483, "label": "City", "properties": {"id": "143859", "name": "Techelsberg", "__id__": 143859, "latitude": "46.65861111", "state_id": "2057", "longitude": "14.10194444", "country_id": "15", "state_code": "2", "country_code": "AT"}}::vertex +(10 rows) + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City) + WITH m AS city + ORDER BY id(m) ASC LIMIT 10 + RETURN id(city),city.name +$$) AS (id agtype, names agtype); + id | names +------------------+----------------------- + 1125899906842625 | "Andorra la Vella" + 1125899906842626 | "Arinsal" + 1125899906842627 | "Canillo" + 1125899906842628 | "El Tarter" + 1125899906842629 | "Encamp" + 1125899906842630 | "Ordino" + 1125899906842631 | "Pas de la Casa" + 1125899906842632 | "Sant Julià de Lòria" + 1125899906842633 | "la Massana" + 1125899906842634 | "les Escaldes" +(10 rows) + +-- WITH/ORDER BY/DESC/WHERE +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + ORDER BY id(m) DESC LIMIT 10 + WHERE city.name = 'Zell' OR city.name = 'Umberg' + RETURN id(city),city.name,country.name +$$) AS (id agtype, city agtype, country agtype); + id | city | country +------------------+----------+----------- + 1125899906986495 | "Zell" | "Austria" + 1125899906986488 | "Umberg" | "Austria" +(2 rows) + +-- multiple WITH clauses +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + WITH city LIMIT 10 + RETURN city.name +$$) AS (city agtype); + city +--------------------- + "Andau" + "Antau" + "Apetlon" + "Bad Sauerbrunn" + "Bad Tatzmannsdorf" + "Badersdorf" + "Bernstein" + "Bocksdorf" + "Breitenbrunn" + "Bruckneudorf" +(10 rows) + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + ORDER BY id(m) DESC LIMIT 10 + WITH city + WHERE city.name = 'Zell' + RETURN id(city),city.name +$$) AS (id agtype, city agtype); + id | city +------------------+-------- + 1125899906986495 | "Zell" +(1 row) + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + WHERE country.name = 'Austria' + WITH city + ORDER BY id(city) DESC + WHERE city.name = 'Zell' + RETURN id(city),city.name +$$) AS (id agtype, city agtype); + id | city +------------------+-------- + 1125899906986495 | "Zell" + 1125899906846495 | "Zell" +(2 rows) + -- Expression item must be aliased. SELECT * FROM cypher('cypher_with', $$ -WITH 1 + 1 -RETURN i + WITH 1 + 1 + RETURN i $$) AS (i int); ERROR: expression item must be aliased -LINE 2: WITH 1 + 1 - ^ +LINE 2: WITH 1 + 1 + ^ HINT: Items can be aliased by using AS. +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH id(m) + RETURN m +$$) AS (id agtype, city agtype); +ERROR: expression item must be aliased +LINE 3: WITH id(m) + ^ +HINT: Items can be aliased by using AS. +-- Reference undefined variable in WITH clause (should error out) +SELECT count(*) FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m + RETURN m,b +$$) AS (City agtype, Country agtype); +ERROR: could not find rte for b +LINE 4: RETURN m,b + ^ +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + WHERE country.name = 'Austria' + WITH city + WHERE city.name = 'Zell' + RETURN id(city),country.name +$$) AS (id agtype, country agtype); +ERROR: could not find rte for country +LINE 7: RETURN id(city),country.name + ^ +-- Clean up SELECT drop_graph('cypher_with', true); -NOTICE: drop cascades to 2 other objects +NOTICE: drop cascades to 5 other objects DETAIL: drop cascades to table cypher_with._ag_label_vertex drop cascades to table cypher_with._ag_label_edge +drop cascades to table cypher_with."Country" +drop cascades to table cypher_with."City" +drop cascades to table cypher_with.has_city NOTICE: graph "cypher_with" has been dropped drop_graph ------------ (1 row) +-- Issue 329 (should error out) +SELECT create_graph('graph'); +NOTICE: graph "graph" has been created + create_graph +-------------- + +(1 row) + +SELECT * FROM cypher('graph', $$ + CREATE (a:A)-[:incs]->(:C), (a)-[:incs]->(:C) + RETURN a +$$) AS (n agtype); + n +----------------------------------------------------------------- + {"id": 844424930131969, "label": "A", "properties": {}}::vertex +(1 row) + +SELECT * FROM cypher('graph', $$ + MATCH (a:A) + WHERE ID(a)=0 + WITH a + OPTIONAL MATCH (a)-[:incs]->(c)-[d:incs]-() + WITH a,c,COUNT(d) AS deps + WHERE deps<=1 + RETURN c,d +$$) AS (n agtype, d agtype); +ERROR: could not find rte for d +LINE 8: RETURN c,d + ^ +-- Issue 396 (should error out) +SELECT * FROM cypher('graph',$$ + CREATE (v),(u),(w), + (v)-[:hasFriend]->(u), + (u)-[:hasFriend]->(w) +$$) as (a agtype); + a +--- +(0 rows) + +SELECT * FROM cypher('graph',$$ + MATCH p=(v)-[*1..2]->(u) + WITH p,length(p) AS path_length + RETURN v,path_length +$$) as (a agtype,b agtype); +ERROR: could not find rte for v +LINE 4: RETURN v,path_length + ^ +-- Clean up +SELECT drop_graph('graph', true); +NOTICE: drop cascades to 6 other objects +DETAIL: drop cascades to table graph._ag_label_vertex +drop cascades to table graph._ag_label_edge +drop cascades to table graph."A" +drop cascades to table graph.incs +drop cascades to table graph."C" +drop cascades to table graph."hasFriend" +NOTICE: graph "graph" has been dropped + drop_graph +------------ + +(1 row) + +-- +-- End of test +-- diff --git a/regress/sql/cypher_with.sql b/regress/sql/cypher_with.sql index 623487b4..95b18c50 100644 --- a/regress/sql/cypher_with.sql +++ b/regress/sql/cypher_with.sql @@ -17,20 +17,223 @@ * under the License. */ + \! cp -r regress/age_load/data regress/instance/data/age_load + LOAD 'age'; SET search_path TO ag_catalog; +-- +-- Load data +-- SELECT create_graph('cypher_with'); +SELECT create_vlabel('cypher_with','Country'); +SELECT load_labels_from_file('cypher_with', 'Country', + 'age_load/countries.csv'); + +SELECT create_vlabel('cypher_with','City'); +SELECT load_labels_from_file('cypher_with', 'City', + 'age_load/cities.csv'); + +SELECT create_elabel('cypher_with','has_city'); +SELECT load_edges_from_file('cypher_with', 'has_city', + 'age_load/edges.csv'); + +-- +-- Test WITH clause +-- + +SELECT count(*) FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m,b + RETURN m,b +$$) AS (City agtype, Country agtype); + +-- WITH/AS + SELECT * FROM cypher('cypher_with', $$ -WITH true AS b -RETURN b + MATCH (b:Country {iso2 : 'AT'}) + WITH b.name AS name, id(b) AS id + RETURN name,id +$$) AS (Country agtype, Country_id agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City {name: 'Zell'})-[]-(b:Country {iso2 : 'AT'}) + WITH b as country, count(*) AS foaf + WHERE foaf > 1 + RETURN country.name, foaf +$$) as (name agtype, foaf agtype); + +SELECT * FROM cypher('cypher_with', $$ + WITH true AS b + RETURN b $$) AS (b bool); +-- WITH/WHERE + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country{iso2:'BE'}) + WITH b,m + WHERE m.name='x' + RETURN m.name,b.iso2 +$$) AS ( "m.name" agtype, "b" agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (b:Country {iso2 : 'AT'}) + WITH b.name AS name, id(b) AS id + WHERE name = 'Austria' + RETURN name,id +$$) AS (Country agtype, Country_id agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (b:Country {iso2 : 'AT'}) + WITH b.name AS name, id(b) AS id + WHERE name = 'Austria' OR name = 'Kosovo' + RETURN name,id +$$) AS (Country agtype, Country_id agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH p = (m:City)-[:has_city*1..2]->(b:Country {iso2 : 'AT'}) + WITH p, length(p) AS path_length + WHERE path_length > 1 + RETURN p +$$) AS (pattern agtype); + +-- MATCH/WHERE with WITH/WHERE + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WHERE b.name = 'Austria' + WITH m.name AS city,b.name AS country + WHERE city = 'Vienna' + RETURN city,country +$$) AS (City agtype, Country agtype); + +-- WITH/ORDER BY + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + ORDER BY id(m) DESC LIMIT 10 + RETURN id(city),city +$$) AS (id agtype, city agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City) + WITH m AS city + ORDER BY id(m) ASC LIMIT 10 + RETURN id(city),city.name +$$) AS (id agtype, names agtype); + +-- WITH/ORDER BY/DESC/WHERE + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + ORDER BY id(m) DESC LIMIT 10 + WHERE city.name = 'Zell' OR city.name = 'Umberg' + RETURN id(city),city.name,country.name +$$) AS (id agtype, city agtype, country agtype); + +-- multiple WITH clauses + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + WITH city LIMIT 10 + RETURN city.name +$$) AS (city agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + ORDER BY id(m) DESC LIMIT 10 + WITH city + WHERE city.name = 'Zell' + RETURN id(city),city.name +$$) AS (id agtype, city agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + WHERE country.name = 'Austria' + WITH city + ORDER BY id(city) DESC + WHERE city.name = 'Zell' + RETURN id(city),city.name +$$) AS (id agtype, city agtype); + -- Expression item must be aliased. + SELECT * FROM cypher('cypher_with', $$ -WITH 1 + 1 -RETURN i + WITH 1 + 1 + RETURN i $$) AS (i int); +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH id(m) + RETURN m +$$) AS (id agtype, city agtype); + +-- Reference undefined variable in WITH clause (should error out) + +SELECT count(*) FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m + RETURN m,b +$$) AS (City agtype, Country agtype); + +SELECT * FROM cypher('cypher_with', $$ + MATCH (m:City)-[:has_city]->(b:Country {iso2 : 'AT'}) + WITH m AS city,b AS country + WHERE country.name = 'Austria' + WITH city + WHERE city.name = 'Zell' + RETURN id(city),country.name +$$) AS (id agtype, country agtype); + +-- Clean up + SELECT drop_graph('cypher_with', true); + +-- Issue 329 (should error out) + +SELECT create_graph('graph'); + +SELECT * FROM cypher('graph', $$ + CREATE (a:A)-[:incs]->(:C), (a)-[:incs]->(:C) + RETURN a +$$) AS (n agtype); + +SELECT * FROM cypher('graph', $$ + MATCH (a:A) + WHERE ID(a)=0 + WITH a + OPTIONAL MATCH (a)-[:incs]->(c)-[d:incs]-() + WITH a,c,COUNT(d) AS deps + WHERE deps<=1 + RETURN c,d +$$) AS (n agtype, d agtype); + +-- Issue 396 (should error out) + +SELECT * FROM cypher('graph',$$ + CREATE (v),(u),(w), + (v)-[:hasFriend]->(u), + (u)-[:hasFriend]->(w) +$$) as (a agtype); + +SELECT * FROM cypher('graph',$$ + MATCH p=(v)-[*1..2]->(u) + WITH p,length(p) AS path_length + RETURN v,path_length +$$) as (a agtype,b agtype); + +-- Clean up + +SELECT drop_graph('graph', true); + +-- +-- End of test +-- diff --git a/src/backend/parser/cypher_clause.c b/src/backend/parser/cypher_clause.c index 98bfa4d4..226284c4 100644 --- a/src/backend/parser/cypher_clause.c +++ b/src/backend/parser/cypher_clause.c @@ -123,7 +123,8 @@ static Query *transform_cypher_with(cypher_parsestate *cpstate, cypher_clause *clause); static Query *transform_cypher_clause_with_where(cypher_parsestate *cpstate, transform_method transform, - cypher_clause *clause); + cypher_clause *clause, + Node *where); // match clause static Query *transform_cypher_match(cypher_parsestate *cpstate, cypher_clause *clause); @@ -1076,7 +1077,7 @@ static Query * transform_cypher_call_stmt(cypher_parsestate *cpstate, return transform_cypher_clause_with_where(cpstate, transform_cypher_call_subquery, - clause); + clause, self->where); } return NULL; @@ -2203,7 +2204,7 @@ static Query *transform_cypher_with(cypher_parsestate *cpstate, wrapper->prev = clause->prev; return transform_cypher_clause_with_where(cpstate, transform_cypher_return, - wrapper); + wrapper, self->where); } static bool match_check_valid_label(cypher_match *match, @@ -2263,28 +2264,14 @@ static bool match_check_valid_label(cypher_match *match, return true; } - static Query *transform_cypher_clause_with_where(cypher_parsestate *cpstate, transform_method transform, - cypher_clause *clause) + cypher_clause *clause, Node *where) { ParseState *pstate = (ParseState *)cpstate; Query *query; Node *self = clause->self; - cypher_match *match_self; - cypher_call *call_self; - Node *where; - - if (is_ag_node(self, cypher_call)) - { - call_self = (cypher_call*) clause->self; - where = call_self->where; - } - else - { - match_self = (cypher_match*) clause->self; - where = match_self->where; - } + Node *where_qual = NULL; if (where) { @@ -2299,32 +2286,27 @@ static Query *transform_cypher_clause_with_where(cypher_parsestate *cpstate, rtindex = list_length(pstate->p_rtable); Assert(rtindex == 1); // rte is the only RangeTblEntry in pstate + /* + * add all the target entries in rte to the current target list to pass + * all the variables that are introduced in the previous clause to the + * next clause + */ query->targetList = expandRelAttrs(pstate, rte, rtindex, 0, -1); markTargetListOrigins(pstate, query->targetList); query->rtable = pstate->p_rtable; - if (is_ag_node(clause->self, cypher_call)) + if (!is_ag_node(self, cypher_match)) { - cypher_call *call = (cypher_call *)clause->self; - - if (call->where != NULL) - { - Expr *where_qual = NULL; - - where_qual = (Expr *)transform_cypher_expr(cpstate, call->where, - EXPR_KIND_WHERE); + where_qual = transform_cypher_expr(cpstate, where, + EXPR_KIND_WHERE); - where_qual = (Expr *)coerce_to_boolean(pstate, (Node *)where_qual, - "WHERE"); - query->jointree = makeFromExpr(pstate->p_joinlist, (Node *)where_qual); - } - } - else - { - query->jointree = makeFromExpr(pstate->p_joinlist, NULL); + where_qual = coerce_to_boolean(pstate, where_qual, + "WHERE"); } + + query->jointree = makeFromExpr(pstate->p_joinlist, where_qual); assign_query_collations(pstate, query); } else @@ -2361,7 +2343,8 @@ static Query *transform_cypher_match(cypher_parsestate *cpstate, } return transform_cypher_clause_with_where( - cpstate, transform_cypher_match_pattern, clause); + cpstate, transform_cypher_match_pattern, clause, + match_self->where); } /* diff --git a/src/backend/parser/cypher_expr.c b/src/backend/parser/cypher_expr.c index c00ca846..00261dd1 100644 --- a/src/backend/parser/cypher_expr.c +++ b/src/backend/parser/cypher_expr.c @@ -319,16 +319,18 @@ static Node *transform_ColumnRef(cypher_parsestate *cpstate, ColumnRef *cref) } /* - * Try to find the columnRef as a transform_entity and extract - * the expr. + * If expr_kind is WHERE, Try to find the columnRef as a + * transform_entity and extract the expr. */ - te = find_variable(cpstate, colname) ; - if (te != NULL && te->expr != NULL) + if (pstate->p_expr_kind == EXPR_KIND_WHERE) { - node = (Node *)te->expr; - break; + te = find_variable(cpstate, colname) ; + if (te != NULL && te->expr != NULL) + { + node = (Node *)te->expr; + break; + } } - /* * Not known as a column of any range-table entry. * Try to find the name as a relation. Note that only
