1

There is very limited information regarding the usage of Redisql module with C#.

I am using StackExchange.Redis nuget package v2.2.4 to connect Redis v5.0.7 with Redisql module installed. I am developing .NET 5 C# Application that connects and create a database and a table with predefined values.

Below is the code block that works fine and as expected.

    ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect("127.0.0.1:6380");
    IDatabase conn = muxer.GetDatabase();

    conn.Execute("DEL", "DB");

    conn.Execute("REDISQL.CREATE_DB", "DB");
    conn.Execute("REDISQL.EXEC", "DB", "CREATE TABLE TABLE1(A INT, B TEXT);");
    conn.Execute("REDISQL.EXEC", "DB" ,"INSERT INTO TABLE1 VALUES(1, 'Value1');");
    conn.Execute("REDISQL.EXEC", "DB" ,"INSERT INTO TABLE1 VALUES(2, 'Value2');");
    var res = conn.Execute("REDISQL.EXEC", "DB", "SELECT * FROM TABLE1");

But what i want to do is to execute insert statements with db parameters instead of providing the values directly in the sql statements. As there is literally no examples or documentations on that I cannot find a way to do that.

I tried to rewrite the insert statement as below but it gives and error

conn.Execute("REDISQL.EXEC", "DB", "INSERT INTO TABLE1 VALUES(?1, ?2);", 1, "Value1");

StackExchange.Redis.RedisServerException: "Wrong number of arguments, it accepts 3, you provide 5" at StackExchange.Redis.ConnectionMultiplexer.ExecuteSyncImpl[T](Message message, ResultProcessor1 processor, ServerEndPoint server) in /_/src/StackExchange.Redis/ConnectionMultiplexer.cs:line 2817\n at StackExchange.Redis.RedisBase.ExecuteSync[T](Message message, ResultProcessor1 processor, ServerEndPoint server) in //src/StackExchange.Redis/RedisBase.cs:line 54\n at StackExchange.Redis.RedisDatabase.Execute(String command, ICollection`1 args, CommandFlags flags) in //src/StackExchange.Redis/RedisDatabase.cs:line 1204\n at StackExchange.Redis.RedisDatabase.Execute(String command, Object[] args) in /_/src/StackExchange.Redis/RedisDatabase.cs:line 1200\n at deneme.Program.Main(String[] args) in /Users/serhatonal/Projects/deneme/deneme/Program.cs:23

After that I changed the script as follows

        ConnectionMultiplexer muxer = ConnectionMultiplexer.Connect("127.0.0.1:6380");
        IDatabase conn = muxer.GetDatabase();

        conn.Execute("DEL", "DB");

        conn.Execute("REDISQL.CREATE_DB", "DB");
        conn.Execute("REDISQL.EXEC", "DB", "CREATE TABLE TABLE1(A INT, B TEXT);");
        
        conn.Execute("REDISQL.CREATE_STATEMENT", "DB", "INSERTINTOTABLE1STMT", "INSERT INTO TABLE1 VALUES(?1,?2)");

        conn.Execute("REDISQL.EXEC_STATEMENT", "DB", "INSERTINTOTABLE1STMT", 1, "Value1" );
        conn.Execute("REDISQL.EXEC_STATEMENT", "DB", "INSERTINTOTABLE1STMT", 2, "Value2");

        var res = conn.Execute("REDISQL.EXEC", "DB", "SELECT * FROM TABLE1");

It gives below error while executing REDISQL.CREATE_STATEMENT line as described in the documentation https://redisql.redbeardlab.com/references/#redisqlexec_statement

System.ArgumentOutOfRangeException: "Specified argument was out of the range of valid values. (Parameter 'Command 'REDISQL.CREATE_STATEMENT' exceeds library limit of 23 bytes')" at StackExchange.Redis.CommandBytes..ctor(String value) in //src/StackExchange.Redis/CommandBytes.cs:line 109\n at StackExchange.Redis.CommandMap.GetBytes(String command) in >//src/StackExchange.Redis/CommandMap.cs:line 181\n at >StackExchange.Redis.RedisDatabase.ExecuteMessage..ctor(CommandMap map, >Int32 db, CommandFlags flags, String command, ICollection1 args) in >/_/src/StackExchange.Redis/RedisDatabase.cs:line 3720\n at >StackExchange.Redis.RedisDatabase.Execute(String command, ICollection1 >args, CommandFlags flags) in >//src/StackExchange.Redis/RedisDatabase.cs:line 1203\n at >StackExchange.Redis.RedisDatabase.Execute(String command, Object[] args) >in //src/StackExchange.Redis/RedisDatabase.cs:line 1200\n at >deneme.Program.Main(String[] args) in >/Users/serhatonal/Projects/deneme/deneme/Program.cs:23

In our realtime scenario we have many sqls that uses multiple type parameters so it is not elegant to continue with sql including parameters as strings.

Any help is appreciated

Serhat Önal
  • 63
  • 1
  • 8

2 Answers2

1

From the error message, it sounds like redisql doesn't accept parameters, so: you'll probably need to inline the values yourself, taking care to avoid SQL injection. That's a topic for the module vendor.

Re the 23-byte limit: interesting that this is the first time I've seen this overflown, but: yes, we can increase that. Sorry.

Marc Gravell
  • 1,026,079
  • 266
  • 2,566
  • 2,900
  • 1
    Thanks @Marc.Gravell I also opened up an issue on https://github.com/StackExchange/StackExchange.Redis/issues/1692 – Serhat Önal Feb 19 '21 at 06:04
1

Simone from RediSQL.

So, you are right about pretty much anything.

RediSQL V1 does not support passing arguments to the EXEC, it was my mistake, and it is a bad design. Fortunately we moved on with RediSQL V2 which support passing arguments to the EXECs.

Your solution to create a statement is the correct one. Statements are suppose to be used when you want to repeat, multiple times, the same query, each time with different arguments.

So you are definitely on a good track.

The second problem is due to StackExchange own limit. Here there is no much we do about.

They are storing the command in a 3 ulongs for fast memory allocation: https://github.com/StackExchange/StackExchange.Redis/blob/main/src/StackExchange.Redis/CommandBytes.cs#L28

It turns out to be (3 * 8) - 1 = 23 bytes and REDISQL.CREATE_STATEMENT is 24 bytes. It does not fit.

Solution to this problem would be to rename the REDISQL.CREATE_STATEMENT into something like REDISQL.NEW_STATEMENT, you can rename Redis commands adding something like this in your config:

rename-command REDISQL.CREATE_STATEMENT REDISQL.NEW_STATEMENT

I understand it is a cumbersome process, but it is the only solution I see.

I would really suggest moving to RediSQL V2 or zeeSQL (https://zeesql.com and documentation in https://doc.zeesql.com).

It would have made these two problem disappears.

Sorry for not answering earlier, but I didn't receive the notification. I believe I fix them now.

Siscia
  • 1,421
  • 1
  • 12
  • 29
  • 1
    We'll fix the 23 byte limit ASAP, btw – Marc Gravell Feb 21 '21 at 11:00
  • @Siscia actually current problem seems to be related with 23 byte limit in StackExchange. I would prefer to wait for the fix instead of switching to Zeesql for now. – Serhat Önal Feb 21 '21 at 15:01
  • 1
    @SerhatÖnal sure, it makes completely sense. The advantages of zeeSQL are mentioned in this page: https://doc.zeesql.com/why-migrate zeeSQL allows secondary indexes, JSON return set, to pass arguments to query, and it is maintained. Beside keeping backward compatibility. – Siscia Feb 21 '21 at 18:31
  • @MarcGravell Elasticache engine version 5.0.6, having 23 byte issue. Trying to follow this https://stackexchange.github.io/StackExchange.Redis/KeysScan.html – T.S. Jul 25 '23 at 23:41
  • @T.S. those two topics are very different; you shouldn't hit any command-length issue with keys/scan, because those are 4 bytes! re 23 bytes: that was upped to 31 bytes well over two years ago, so all I can say there is: check what version of SE.Redis you're using, because it sounds like you have an old one (I can't tell anything from Elasticache engine version number) – Marc Gravell Jul 26 '23 at 08:47
  • @MarcGravell ok. my point was, I had a command like `--scan --pattern '[guid]*'` and it was giving error to me. I solved using key iteration from that page ^^. Will need to find somehow real version number. did not see it in the web console – T.S. Jul 26 '23 at 12:32
  • @T.S. that's not a command; that's a command *and arguments* - or that could even be a redis-cli feature? but: not a command – Marc Gravell Jul 26 '23 at 15:14
  • @MarcGravell I tried to execute it via raw execute with `stackexchange.redis.execute()`. For example `RedisResult reply = db.Execute("PING");` works. BTW `[guid]` above was literally full guid value. – T.S. Jul 26 '23 at 17:48
  • @T.S. I hear you; just: there is no command that looks like that... redis commands don't follow the `--scan` etc pattern; I think you're confusing a redis-cli feature with raw redis commands; just because redis-cli can do a thing: doesn't mean it is a single inbuilt redis command; where have you seen this `--scan --pattern` thing mentioned *like that*? If you just want to scan the DB from SE.Redis: then the link you already linked: is how to do that – Marc Gravell Jul 27 '23 at 16:42
  • @MarcGravell Thanks. I found that command somewhere on the pages of stackoverflow. I am good now. Works! – T.S. Jul 27 '23 at 22:22
  • @MarcGravell you asked "where I saw it?" here https://stackoverflow.com/a/61607308/1704458 – T.S. Jul 28 '23 at 17:08
  • @T.S. and as I guessed: that's a redis-cli feature; basically, redis-cli is unrolling that into a *series* of `SCAN` operations - multiple commands; it isn't a single redis command; however, SE.Redis *does the exact same thing* - when you use the approach in the page you linked to ages ago, about "where are keys/scan/etc" – Marc Gravell Jul 29 '23 at 14:28