Don't attempt to access non-existent properties by jeffreylovitz · Pull Request #1495 · RedisGraph/RedisGraph · GitHub
Skip to content
Merged
Show file tree
Hide file tree
Changes from all commits
Commits
File filter

Filter by extension

Filter by extension

Conversations
Failed to load comments.
Loading
Jump to
Jump to file
Failed to load files.
Loading
Diff view
Diff view
1 change: 0 additions & 1 deletion docs/known_limitations.md
4 changes: 4 additions & 0 deletions src/execution_plan/ops/shared/create_functions.c
Original file line number Diff line number Diff line change
Expand Up @@ -164,6 +164,10 @@ PendingProperties *ConvertPropertyMap(Record r, PropertyMap *map, bool fail_on_n
PendingProperties *converted = rm_malloc(sizeof(PendingProperties));
converted->values = rm_malloc(sizeof(SIValue) * map->property_count);
for(int i = 0; i < map->property_count; i++) {
/* Note that AR_EXP_Evaluate may raise a run-time exception, in which case
* the allocations in this function will be memory leaks.
* For example, this occurs in the query:
* CREATE (a {val: 2}), (b {val: a.val}) */
SIValue val = AR_EXP_Evaluate(map->values[i], r);
if(!(SI_TYPE(val) & SI_VALID_PROPERTY_VALUE)) {
// This value is of an invalid type.
Expand Down
8 changes: 8 additions & 0 deletions src/graph/entities/graph_entity.c
Original file line number Diff line number Diff line change
Expand Up @@ -68,6 +68,14 @@ SIValue *GraphEntity_AddProperty(GraphEntity *e, Attribute_ID attr_id, SIValue v

SIValue *GraphEntity_GetProperty(const GraphEntity *e, Attribute_ID attr_id) {
if(attr_id == ATTRIBUTE_NOTFOUND) return PROPERTY_NOTFOUND;
if(e->entity == NULL) {
/* The internal entity pointer should only be NULL if the entity
* is in an intermediate state, such as a node scheduled for creation.
* Note that this exception may cause memory to be leaked in the caller. */
ASSERT(e->id == INVALID_ENTITY_ID);
ErrorCtx_SetError("Attempted to access undefined property");
return PROPERTY_NOTFOUND;
}

for(int i = 0; i < e->entity->prop_count; i++) {
if(attr_id == e->entity->properties[i].id) {
Expand Down
14 changes: 14 additions & 0 deletions tests/flow/test_graph_create.py
Original file line number Diff line number Diff line change
@@ -1,5 +1,6 @@
import os
import sys
import redis
from RLTest import Env
from redisgraph import Graph, Node, Edge

Expand Down Expand Up @@ -65,3 +66,16 @@ def test04_create_with_null_properties(self):
result = redis_graph.query(query)
self.env.assertEquals(result.nodes_created, 2)
self.env.assertEquals(result.properties_set, 1)

def test05_create_with_property_reference(self):
# Skip this test if running under Valgrind, as it causes a memory leak.
if Env().envRunner.debugger is not None:
Env().skip()

# Queries that reference properties before they have been created should emit an error.
try:
query = """CREATE (a {val: 2}), (b {val: a.val})"""
redis_graph.query(query)
self.env.assertTrue(False)
except redis.exceptions.ResponseError as e:
self.env.assertIn("undefined property", e.message)
13 changes: 13 additions & 0 deletions tests/flow/test_graph_merge.py
Original file line number Diff line number Diff line change
Expand Up @@ -545,6 +545,10 @@ def test26_merge_set_invalid_property(self):
self.env.assertEquals(result.properties_set, 0)

def test27_merge_create_invalid_entity(self):
# Skip this test if running under Valgrind, as it causes a memory leak.
if Env().envRunner.debugger is not None:
Env().skip()

redis_con = self.env.getConnection()
graph = Graph("N", redis_con) # Instantiate a new graph.

Expand All @@ -562,3 +566,12 @@ def test27_merge_create_invalid_entity(self):
query = """MATCH (a) RETURN a"""
result = graph.query(query)
self.env.assertEquals(result.result_set, [])

try:
# Try to merge a node with a self-referential property.
query = """MERGE (a:L {v: a.v})"""
graph.query(query)
assert(False)
except redis.exceptions.ResponseError as e:
# Expecting an error.
self.env.assertIn("undefined property", e.message)
19 changes: 19 additions & 0 deletions tests/flow/test_query_validation.py