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

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


The following commit(s) were added to refs/heads/master by this push:
     new 15b12d8e Fix issue #883 - operator does not exist: @> agtype (#901)
15b12d8e is described below

commit 15b12d8e38fe2939c98b73103c05ef43dd1c0cf5
Author: Muhammad Taha Naveed <[email protected]>
AuthorDate: Tue May 9 20:33:56 2023 +0500

    Fix issue #883 - operator does not exist: @> agtype (#901)
    
    - Using '_' as a variable was conflicting with the default alias
      name being internally used which is also '_'.
    - Changed all internal aliases and var names to be prefixed with
      '_age_default_'.
    - Added grammer rule to disallow use of variables prefixed with
      '_age_default_' in user query.
    - Added corresponding test cases.
---
 regress/expected/cypher_match.out      | 55 ++++++++++++++++++++++++++++++++++
 regress/sql/cypher_match.sql           | 14 +++++++++
 src/backend/parser/cypher_clause.c     |  4 +--
 src/backend/parser/cypher_gram.y       | 25 ++++++++++++++--
 src/include/parser/cypher_parse_node.h | 10 +++++--
 5 files changed, 101 insertions(+), 7 deletions(-)

diff --git a/regress/expected/cypher_match.out 
b/regress/expected/cypher_match.out
index e322a3b7..c7a9b305 100644
--- a/regress/expected/cypher_match.out
+++ b/regress/expected/cypher_match.out
@@ -1787,6 +1787,61 @@ ERROR:  duplicate edge variable 'b' within a clause
 LINE 1: ...pher('cypher_match', $$ MATCH p=(a)-[b:knows]->()-[b]->(a) R...
                                                              ^
 --
+-- Default alias check (issue #883)
+--
+SELECT * FROM cypher('cypher_match', $$ MATCH (_) RETURN _ $$) as (a agtype);
+                                            a                                  
           
+------------------------------------------------------------------------------------------
+ {"id": 281474976710662, "label": "", "properties": {"i": 1, "j": 2, "k": 
3}}::vertex
+ {"id": 281474976710663, "label": "", "properties": {"i": 1, "j": 3}}::vertex
+ {"id": 281474976710664, "label": "", "properties": {"i": 2, "k": 3}}::vertex
+ {"id": 281474976710665, "label": "", "properties": {"age": 4}}::vertex
+ {"id": 281474976710666, "label": "", "properties": {"age": 6}}::vertex
+ {"id": 281474976710660, "label": "", "properties": {"age": 4, "name": 
"F"}}::vertex
+ {"id": 281474976710661, "label": "", "properties": {"age": 4, "name": 
"T"}}::vertex
+ {"id": 281474976710659, "label": "", "properties": {"age": 3, "name": 
"orphan"}}::vertex
+ {"id": 281474976710667, "label": "", "properties": {"name": "Dave"}}::vertex
+ {"id": 281474976710668, "label": "", "properties": {"name": "John"}}::vertex
+(10 rows)
+
+SELECT * FROM cypher('cypher_match', $$ MATCH () MATCH (_{name: "Dave"}) 
RETURN 0 $$) as (a agtype);
+ a 
+---
+ 0
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$ MATCH () MATCH (_{name: "Dave"}) 
RETURN _ $$) as (a agtype);
+                                      a                                       
+------------------------------------------------------------------------------
+ {"id": 281474976710667, "label": "", "properties": {"name": "Dave"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$ MATCH (my_age_default_{name: "Dave"}) 
RETURN my_age_default_$$) as (a agtype);
+                                      a                                       
+------------------------------------------------------------------------------
+ {"id": 281474976710667, "label": "", "properties": {"name": "Dave"}}::vertex
+(1 row)
+
+SELECT * FROM cypher('cypher_match', $$ MATCH () MATCH (my_age_default_{name: 
"Dave"}) RETURN my_age_default_$$) as (a agtype);
+                                      a                                       
+------------------------------------------------------------------------------
+ {"id": 281474976710667, "label": "", "properties": {"name": "Dave"}}::vertex
+(1 row)
+
+-- these should fail as they are prefixed with _age_default_ which is only for 
internal use
+SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_) RETURN 
_age_default_ $$) as (a agtype);
+ERROR:  _age_default_ is only for internal use
+LINE 1: SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_...
+                                                       ^
+SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_a) RETURN 
_age_default_a $$) as (a agtype);
+ERROR:  _age_default_ is only for internal use
+LINE 1: SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_...
+                                                       ^
+SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_whatever) RETURN 0 
$$) as (a agtype);
+ERROR:  _age_default_ is only for internal use
+LINE 1: SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_...
+                                                       ^
+--
 -- self referencing property constraints (issue #898)
 --
 SELECT * FROM cypher('cypher_match', $$ MATCH (a {name:a.name}) RETURN a $$) 
as (a agtype);
diff --git a/regress/sql/cypher_match.sql b/regress/sql/cypher_match.sql
index 75193576..60931f60 100644
--- a/regress/sql/cypher_match.sql
+++ b/regress/sql/cypher_match.sql
@@ -842,6 +842,20 @@ SELECT * FROM cypher('cypher_match', $$ MATCH 
p=(a)-[b]->()-[b:knows]->(a) RETUR
 SELECT * FROM cypher('cypher_match', $$ MATCH 
p=(a)-[b:knows]->()-[b:knows]->(a) RETURN p $$)as (p agtype);
 SELECT * FROM cypher('cypher_match', $$ MATCH p=(a)-[b:knows]->()-[b]->(a) 
RETURN p $$)as (p agtype);
 
+--
+-- Default alias check (issue #883)
+--
+SELECT * FROM cypher('cypher_match', $$ MATCH (_) RETURN _ $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH () MATCH (_{name: "Dave"}) 
RETURN 0 $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH () MATCH (_{name: "Dave"}) 
RETURN _ $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH (my_age_default_{name: "Dave"}) 
RETURN my_age_default_$$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH () MATCH (my_age_default_{name: 
"Dave"}) RETURN my_age_default_$$) as (a agtype);
+
+-- these should fail as they are prefixed with _age_default_ which is only for 
internal use
+SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_) RETURN 
_age_default_ $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_a) RETURN 
_age_default_a $$) as (a agtype);
+SELECT * FROM cypher('cypher_match', $$ MATCH (_age_default_whatever) RETURN 0 
$$) as (a agtype);
+
 --
 -- self referencing property constraints (issue #898)
 --
diff --git a/src/backend/parser/cypher_clause.c 
b/src/backend/parser/cypher_clause.c
index 98233b9e..ad8821a2 100644
--- a/src/backend/parser/cypher_clause.c
+++ b/src/backend/parser/cypher_clause.c
@@ -273,8 +273,8 @@ static Query 
*transform_cypher_call_subquery(cypher_parsestate *cpstate,
                                           cypher_clause *clause);
 
 // transform
-#define PREV_CYPHER_CLAUSE_ALIAS    "_"
-#define CYPHER_OPT_RIGHT_ALIAS      "_R"
+#define PREV_CYPHER_CLAUSE_ALIAS 
AGE_DEFAULT_ALIAS_PREFIX"previous_cypher_clause"
+#define CYPHER_OPT_RIGHT_ALIAS AGE_DEFAULT_ALIAS_PREFIX"cypher_optional_right"
 #define transform_prev_cypher_clause(cpstate, prev_clause, add_rte_to_query) \
     transform_cypher_clause_as_subquery(cpstate, transform_cypher_clause, \
                                         prev_clause, NULL, add_rte_to_query)
diff --git a/src/backend/parser/cypher_gram.y b/src/backend/parser/cypher_gram.y
index 6e124679..5f8dc2d8 100644
--- a/src/backend/parser/cypher_gram.y
+++ b/src/backend/parser/cypher_gram.y
@@ -32,6 +32,7 @@
 #include "nodes/cypher_nodes.h"
 #include "parser/ag_scanner.h"
 #include "parser/cypher_gram.h"
+#include "parser/cypher_parse_node.h"
 
 // override the default action for locations
 #define YYLLOC_DEFAULT(current, rhs, n) \
@@ -183,8 +184,11 @@
 
 %{
 //
+// internal alias check
+static bool has_internal_default_prefix(char *str);
+
 // unique name generation
-#define UNIQUE_NAME_NULL_PREFIX "_unique_null_prefix"
+#define UNIQUE_NAME_NULL_PREFIX AGE_DEFAULT_PREFIX"unique_null_prefix"
 static char *create_unique_name(char *prefix_name);
 static unsigned long get_a_unique_number(void);
 
@@ -1827,6 +1831,15 @@ property_key_name:
 
 var_name:
     symbolic_name
+    {
+        if (has_internal_default_prefix($1))
+        {
+            ereport(ERROR,
+                (errcode(ERRCODE_SYNTAX_ERROR),
+                    errmsg("%s is only for internal use", AGE_DEFAULT_PREFIX),
+                    ag_scanner_errposition(@1, scanner)));   
+        }
+    }
     ;
 
 var_name_opt:
@@ -2199,6 +2212,12 @@ static char *create_unique_name(char *prefix_name)
     return name;
 }
 
+/* function to check if given string has internal alias as prefix */
+static bool has_internal_default_prefix(char *str)
+{
+    return strncmp(AGE_DEFAULT_PREFIX, str, strlen(AGE_DEFAULT_PREFIX)) == 0;
+}
+
 /* function to return a unique unsigned long number */
 static unsigned long get_a_unique_number(void)
 {
@@ -2411,7 +2430,7 @@ static cypher_relationship *build_VLE_relation(List 
*left_arg,
         (cnl->name == NULL && cnr->label != NULL) ||
         (cnl->name == NULL && cnr->props != NULL))
     {
-        cnl->name = create_unique_name("_vle_function_start_var");
+        cnl->name = 
create_unique_name(AGE_DEFAULT_PREFIX"vle_function_start_var");
     }
 
     /* add in the start vertex as a ColumnRef if necessary */
@@ -2443,7 +2462,7 @@ static cypher_relationship *build_VLE_relation(List 
*left_arg,
     if (cnr->name == NULL &&
         (cnr->label != NULL || cnr->props != NULL))
     {
-        cnr->name = create_unique_name("_vle_function_end_var");
+        cnr->name = 
create_unique_name(AGE_DEFAULT_PREFIX"vle_function_end_var");
     }
     /*
      * We need a NULL for the target vertex in the VLE match to
diff --git a/src/include/parser/cypher_parse_node.h 
b/src/include/parser/cypher_parse_node.h
index 5b6cc695..c0d33f88 100644
--- a/src/include/parser/cypher_parse_node.h
+++ b/src/include/parser/cypher_parse_node.h
@@ -25,8 +25,14 @@
 
 #include "nodes/cypher_nodes.h"
 
-#define AGE_DEFAULT_ALIAS_PREFIX "_age_default_alias_"
-#define AGE_DEFAULT_VARNAME_PREFIX "_age_varname_"
+/*
+ * Every internal alias or variable name should be prefixed
+ * with AGE_DEFAULT_PREFIX. Grammer restricts variables
+ * prefixed with _age_default_ in user query to be used.
+ */
+#define AGE_DEFAULT_PREFIX "_age_default_"
+#define AGE_DEFAULT_ALIAS_PREFIX AGE_DEFAULT_PREFIX"alias_"
+#define AGE_DEFAULT_VARNAME_PREFIX AGE_DEFAULT_PREFIX"varname_"
 
 typedef struct cypher_parsestate
 {

Reply via email to