From ed22e52ed1182ffb9f2b6b6959685e9e8e9b5b83 Mon Sep 17 00:00:00 2001 From: Roi Lipman Date: Tue, 18 Feb 2020 14:43:37 +0200 Subject: [PATCH] RediSearch query error reporting (#925) --- docs/commands.md | 2 +- src/procedures/proc_fulltext_query.c | 13 +++++++++++++ src/value.c | 2 +- tests/flow/test_procedures.py | 10 +++++++++- 4 files changed, 24 insertions(+), 3 deletions(-) diff --git a/docs/commands.md b/docs/commands.md index 1f62988401..4a7d7a43d9 100644 --- a/docs/commands.md +++ b/docs/commands.md @@ -660,7 +660,7 @@ GRAPH.QUERY DEMO_GRAPH "DROP INDEX ON :person(age)" ## Full-text indexes -RedisGraph leverages the indexing capabilities of RediSearch to provide full-text indexes through procedure calls. To construct a full-text index on the `title` property of all nodes with label `movie`, use the syntax: +RedisGraph leverages the indexing capabilities of [RediSearch](https://oss.redislabs.com/redisearch/index.html) to provide full-text indices through procedure calls. To construct a full-text index on the `title` property of all nodes with label `movie`, use the syntax: ```sh GRAPH.QUERY DEMO_GRAPH "CALL db.idx.fulltext.createNodeIndex('movie', 'title')" diff --git a/src/procedures/proc_fulltext_query.c b/src/procedures/proc_fulltext_query.c index c425df148c..0025ff7515 100644 --- a/src/procedures/proc_fulltext_query.c +++ b/src/procedures/proc_fulltext_query.c @@ -55,6 +55,19 @@ ProcedureResult Proc_FulltextQueryNodeInvoke(ProcedureCtx *ctx, const SIValue *a // Execute query pdata->iter = Index_Query(pdata->idx, query, &err); + // Raise runtime exception if err != NULL. + if(err) { + /* RediSearch error message is allocated using `rm_strdup` + * QueryCtx is expecting to free `error` using `free` + * in which case we have no option but to clone error. */ + char *error; + asprintf(&error, "RediSearch: %s", err); + rm_free(err); + QueryCtx_SetError(error); + /* Raise the exception, we expect an exception handler to be set. + * as procedure invocation is done at runtime. */ + QueryCtx_RaiseRuntimeException(); + } assert(pdata->iter); ctx->privateData = pdata; diff --git a/src/value.c b/src/value.c index 50107e69d3..ba0cb0176b 100644 --- a/src/value.c +++ b/src/value.c @@ -398,7 +398,7 @@ SIValue SIValue_Modulo(const SIValue a, const SIValue n) { case true: // The modulo machine instruction may be used if a and n are both integers. return SI_LongVal(a.longval % n.longval); - case false: + default: // Otherwise, use the library function fmod to calculate the modulo and return a double. return SI_DoubleVal(fmod(SI_GET_NUMERIC(a), SI_GET_NUMERIC(n))); } diff --git a/tests/flow/test_procedures.py b/tests/flow/test_procedures.py index 561fc8c3c7..67fe6cddfd 100644 --- a/tests/flow/test_procedures.py +++ b/tests/flow/test_procedures.py @@ -286,4 +286,12 @@ def test_procedure_propertyKeys(self): actual_resultset = redis_graph.call_procedure("db.propertyKeys").result_set expected_results = [["name"], ["value"]] self.env.assertEquals(actual_resultset, expected_results) - \ No newline at end of file + + def test_procedure_fulltext_syntax_error(self): + try: + query = """CALL db.idx.fulltext.queryNodes('fruit', 'Orange || Apple') YIELD node RETURN node""" + redis_graph.query(query) + assert(False) + except redis.exceptions.ResponseError: + # Expecting an error. + pass