1

I use hiredis library in my c++ code to execute RedisGraph commands. When I try to execute 'create' command in c++ code it throws an error, but when i execute exactly the same command in command line it works fine. What's going on? Maybe i do something wrong? Redis server version is 4.0.9, here is my code in c++:

#include <iostream>
#include <cstdint>
#include <cstring>
#include <hiredis.h>
using namespace std;
int main(int argc, char** argv) {
    unsigned int j, isunix = 0;
    redisContext *c;
    redisReply *reply;
    const char *hostname = (argc > 1) ? argv[1] : "127.0.0.1";
    int port = (argc > 2) ? atoi(argv[2]) : 6379;
    struct timeval timeout = { 1, 500000 }; // 1.5 seconds
    if (isunix) {
        c = redisConnectUnixWithTimeout(hostname, timeout);
    } else {
        c = redisConnectWithTimeout(hostname, port, timeout);
    }
    if (c == NULL || c->err) {
        if (c) {
            printf("Connection error: %s\n", c->errstr);
            redisFree(c);
        } else {
            printf("Connection error: can't allocate redis context\n");
        }
    }
    const char * destPtr = "GRAPH.QUERY Project \"CREATE (:User {userId:9})\"";
    std::cout<<destPtr<<std::endl;
    reply = (redisReply *)redisCommand(c,destPtr);
    //
    printf(reply->str);
   freeReplyObject(reply);
    return 0;
}

It throws this error:

Syntax error at offset 8 near 'CREATE'
BigNoob
  • 11
  • 1
  • I've never seen any Redis commands that look like that, so I can't response to that. But can you get much simpler commands to work first? Change to something simple like "SET foo 1". Does that work? – Joseph Larson Dec 02 '19 at 15:51
  • because it's not simple Redis, it's Redis Graph module. If you don't know, here is the link: https://oss.redislabs.com/redisgraph/ – BigNoob Dec 02 '19 at 15:56
  • when i execute command "set foo 1" in c++, it works fine – BigNoob Dec 02 '19 at 15:57
  • I don't think hiredis will be able to parse the redisgraph queries. It is client library for redis not redisgraph. Supported client libraries for redisgraph. https://oss.redislabs.com/redisgraph/clients/ Nothing for c/c++. You can look into python library and see how they are parsing the redisgraph queries and turns into redis commands. Or, start calling python function from c++. The other option is to look into libredis. You need something in c/c++ which will send raw commands to redis. I think libredis also do some sort of parsing and it may not understand the redisgraph queries. – Icarus3 Dec 02 '19 at 17:51

2 Answers2

1

haven't tried this, but worth a shot:

reply = (redisReply *)redisCommand(c, "GRAPH.QUERY key:%s %s", "Project", "CREATE (:User {userId:9})");

https://github.com/redis/hiredis#sending-commands

SWilly22
  • 869
  • 4
  • 5
0

I cross the information of @SWilly22 and by reading the structure of replyRedis, I discover that it's possible to do RedisGraph queries by using hiredis. Here's how, by an example code using the example Graph Query of the REAMDE's RedisGraph Project. This is the query to create the example :

GRAPH.QUERY MotoGP "CREATE (:Rider {name:'Valentino Rossi'})-[:rides]->(:Team {name:'Yamaha'}), (:Rider {name:'Dani Pedrosa'})-[:rides]->(:Team {name:'Honda'}), (:Rider {name:'Andrea Dovizioso'})-[:rides]->(:Team {name:'Ducati'})"

Here is the query that we want to execute with hiredis :

GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team {name:'Ducati'}) RETURN count(r)"

So here's an example of how to do it in C by using hiredis :

#include <hiredis/hiredis.h>
#include <stdlib.h>
#include <stdio.h>

#define REDIS_CONTEXT       redisContext *context = redisConnect("127.0.0.1", 6379);\
                if (context == NULL || context->err) {\
                    if (context) {\
                    printf("Error: %s\n", context->errstr);\
                    return -3;\
                    } else {\
                    printf("Can't allocate redis context\n");\
                    return -4;\
                    }\
                } else printf("connected!\n");

int
main(void) {

    REDIS_CONTEXT;  
    redisReply *reply = redisCommand(context, "GRAPH.QUERY MotoGP %s", "MATCH (r:Rider)-[:rides]->(t:Team {name:'Ducati'}) RETURN count(r)");
    /* Note : you can also try this Query the result is on the readme project
     * RedisGraph and gives you aproximatively the same response. */
    //redisReply *reply = redisCommand(context, "GRAPH.QUERY MotoGP %s", "MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, t.name");
    if( reply == NULL )
        return 1;
    for(int i=0; i<reply->elements; i++) {
        printf("\tstr\t:%s#\n",reply->element[i]->str);
        printf("\ttype\t:%d#\n",reply->element[i]->type);
        printf("\tinteger\t:%llu#\n",reply->element[i]->integer);
        printf("\tdval\t:%f#\n",reply->element[i]->dval);
        printf("\tlen\t:%zu#\n",reply->element[i]->len);
        printf("\tvtype\t:%s#\n",reply->element[i]->vtype);
        printf("\telements\t:%zu#\n",reply->element[i]->elements);

        for(int j=0; j<reply->element[i]->elements; j++)
            switch( reply->element[i]->element[j]->type ) {
            case REDIS_REPLY_STRING :
                printf("\t\tstr:%s\n",reply->element[i]->element[j]->str);
                break;
            case REDIS_REPLY_INTEGER :
                printf("\t\tinteger:%lld\n",reply->element[i]->element[j]->integer);
                break;
            case REDIS_REPLY_ARRAY : 
                printf("\t\t{\n");
                for(int k=0; k<reply->element[i]->element[j]->elements; k++)
                    switch( reply->element[i]->element[j]->element[k]->type ) {
                    case REDIS_REPLY_STRING :
                        printf("\t\t\t>str:%s\n",reply->element[i]->element[j]->element[k]->str);
                        break;
                    case REDIS_REPLY_INTEGER :
                        printf("\t\t\t>integer:%lld\n",reply->element[i]->element[j]->element[k]->integer);
                        break;
                    default:
                        continue;
                    }
                printf("\t\t{\n");
                break;
            default:
                continue;
            }

        printf("---------------------------\n");
    }
    return 0;
}

Here's the result:

        str     :(null)#
        type    :2#
        integer :0#
        dval    :0.000000#
        len     :0#
        vtype   :#
        elements        :1#
                str:count(r)
---------------------------
        str     :(null)#
        type    :2#
        integer :0#
        dval    :0.000000#
        len     :0#
        vtype   :#
        elements        :1#
                {
                        >integer:1
                {
---------------------------
        str     :(null)#
        type    :2#
        integer :0#
        dval    :0.000000#
        len     :0#
        vtype   :#
        elements        :2#
                str:Cached execution: 1
                str:Query internal execution time: 0.856161 milliseconds
---------------------------

Explanation

Here's the struct redisReply :

/* This is the reply object returned by redisCommand() */
typedef struct redisReply {
    int type; /* REDIS_REPLY_* */
    long long integer; /* The integer when type is REDIS_REPLY_INTEGER */
    double dval; /* The double when type is REDIS_REPLY_DOUBLE */
    size_t len; /* Length of string */
    char *str; /* Used for REDIS_REPLY_ERROR, REDIS_REPLY_STRING
                  REDIS_REPLY_VERB, REDIS_REPLY_DOUBLE (in additional to dval),
                  and REDIS_REPLY_BIGNUM. */
    char vtype[4]; /* Used for REDIS_REPLY_VERB, contains the null
                      terminated 3 character content type, such as "txt". */
    size_t elements; /* number of elements, for REDIS_REPLY_ARRAY */
    struct redisReply **element; /* elements vector for REDIS_REPLY_ARRAY */
} redisReply;

And here's what you obtain with redis-cli :

127.0.0.1:6379> GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team {name:'Ducati'}) RETURN count(r)"
1) 1) "count(r)"
2) 1) 1) (integer) 1
3) 1) "Query internal execution time: 0.624435 milliseconds"

So by analysing the redis-cli reply we can see that we have three elements named 1,2 and 3. Each of them are of type : REDIS_REPLY_ARRAY. So now we can enterred in each arrays. In the array called 1 we have one element of type : REDIS_REPLY_STRING its value is "count(r)".

another example

for the query :

GRAPH.QUERY MotoGP "MATCH (r:Rider)-[:rides]->(t:Team) WHERE t.name = 'Yamaha' RETURN r.name, t.name"

by uncommenting the second query in the main function you can have this results :

connected!
        str     :(null)#
        type    :2#
        integer :0#
        dval    :0.000000#
        len     :0#
        vtype   :#
        elements        :2#
                str:r.name
                str:t.name
---------------------------
        str     :(null)#
        type    :2#
        integer :0#
        dval    :0.000000#
        len     :0#
        vtype   :#
        elements        :1#
                {
                        >str:Valentino Rossi
                        >str:Yamaha
                {
---------------------------
        str     :(null)#
        type    :2#
        integer :0#
        dval    :0.000000#
        len     :0#
        vtype   :#
        elements        :2#
                str:Cached execution: 1
                str:Query internal execution time: 0.827074 milliseconds
---------------------------

Which correspond to the readme one :

1) 1) "r.name"
   2) "t.name"
2) 1) 1) "Valentino Rossi"
      2) "Yamaha"
3) 1) "Query internal execution time: 0.625399 milliseconds"

NB : this algorithm is provide under "ASIS" please do not use it in production mode