Skip to content
New issue

Have a question about this project? Sign up for a free GitHub account to open an issue and contact its maintainers and the community.

By clicking “Sign up for GitHub”, you agree to our terms of service and privacy statement. We’ll occasionally send you account related emails.

Already on GitHub? Sign in to your account

edges are not bound-able #498

Open
wants to merge 8 commits into
base: master
Choose a base branch
from
Open

edges are not bound-able #498

wants to merge 8 commits into from

Conversation

swilly22
Copy link
Contributor

@swilly22 swilly22 commented Nov 6, 2023

Resolves #465

Unlike nodes, edges always declare alias
Example:

MATCH (a) WITH a MATCH (z)-[]->(a) RETURN z

Here a is declared by the first MATCH clause and a is considered bounded by the second MATCH clause.

This behavior isn't applicable for edges

MATCH ()-[e]->() WITH e MATCH ()-[e]->() RETURN *

In this case e is declared by BOTH MATCH clauses, which is not allowed.

Summary by CodeRabbit

  • Bug Fixes

    • Improved validation logic for CREATE and MERGE clauses to handle relation types, directions, and properties accurately.
    • Refined error messages and handling for better clarity during graph pattern creation.
  • Tests

    • Added extra lines and comments for clarity in various test methods.
    • Updated test cases to handle redeclaration errors for bound edges and variables.
    • Enhanced exception handling in test07_null_graph_entity_inputs to manage specific error scenarios during query execution.

Copy link

coderabbitai bot commented Apr 4, 2024

Walkthrough

The recent changes focus on enhancing the validation logic for Abstract Syntax Tree (AST) nodes in query language operations, particularly for CREATE and MERGE clauses. These updates ensure accurate handling of relation types, directions, and properties, and improve error handling. Additionally, several test files have been updated to reflect these changes, incorporating clearer error messages and more structured test cases.

Changes

File Path Change Summary
src/ast/ast_validations.c Refined validation logic for AST nodes, removed specific validation functions, updated error handling.
tests/flow/test_bound_variables.py Added empty lines for clarity, updated test methods with improved structure.
tests/flow/test_create_clause.py Updated logic for reusing bound edges in CREATE clauses, refined error messages.
tests/flow/test_graph_create.py Adjusted CREATE queries to handle redeclaration errors for bound edges and variables.
tests/flow/test_null_handling.py Added try-except block to handle specific error messages during query execution.

Assessment against linked issues

Objective Addressed Explanation
Ensure validation logic prevents crashes with same relationship variable in patterns (#465)
Improve error messages for redeclaration of bound edges and variables (#465)
Update test cases to reflect changes in validation logic (#465)

Poem

Amidst the code in files so vast,
Relations checked, errors cast,
Bound edges now with clarity,
In tests, we see prosperity.
A rabbit's joy in lines so neat,
Validation's dance, a coder's feat.
🐇✨


Thank you for using CodeRabbit. We offer it for free to the OSS community and would appreciate your support in helping us grow. If you find it useful, would you consider giving us a shout-out on your favorite social media?

Share
Tips

Chat

There are 3 ways to chat with CodeRabbit:

  • Review comments: Directly reply to a review comment made by CodeRabbit. Example:
    • I pushed a fix in commit <commit_id>.
    • Generate unit testing code for this file.
    • Open a follow-up GitHub issue for this discussion.
  • Files and specific lines of code (under the "Files changed" tab): Tag @coderabbitai in a new review comment at the desired location with your query. Examples:
    • @coderabbitai generate unit testing code for this file.
    • @coderabbitai modularize this function.
  • PR comments: Tag @coderabbitai in a new PR comment to ask questions about the PR branch. For the best results, please provide a very specific query, as very limited context is provided in this mode. Examples:
    • @coderabbitai generate interesting stats about this repository and render them as a table.
    • @coderabbitai show all the console.log statements in this repository.
    • @coderabbitai read src/utils.ts and generate unit testing code.
    • @coderabbitai read the files in the src/scheduler package and generate a class diagram using mermaid and a README in the markdown format.
    • @coderabbitai help me debug CodeRabbit configuration file.

Note: Be mindful of the bot's finite context window. It's strongly recommended to break down tasks such as reading entire modules into smaller chunks. For a focused discussion, use review comments to chat about specific files and their changes, instead of using the PR comments.

CodeRabbit Commands (invoked as PR comments)

  • @coderabbitai pause to pause the reviews on a PR.
  • @coderabbitai resume to resume the paused reviews.
  • @coderabbitai review to trigger an incremental review. This is useful when automatic reviews are disabled for the repository.
  • @coderabbitai full review to do a full review from scratch and review all the files again.
  • @coderabbitai summary to regenerate the summary of the PR.
  • @coderabbitai resolve resolve all the CodeRabbit review comments.
  • @coderabbitai configuration to show the current CodeRabbit configuration for the repository.
  • @coderabbitai help to get help.

Additionally, you can add @coderabbitai ignore anywhere in the PR description to prevent this PR from being reviewed.

CodeRabbit Configration File (.coderabbit.yaml)

  • You can programmatically configure CodeRabbit by adding a .coderabbit.yaml file to the root of your repository.
  • Please see the configuration documentation for more information.
  • If your editor has YAML language server enabled, you can add the path at the top of this file to enable auto-completion and validation: # yaml-language-server: $schema=https://coderabbit.ai/integrations/schema.v2.json

Documentation and Community

  • Visit our Documentation for detailed information on how to use CodeRabbit.
  • Join our Discord Community to get help, request features, and share feedback.
  • Follow us on X/Twitter for updates and announcements.

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 9

Review Status

Configuration used: CodeRabbit UI

Commits Files that changed from the base of the PR and between 3ea7a3b and c613605.
Files selected for processing (6)
  • src/ast/ast_validations.c (5 hunks)
  • src/errors/error_msgs.h (1 hunks)
  • tests/flow/test_bound_variables.py (7 hunks)
  • tests/flow/test_create_clause.py (2 hunks)
  • tests/flow/test_graph_create.py (1 hunks)
  • tests/flow/test_null_handling.py (1 hunks)
Additional comments not posted (2)
src/errors/error_msgs.h (1)

64-64: Confirm the addition of the new error message EMSG_EDGE_REDECLARATION for when an edge is declared more than once.

  • This change aligns with the PR's objective to improve error handling and messaging for edge variable redeclaration.
  • Ensure that the error message is consistently used across the codebase where applicable.
src/ast/ast_validations.c (1)

1670-1670: Ensure CALL {} clauses are non-returning when they are the last clause in a query.

The validation for CALL {} clauses being non-returning when they are the last clause in a query is crucial for query correctness. This shell script uses ast-grep to search for any CALL {} clauses that improperly include a RETURN statement, which should be manually reviewed to ensure compliance with the validation rules.

Verification successful

This script aims to find references to the handling or validation of CALL {} clauses within the C codebase, which could provide insights into how these clauses are ensured to be non-returning when they are the last clause in a query.


The review comment is supported by the evidence found in the script output, particularly within src/ast/ast_validations.c, which includes comments and logic related to ensuring CALL {} clauses are non-returning when they are the last clause in a query. This confirms the importance of the validation for query correctness as mentioned in the review comment.

Scripts Executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Check for CALL {} clauses that are the last clause and ensure they are non-returning.
ast-grep --lang cypher --pattern $'CALL {
  $$$
  RETURN($_)
}'

Length of output: 177



Script:

#!/bin/bash
# Search for references to 'CALL' clause handling or validation in C files.
rg "CALL.*\{.*\}" --type c

Length of output: 1931

q = "CREATE ()-[e:R]->()-[e:R]->()"
try:
self.g.query(q)
# should not reach this point
self.env.assertTrue(False)
except Exception as e:
self.env.assertTrue("Variable `e` already declared" in str(e))
self.env.assertTrue("Edge `e` can only be declared once" in str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the error message check to ensure it precisely matches the new standard error message for edge redeclaration.

- self.env.assertTrue("Edge `e` can only be declared once" in str(e))
+ self.env.assertTrue("Edge 'e' can only be declared once" in str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.env.assertTrue("Edge `e` can only be declared once" in str(e))
self.env.assertTrue("Edge 'e' can only be declared once" in str(e))

@@ -68,5 +67,5 @@ def test02_edge_reuse(self):
# should not reach this point
self.env.assertTrue(False)
except Exception as e:
self.env.assertTrue("The bound variable 'e' can't be redeclared in a CREATE clause" in str(e))
self.env.assertTrue("Edge `e` can only be declared once" in str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the error message check to ensure it precisely matches the new standard error message for edge redeclaration.

- self.env.assertTrue("Edge `e` can only be declared once" in str(e))
+ self.env.assertTrue("Edge 'e' can only be declared once" in str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.env.assertTrue("Edge `e` can only be declared once" in str(e))
self.env.assertTrue("Edge 'e' can only be declared once" in str(e))

Comment on lines 115 to 135
def test07_bound_edges(self):
# edges can only be declared once
# re-declaring a variable as an edge is forbidden

queries = ["MATCH ()-[e]->()-[e]->() RETURN *",
"MATCH ()-[e]->() MATCH ()<-[e]-() RETURN *",
"WITH NULL AS e MATCH ()-[e]->() RETURN *",
"MATCH ()-[e]->() WITH e MATCH ()-[e]->() RETURN *",
"MATCH ()-[e]->() MERGE ()-[e:R]->() RETURN *",
"WITH NULL AS e MERGE ()-[e:R]->() RETURN *",
"MERGE ()-[e:R]->() MERGE ()-[e:R]->()",
"MATCH ()-[e]->() WHERE ()-[e]->() RETURN *"]

for q in queries:
try:
res = self.g.query(q)
# should not reach this point
self.env.assertFalse(True)
except Exception as e:
self.env.assertIn("Edge `e` can only be declared once", str(e))

Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure the new test method test07_bound_edges correctly tests the constraints on edge declaration.

  • The test method is well-structured and covers various scenarios where edge redeclaration might occur.
  • The error message check within the exception handling should precisely match the new standard error message for edge redeclaration.

Consider refining the error message check to align with the new error message format.

- self.env.assertIn("Edge `e` can only be declared once", str(e))
+ self.env.assertIn("Edge 'e' can only be declared once", str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
def test07_bound_edges(self):
# edges can only be declared once
# re-declaring a variable as an edge is forbidden
queries = ["MATCH ()-[e]->()-[e]->() RETURN *",
"MATCH ()-[e]->() MATCH ()<-[e]-() RETURN *",
"WITH NULL AS e MATCH ()-[e]->() RETURN *",
"MATCH ()-[e]->() WITH e MATCH ()-[e]->() RETURN *",
"MATCH ()-[e]->() MERGE ()-[e:R]->() RETURN *",
"WITH NULL AS e MERGE ()-[e:R]->() RETURN *",
"MERGE ()-[e:R]->() MERGE ()-[e:R]->()",
"MATCH ()-[e]->() WHERE ()-[e]->() RETURN *"]
for q in queries:
try:
res = self.g.query(q)
# should not reach this point
self.env.assertFalse(True)
except Exception as e:
self.env.assertIn("Edge `e` can only be declared once", str(e))
def test07_bound_edges(self):
# edges can only be declared once
# re-declaring a variable as an edge is forbidden
queries = ["MATCH ()-[e]->()-[e]->() RETURN *",
"MATCH ()-[e]->() MATCH ()<-[e]-() RETURN *",
"WITH NULL AS e MATCH ()-[e]->() RETURN *",
"MATCH ()-[e]->() WITH e MATCH ()-[e]->() RETURN *",
"MATCH ()-[e]->() MERGE ()-[e:R]->() RETURN *",
"WITH NULL AS e MERGE ()-[e:R]->() RETURN *",
"MERGE ()-[e:R]->() MERGE ()-[e:R]->()",
"MATCH ()-[e]->() WHERE ()-[e]->() RETURN *"]
for q in queries:
try:
res = self.g.query(q)
# should not reach this point
self.env.assertFalse(True)
except Exception as e:
self.env.assertIn("Edge 'e' can only be declared once", str(e))

Comment on lines 99 to 105
try:
query = """WITH NULL AS e MATCH (a:L)-[e]->(b) RETURN a, e, b"""
plan = self.graph.explain(query)
# not expecting to reach this point
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("Edge `e` can only be declared once", str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the error message check to ensure it precisely matches the new standard error message for edge redeclaration.

- self.env.assertContains("Edge `e` can only be declared once", str(e))
+ self.env.assertContains("Edge 'e' can only be declared once", str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
try:
query = """WITH NULL AS e MATCH (a:L)-[e]->(b) RETURN a, e, b"""
plan = self.graph.explain(query)
# not expecting to reach this point
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("Edge `e` can only be declared once", str(e))
try:
query = """WITH NULL AS e MATCH (a:L)-[e]->(b) RETURN a, e, b"""
plan = self.graph.explain(query)
# not expecting to reach this point
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("Edge 'e' can only be declared once", str(e))

Comment on lines 137 to 145
"CREATE (n1)-[r:Rel1]->(n2), (n2)-[r:Rel1]->(n1)",
"CREATE (n1)-[r:Rel1]->(n2) CREATE (n2)-[r2:Rel1]->(n3), (n3)-[r:Rel1]->(n2)"]

for query in queries:
try:
self.graph.query(query)
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("The bound variable 'r' can't be redeclared in a CREATE clause", str(e))
self.env.assertContains("Edge `r` can only be declared once", str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the error message checks to ensure they precisely match the new standard error message for edge redeclaration.

- self.env.assertContains("Edge `r` can only be declared once", str(e))
+ self.env.assertContains("Edge 'r' can only be declared once", str(e))

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
"CREATE (n1)-[r:Rel1]->(n2), (n2)-[r:Rel1]->(n1)",
"CREATE (n1)-[r:Rel1]->(n2) CREATE (n2)-[r2:Rel1]->(n3), (n3)-[r:Rel1]->(n2)"]
for query in queries:
try:
self.graph.query(query)
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("The bound variable 'r' can't be redeclared in a CREATE clause", str(e))
self.env.assertContains("Edge `r` can only be declared once", str(e))
"CREATE (n1)-[r:Rel1]->(n2), (n2)-[r:Rel1]->(n1)",
"CREATE (n1)-[r:Rel1]->(n2) CREATE (n2)-[r2:Rel1]->(n3), (n3)-[r:Rel1]->(n2)"]
for query in queries:
try:
self.graph.query(query)
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("Edge 'r' can only be declared once", str(e))

try:
self.graph.query(query)
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertContains("Variable `r` already declared", str(e))
self.env.assertContains("The bound variable 'r' can't be redeclared in a CREATE clause", str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the error message check to ensure it precisely matches the new standard error message for variable redeclaration.

- self.env.assertContains("The bound variable 'r' can't be redeclared in a CREATE clause", str(e))
+ self.env.assertContains("The bound variable 'r' cannot be redeclared in a CREATE clause", str(e))

Note: This suggestion assumes that the error message standardization also applies to other variable redeclaration scenarios. If not, please disregard this comment.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.env.assertContains("The bound variable 'r' can't be redeclared in a CREATE clause", str(e))
self.env.assertContains("The bound variable 'r' cannot be redeclared in a CREATE clause", str(e))

Comment on lines 739 to 793
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
if(vctx->clause == CYPHER_AST_CREATE) {
// validate that the relation alias is not bound
if(_ValidateCreateRelation(n, vctx) == AST_INVALID) {
return VISITOR_BREAK;
}

// Validate that each relation has exactly one type
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
// extra validation when in a CREATE / MERGE clause
if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
// clause name used for error reporting
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ?
"CREATE" :
"MERGE";

// validate that each relation has exactly one type
if(reltype_count != 1) {
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "CREATE");
// CREATE ()-[:A:B]->()
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
return VISITOR_BREAK;
}

// Validate that each relation being created is directed
if(cypher_ast_rel_pattern_get_direction(n) == CYPHER_REL_BIDIRECTIONAL) {
// validate that each relation being created is directed
// CREATE ()-[]-()
if(dir == CYPHER_REL_BIDIRECTIONAL) {
ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
return VISITOR_BREAK;
}

// Validate that each relation being created is not variable length relationship
// validate that each relation being created is not of variable length
// CREATE ()-[*2..4]->()
if(range) {
ErrorCtx_SetError(EMSG_VAR_LEN, "CREATE");
ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
return VISITOR_BREAK;
}
}

if(_ValidateInlinedProperties(cypher_ast_rel_pattern_get_properties(n)) == AST_INVALID) {
return VISITOR_BREAK;
}

if(vctx->clause == CYPHER_AST_MERGE &&
_ValidateMergeRelation(n, vctx) == AST_INVALID) {
const cypher_astnode_t *props = cypher_ast_rel_pattern_get_properties(n);
if(_ValidateInlinedProperties(props) == AST_INVALID) {
return VISITOR_BREAK;
}

const cypher_astnode_t *alias_node = cypher_ast_rel_pattern_get_identifier(n);
if(!alias_node && !range) {
return VISITOR_RECURSE; // Skip unaliased, single-hop entities.
return VISITOR_RECURSE; // skip unaliased, single-hop entities
}

// If this is a multi-hop traversal, validate it accordingly
// if this is a multi-hop traversal, validate it accordingly
if(range && _ValidateMultiHopTraversal(n, range) == AST_INVALID) {
return VISITOR_BREAK;
}

if(alias_node) {
const char *alias = cypher_ast_identifier_get_name(alias_node);
void *alias_type = _IdentifiersFind(vctx, alias);
if(alias_type == raxNotFound) {
_IdentifierAdd(vctx, alias, (void*)T_EDGE);
return VISITOR_RECURSE;
}

if(alias_type != (void *)T_EDGE && alias_type != NULL) {
ErrorCtx_SetError(EMSG_SAME_ALIAS_NODE_RELATIONSHIP, alias);
return VISITOR_BREAK;
}
void *alias_type = _IdentifiersFind(vctx, alias);

if(vctx->clause == CYPHER_AST_MATCH && alias_type != NULL) {
ErrorCtx_SetError(EMSG_SAME_ALIAS_MULTIPLE_PATTERNS, alias);
// edge can not be redeclared
if(_IdentifierAdd(vctx, alias, (void*)T_EDGE) == 0) {
ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider refactoring _Validate_rel_pattern to improve readability and maintainability.

- if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
+ // Refactor into a separate function for clarity
+ if(_isCreateOrMergeClause(vctx->clause)) {

The function _Validate_rel_pattern is complex and handles multiple validation checks. Refactoring it by extracting some of its logic into smaller, more focused functions can improve readability and maintainability. For example, the checks specific to CREATE and MERGE clauses could be moved into a separate function. This would make the main function shorter and its purpose clearer.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
if(vctx->clause == CYPHER_AST_CREATE) {
// validate that the relation alias is not bound
if(_ValidateCreateRelation(n, vctx) == AST_INVALID) {
return VISITOR_BREAK;
}
// Validate that each relation has exactly one type
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
// extra validation when in a CREATE / MERGE clause
if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
// clause name used for error reporting
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ?
"CREATE" :
"MERGE";
// validate that each relation has exactly one type
if(reltype_count != 1) {
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "CREATE");
// CREATE ()-[:A:B]->()
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
return VISITOR_BREAK;
}
// Validate that each relation being created is directed
if(cypher_ast_rel_pattern_get_direction(n) == CYPHER_REL_BIDIRECTIONAL) {
// validate that each relation being created is directed
// CREATE ()-[]-()
if(dir == CYPHER_REL_BIDIRECTIONAL) {
ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
return VISITOR_BREAK;
}
// Validate that each relation being created is not variable length relationship
// validate that each relation being created is not of variable length
// CREATE ()-[*2..4]->()
if(range) {
ErrorCtx_SetError(EMSG_VAR_LEN, "CREATE");
ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
return VISITOR_BREAK;
}
}
if(_ValidateInlinedProperties(cypher_ast_rel_pattern_get_properties(n)) == AST_INVALID) {
return VISITOR_BREAK;
}
if(vctx->clause == CYPHER_AST_MERGE &&
_ValidateMergeRelation(n, vctx) == AST_INVALID) {
const cypher_astnode_t *props = cypher_ast_rel_pattern_get_properties(n);
if(_ValidateInlinedProperties(props) == AST_INVALID) {
return VISITOR_BREAK;
}
const cypher_astnode_t *alias_node = cypher_ast_rel_pattern_get_identifier(n);
if(!alias_node && !range) {
return VISITOR_RECURSE; // Skip unaliased, single-hop entities.
return VISITOR_RECURSE; // skip unaliased, single-hop entities
}
// If this is a multi-hop traversal, validate it accordingly
// if this is a multi-hop traversal, validate it accordingly
if(range && _ValidateMultiHopTraversal(n, range) == AST_INVALID) {
return VISITOR_BREAK;
}
if(alias_node) {
const char *alias = cypher_ast_identifier_get_name(alias_node);
void *alias_type = _IdentifiersFind(vctx, alias);
if(alias_type == raxNotFound) {
_IdentifierAdd(vctx, alias, (void*)T_EDGE);
return VISITOR_RECURSE;
}
if(alias_type != (void *)T_EDGE && alias_type != NULL) {
ErrorCtx_SetError(EMSG_SAME_ALIAS_NODE_RELATIONSHIP, alias);
return VISITOR_BREAK;
}
void *alias_type = _IdentifiersFind(vctx, alias);
if(vctx->clause == CYPHER_AST_MATCH && alias_type != NULL) {
ErrorCtx_SetError(EMSG_SAME_ALIAS_MULTIPLE_PATTERNS, alias);
// edge can not be redeclared
if(_IdentifierAdd(vctx, alias, (void*)T_EDGE) == 0) {
ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
// extra validation when in a CREATE / MERGE clause
if(_isCreateOrMergeClause(vctx->clause)) {
// clause name used for error reporting
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ?
"CREATE" :
"MERGE";
// validate that each relation has exactly one type
if(reltype_count != 1) {
// CREATE ()-[:A:B]->()
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
return VISITOR_BREAK;
}
// validate that each relation being created is directed
// CREATE ()-[]-()
if(dir == CYPHER_REL_BIDIRECTIONAL) {
ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
return VISITOR_BREAK;
}
// validate that each relation being created is not of variable length
// CREATE ()-[*2..4]->()
if(range) {
ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
return VISITOR_BREAK;
}
}
const cypher_astnode_t *props = cypher_ast_rel_pattern_get_properties(n);
if(_ValidateInlinedProperties(props) == AST_INVALID) {
return VISITOR_BREAK;
}
const cypher_astnode_t *alias_node = cypher_ast_rel_pattern_get_identifier(n);
if(!alias_node && !range) {
return VISITOR_RECURSE; // skip unaliased, single-hop entities
}
// if this is a multi-hop traversal, validate it accordingly
if(range && _ValidateMultiHopTraversal(n, range) == AST_INVALID) {
return VISITOR_BREAK;
}
if(alias_node) {
const char *alias = cypher_ast_identifier_get_name(alias_node);
void *alias_type = _IdentifiersFind(vctx, alias);
// edge can not be redeclared
if(_IdentifierAdd(vctx, alias, (void*)T_EDGE) == 0) {
ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);

@@ -250,7 +250,7 @@ static AST_Validation _ValidateMultiHopTraversal
end = AST_ParseIntegerNode(range_end);
}

// Validate specified range
// validate specified range
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure proper handling of negative range values in _ValidateMultiHopTraversal.

+ // Ensure start and end are non-negative
+ if(start < 0 || end < 0) {
+     ErrorCtx_SetError(EMSG_VAR_LEN_INVALID_RANGE);
+     return AST_INVALID;
+ }

The function _ValidateMultiHopTraversal currently checks if the start of the range is greater than the end, but it does not explicitly check for negative values. In Cypher, ranges should be non-negative. Adding a check for negative values would prevent potential issues with range specifications.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
// validate specified range
// validate specified range
+ // Ensure start and end are non-negative
+ if(start < 0 || end < 0) {
+ ErrorCtx_SetError(EMSG_VAR_LEN_INVALID_RANGE);
+ return AST_INVALID;
+ }

@@ -1729,7 +1667,7 @@ static VISITOR_STRATEGY _Validate_CREATE_Clause

// fail on duplicate identifier
if(_IdentifierAdd(vctx, alias, (void*)t) == 0 && t == T_EDGE) {
ErrorCtx_SetError(EMSG_VAIABLE_ALREADY_DECLARED, alias);
ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Avoid redeclaration of edges in CREATE clauses.

- ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);

The error handling for edge redeclaration within CREATE clauses is correctly placed. However, ensure that the logic preceding this error handling accurately identifies redeclarations and does not falsely trigger this error in valid scenarios.


Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);

@gkorland gkorland requested a review from AviAvni May 26, 2024 06:25
Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review Details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits Files that changed from the base of the PR and between c613605 and a5b3db3.
Files selected for processing (1)
  • src/ast/ast_validations.c (5 hunks)
Additional comments not posted (3)
src/ast/ast_validations.c (3)

739-793: Consider refactoring _Validate_rel_pattern to improve readability and maintainability.


1678-1678: Avoid redeclaration of edges in CREATE clauses.


253-253: Ensure proper handling of negative range values in _ValidateMultiHopTraversal.

Copy link

codecov bot commented May 26, 2024

Codecov Report

All modified and coverable lines are covered by tests ✅

Project coverage is 81.01%. Comparing base (b7f27c5) to head (0be9ca8).
Report is 2 commits behind head on master.

Additional details and impacted files
@@            Coverage Diff             @@
##           master     #498      +/-   ##
==========================================
- Coverage   81.04%   81.01%   -0.03%     
==========================================
  Files         313      313              
  Lines       31856    31826      -30     
  Branches     5113     5105       -8     
==========================================
- Hits        25818    25785      -33     
- Misses       5207     5210       +3     
  Partials      831      831              

☔ View full report in Codecov by Sentry.
📢 Have feedback on the report? Share it here.

ErrorCtx_SetError(EMSG_SAME_ALIAS_NODE_RELATIONSHIP, alias);
return VISITOR_BREAK;
}
void *alias_type = _IdentifiersFind(vctx, alias);
Copy link
Contributor

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

is this needed?

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Outside diff range and nitpick comments (1)
tests/flow/test_bound_variables.py (1)

Line range hint 1-1: Avoid using star imports as they can lead to undefined names.

- from common import *
- from index_utils import *
+ from common import Env, FlowTestsBase
+ from index_utils import create_node_fulltext_index

Also applies to: 2-2, 4-4, 8-8, 11-11

Tools
Ruff

8-8: FlowTestsBase may be undefined, or defined from star imports (F405)


11-11: Env may be undefined, or defined from star imports (F405)

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between a5b3db3 and eff8d1f.

Files selected for processing (2)
  • src/ast/ast_validations.c (5 hunks)
  • tests/flow/test_bound_variables.py (7 hunks)
Additional context used
Ruff
tests/flow/test_bound_variables.py

1-1: from common import * used; unable to detect undefined names (F403)


2-2: from index_utils import * used; unable to detect undefined names (F403)


4-4: sys may be undefined, or defined from star imports (F405)


4-4: os may be undefined, or defined from star imports (F405)


4-4: os may be undefined, or defined from star imports (F405)


8-8: FlowTestsBase may be undefined, or defined from star imports (F405)


11-11: Env may be undefined, or defined from star imports (F405)


22-22: Node may be undefined, or defined from star imports (F405)


27-27: Edge may be undefined, or defined from star imports (F405)


28-28: Edge may be undefined, or defined from star imports (F405)


58-58: create_node_fulltext_index may be undefined, or defined from star imports (F405)


130-130: Local variable res is assigned to but never used (F841)

Additional comments not posted (7)
tests/flow/test_bound_variables.py (6)

38-38: The check for Cartesian products is correctly implemented.


50-50: The checks for created nodes and relationships are correctly implemented.


60-65: The verification of the execution plan's order is correctly implemented.


79-84: The count of scan operations in the execution plan is correctly verified.


110-114: The verification of overriding a bound alias with a new scan is correctly implemented.


134-134: Refine the error message check to align with the new error message format.

- self.env.assertIn("Edge `e` can only be declared once", str(e))
+ self.env.assertIn("Edge 'e' can only be declared once", str(e))
src/ast/ast_validations.c (1)

790-791: Avoid redeclaration of edges in CREATE clauses.

The error handling for edge redeclaration within CREATE clauses is correctly placed. However, ensure that the logic preceding this error handling accurately identifies redeclarations and does not falsely trigger this error in valid scenarios.

Comment on lines 739 to 768
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
if(vctx->clause == CYPHER_AST_CREATE) {
// validate that the relation alias is not bound
if(_ValidateCreateRelation(n, vctx) == AST_INVALID) {
return VISITOR_BREAK;
}

// Validate that each relation has exactly one type
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
// extra validation when in a CREATE / MERGE clause
if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
// clause name used for error reporting
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ?
"CREATE" :
"MERGE";

// validate that each relation has exactly one type
if(reltype_count != 1) {
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "CREATE");
// CREATE ()-[:A:B]->()
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
return VISITOR_BREAK;
}

// Validate that each relation being created is directed
if(cypher_ast_rel_pattern_get_direction(n) == CYPHER_REL_BIDIRECTIONAL) {
// validate that each relation being created is directed
// CREATE ()-[]-()
if(dir == CYPHER_REL_BIDIRECTIONAL) {
ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
return VISITOR_BREAK;
}

// Validate that each relation being created is not variable length relationship
// validate that each relation being created is not of variable length
// CREATE ()-[*2..4]->()
if(range) {
ErrorCtx_SetError(EMSG_VAR_LEN, "CREATE");
ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Consider simplifying the validation logic for relation patterns.

The validation logic for relation patterns in CREATE and MERGE clauses is quite verbose and repetitive. Consider refactoring this into a helper function to check the conditions and set the error context. This would make the code cleaner and more maintainable.

- if(reltype_count != 1) {
-   ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
-   return VISITOR_BREAK;
- }
- if(dir == CYPHER_REL_BIDIRECTIONAL) {
-   ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
-   return VISITOR_BREAK;
- }
- if(range) {
-   ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
-   return VISITOR_BREAK;
- }
+ if (!validateRelationPattern(reltype_count, dir, range, clause_name)) {
+   return VISITOR_BREAK;
+ }

Committable suggestion was skipped due to low confidence.

@@ -20,6 +21,7 @@ def populate_graph(self):
for idx, v in enumerate(node_props):
node = Node(alias=f"n_{idx}", labels="L", properties={"val": v})
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Ensure that Node and Edge are defined or imported explicitly.

+ from graph_entities import Node, Edge

Also applies to: 27-28

Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
node = Node(alias=f"n_{idx}", labels="L", properties={"val": v})
+ from graph_entities import Node, Edge
node = Node(alias=f"n_{idx}", labels="L", properties={"val": v})
Tools
Ruff

22-22: Node may be undefined, or defined from star imports (F405)

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 2

Outside diff range and nitpick comments (1)
tests/flow/test_bound_variables.py (1)

Line range hint 1-1: Refactor to use explicit imports instead of star imports.

- from common import *
- from index_utils import *
+ from common import Env, Node, Edge
+ from index_utils import create_node_fulltext_index

This change will help avoid potential issues with undefined names and improve code clarity.

Also applies to: 2-2, 4-4, 8-8, 11-11, 22-22, 27-27, 28-28, 58-58

Tools
Ruff

8-8: FlowTestsBase may be undefined, or defined from star imports (F405)


11-11: Env may be undefined, or defined from star imports (F405)

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between a5b3db3 and eff8d1f.

Files selected for processing (2)
  • src/ast/ast_validations.c (5 hunks)
  • tests/flow/test_bound_variables.py (7 hunks)
Additional context used
Ruff
tests/flow/test_bound_variables.py

1-1: from common import * used; unable to detect undefined names (F403)


2-2: from index_utils import * used; unable to detect undefined names (F403)


4-4: sys may be undefined, or defined from star imports (F405)


4-4: os may be undefined, or defined from star imports (F405)


4-4: os may be undefined, or defined from star imports (F405)


8-8: FlowTestsBase may be undefined, or defined from star imports (F405)


11-11: Env may be undefined, or defined from star imports (F405)


22-22: Node may be undefined, or defined from star imports (F405)


27-27: Edge may be undefined, or defined from star imports (F405)


28-28: Edge may be undefined, or defined from star imports (F405)


58-58: create_node_fulltext_index may be undefined, or defined from star imports (F405)


130-130: Local variable res is assigned to but never used (F841)

Additional comments not posted (7)
tests/flow/test_bound_variables.py (6)

Line range hint 10-27: Setup in populate_graph method looks correct.

Tools
Ruff

22-22: Node may be undefined, or defined from star imports (F405)


27-27: Edge may be undefined, or defined from star imports (F405)


38-38: Check for Cartesian products is correctly implemented.


50-50: Creation and validation in test02_match_create_bound_variable are correctly implemented.


60-65: Integration of full-text index with MATCH pattern is correctly implemented.


79-84: Scanning and validation in test04_projected_scanned_entity are correctly implemented.


110-114: Alias override behavior in test06_override_bound_with_label is correctly implemented.

src/ast/ast_validations.c (1)

1676-1676: Ensure that the error handling for edge redeclaration is robust and covers all necessary scenarios.

Verification successful

Ensure that the error handling for edge redeclaration is robust and covers all necessary scenarios.

  • The definition of EMSG_EDGE_REDECLARATION is found in src/errors/error_msgs.h.
  • The usage of ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias); is found only in src/ast/ast_validations.c.

Given that the error handling for edge redeclaration is localized to src/ast/ast_validations.c, it appears to be correctly implemented within the context of this file. However, there are no other instances of this specific error handling across the codebase, which suggests that edge redeclaration errors are only managed within this specific validation function.

Scripts executed

The following scripts were executed for the analysis:


Script:

#!/bin/bash
# Description: Verify that edge redeclaration is handled correctly across all scenarios.

# Test: Search for edge redeclaration handling in all relevant files.
rg --type c $'ErrorCtx_SetError(EMSG_EDGE_REDECLARATION, alias);'

Length of output: 66



Script:

#!/bin/bash
# Description: Verify the definition and usage of EMSG_EDGE_REDECLARATION and ErrorCtx_SetError.

# Search for the definition of EMSG_EDGE_REDECLARATION
rg --type c 'EMSG_EDGE_REDECLARATION'

# Search for all usages of ErrorCtx_SetError
rg --type c 'ErrorCtx_SetError'

Length of output: 16195

Comment on lines 739 to 768
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
if(vctx->clause == CYPHER_AST_CREATE) {
// validate that the relation alias is not bound
if(_ValidateCreateRelation(n, vctx) == AST_INVALID) {
return VISITOR_BREAK;
}

// Validate that each relation has exactly one type
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
// extra validation when in a CREATE / MERGE clause
if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
// clause name used for error reporting
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ?
"CREATE" :
"MERGE";

// validate that each relation has exactly one type
if(reltype_count != 1) {
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "CREATE");
// CREATE ()-[:A:B]->()
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
return VISITOR_BREAK;
}

// Validate that each relation being created is directed
if(cypher_ast_rel_pattern_get_direction(n) == CYPHER_REL_BIDIRECTIONAL) {
// validate that each relation being created is directed
// CREATE ()-[]-()
if(dir == CYPHER_REL_BIDIRECTIONAL) {
ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
return VISITOR_BREAK;
}

// Validate that each relation being created is not variable length relationship
// validate that each relation being created is not of variable length
// CREATE ()-[*2..4]->()
if(range) {
ErrorCtx_SetError(EMSG_VAR_LEN, "CREATE");
ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refactor the validation logic for relation patterns to simplify and enhance readability.

- if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
-   const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ? "CREATE" : "MERGE";
-   if(reltype_count != 1) {
-     ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
-     return VISITOR_BREAK;
-   }
-   if(dir == CYPHER_REL_BIDIRECTIONAL) {
-     ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
-     return VISITOR_BREAK;
-   }
-   if(range) {
-     ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
-     return VISITOR_BREAK;
-   }
- }
+ // Simplify the conditional structure and reduce nesting
+ const char *clause_name = (vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) ? 
+                           (vctx->clause == CYPHER_AST_CREATE ? "CREATE" : "MERGE") : NULL;
+ if(clause_name) {
+   if(reltype_count != 1) ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
+   else if(dir == CYPHER_REL_BIDIRECTIONAL) ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
+   else if(range) ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
+   if(ErrorCtx_EncounteredError()) return VISITOR_BREAK;
+ }
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
if(vctx->clause == CYPHER_AST_CREATE) {
// validate that the relation alias is not bound
if(_ValidateCreateRelation(n, vctx) == AST_INVALID) {
return VISITOR_BREAK;
}
// Validate that each relation has exactly one type
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
// extra validation when in a CREATE / MERGE clause
if(vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) {
// clause name used for error reporting
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE) ?
"CREATE" :
"MERGE";
// validate that each relation has exactly one type
if(reltype_count != 1) {
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, "CREATE");
// CREATE ()-[:A:B]->()
ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
return VISITOR_BREAK;
}
// Validate that each relation being created is directed
if(cypher_ast_rel_pattern_get_direction(n) == CYPHER_REL_BIDIRECTIONAL) {
// validate that each relation being created is directed
// CREATE ()-[]-()
if(dir == CYPHER_REL_BIDIRECTIONAL) {
ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
return VISITOR_BREAK;
}
// Validate that each relation being created is not variable length relationship
// validate that each relation being created is not of variable length
// CREATE ()-[*2..4]->()
if(range) {
ErrorCtx_SetError(EMSG_VAR_LEN, "CREATE");
ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
uint reltype_count = cypher_ast_rel_pattern_nreltypes(n);
enum cypher_rel_direction dir = cypher_ast_rel_pattern_get_direction(n);
const cypher_astnode_t *range = cypher_ast_rel_pattern_get_varlength(n);
// extra validation when in a CREATE / MERGE clause
const char *clause_name = (vctx->clause == CYPHER_AST_CREATE || vctx->clause == CYPHER_AST_MERGE) ?
(vctx->clause == CYPHER_AST_CREATE ? "CREATE" : "MERGE") : NULL;
if(clause_name) {
if(reltype_count != 1) ErrorCtx_SetError(EMSG_ONE_RELATIONSHIP_TYPE, clause_name);
else if(dir == CYPHER_REL_BIDIRECTIONAL) ErrorCtx_SetError(EMSG_CREATE_DIRECTED_RELATIONSHIP);
else if(range) ErrorCtx_SetError(EMSG_VAR_LEN, clause_name);
if(ErrorCtx_EncounteredError()) return VISITOR_BREAK;
}

# should not reach this point
self.env.assertFalse(True)
except Exception as e:
self.env.assertIn("Edge `e` can only be declared once", str(e))
Copy link

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Refine the error message check to align with the new standard error message format.

- self.env.assertIn("Edge `e` can only be declared once", str(e))
+ self.env.assertIn("Edge 'e' can only be declared once", str(e))
Committable suggestion

‼️ IMPORTANT
Carefully review the code before committing. Ensure that it accurately replaces the highlighted code, contains no missing lines, and has no issues with indentation.

Suggested change
self.env.assertIn("Edge `e` can only be declared once", str(e))
self.env.assertIn("Edge 'e' can only be declared once", str(e))

Copy link

@coderabbitai coderabbitai bot left a comment

Choose a reason for hiding this comment

The reason will be displayed to describe this comment to others. Learn more.

Actionable comments posted: 0

Review details

Configuration used: CodeRabbit UI
Review profile: CHILL

Commits

Files that changed from the base of the PR and between eff8d1f and aaf7ba9.

Files selected for processing (5)
  • src/ast/ast_validations.c (5 hunks)
  • tests/flow/test_bound_variables.py (7 hunks)
  • tests/flow/test_create_clause.py (2 hunks)
  • tests/flow/test_graph_create.py (1 hunks)
  • tests/flow/test_null_handling.py (1 hunks)
Additional context used
Ruff
tests/flow/test_create_clause.py

1-1: from common import * used; unable to detect undefined names (F403)


2-2: from index_utils import * used; unable to detect undefined names (F403)


8-8: Env may be undefined, or defined from star imports (F405)

tests/flow/test_bound_variables.py

1-1: from common import * used; unable to detect undefined names (F403)


2-2: from index_utils import * used; unable to detect undefined names (F403)


4-4: sys may be undefined, or defined from star imports (F405)


4-4: os may be undefined, or defined from star imports (F405)


4-4: os may be undefined, or defined from star imports (F405)


8-8: FlowTestsBase may be undefined, or defined from star imports (F405)


11-11: Env may be undefined, or defined from star imports (F405)


22-22: Node may be undefined, or defined from star imports (F405)


27-27: Edge may be undefined, or defined from star imports (F405)


28-28: Edge may be undefined, or defined from star imports (F405)


58-58: create_node_fulltext_index may be undefined, or defined from star imports (F405)


130-130: Local variable res is assigned to but never used (F841)

tests/flow/test_null_handling.py

1-1: from common import * used; unable to detect undefined names (F403)


5-5: FlowTestsBase may be undefined, or defined from star imports (F405)


7-7: Env may be undefined, or defined from star imports (F405)


21-21: redis may be undefined, or defined from star imports (F405)


29-29: redis may be undefined, or defined from star imports (F405)


39-39: redis may be undefined, or defined from star imports (F405)


47-47: redis may be undefined, or defined from star imports (F405)


104-104: redis may be undefined, or defined from star imports (F405)

tests/flow/test_graph_create.py

1-1: from common import * used; unable to detect undefined names (F403)


5-5: FlowTestsBase may be undefined, or defined from star imports (F405)


7-7: Env may be undefined, or defined from star imports (F405)


50-50: Node may be undefined, or defined from star imports (F405)


74-74: redis may be undefined, or defined from star imports (F405)


105-105: redis may be undefined, or defined from star imports (F405)


144-144: redis may be undefined, or defined from star imports (F405)


151-151: redis may be undefined, or defined from star imports (F405)

Additional comments not posted (4)
tests/flow/test_create_clause.py (1)

59-59: Refine the error message check to ensure it precisely matches the new standard error message for edge redeclaration.

- self.env.assertTrue("The bound edge 'e' can't be redeclared in a CREATE clause" in str(e))
+ self.env.assertTrue("Edge 'e' can only be declared once" in str(e))

Also applies to: 70-70

tests/flow/test_bound_variables.py (1)

134-134: Refine the error message check to align with the new standard error message format.

- self.env.assertIn("The bound edge 'e' can't be redeclared in a MERGE clause", str(e))
+ self.env.assertIn("Edge 'e' can only be declared once", str(e))
src/ast/ast_validations.c (2)

739-768: Refined validation logic for relation patterns in CREATE and MERGE clauses.

The changes correctly implement additional checks for relation types, ensuring each relation has exactly one type and is directed, and that variable-length relations are not allowed in CREATE and MERGE clauses. This aligns with the PR objectives to prevent incorrect usage of edge variables in multiple MATCH clauses.


1677-1677: Ensure proper error handling when redeclaring an edge in a CREATE clause.

The addition of an error message when an edge is redeclared in a CREATE clause is a good practice. It prevents potential conflicts or logical errors in graph database operations, aligning with the overall goal of enhancing query validation.

Sign up for free to join this conversation on GitHub. Already have an account? Sign in to comment
Labels
None yet
Projects
None yet
Development

Successfully merging this pull request may close these issues.

Crash encountered about same relationship variable in pattern
3 participants