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
{