15

When I run this code through redis EVAL it return no results. Any idea why this is not working?

redis-cli EVAL "$(cat bug.lua)" 0

bug.lua

local retv = {}
retv["test"] = 1000

return retv

If I initialize the table that value alone gets printed.

$ cat bug.lua 
--!/usr/bin/env lua


local retv = {"This", "is", "a", "bug" }
retv["test"] = 1000

return retv

$ redis-cli EVAL "$(cat bug.lua)" 2 a b
1) "This"
2) "is"
3) "a"
4) "bug"
vivekv
  • 2,238
  • 3
  • 23
  • 37
  • does your actual command have a closing quote before the 0? wont' work without it, wondering if typo or real – Oliver Jun 19 '14 at 06:58
  • Yes you are right. It is just a typo here. I have it right on the command line. Fixing the question. Thanks for pointing it out. – vivekv Jun 19 '14 at 06:58
  • does it work if bug.lua has `local msg = "hi"; return msg`? do you get an error message if you cat a file that does not exist? You are returning a reference to the table, not a string representation of the table, does Redis know how to display the reference (a pointer, essentially)? – Oliver Jun 19 '14 at 07:08
  • Lua interpreter works fine and loads the file fine as well. Have checked both. – vivekv Jun 19 '14 at 07:11
  • As far as the return of a table reference, Redis manual (http://redis.io/commands/eval) says that a Lua table is converted to an appropriate redis datastructure. So I am not sure if there is a problem there. – vivekv Jun 19 '14 at 07:13
  • Interestingly. I made a small change to initialize the table and that works fine. Have updated the question with the changed script. – vivekv Jun 19 '14 at 07:14

2 Answers2

22

If you refer to the Redis EVAL documentation you can see what are the rules Redis uses to convert a Lua table into a Redis reply:

  1. Lua table (array) -> Redis multi bulk reply (truncated to the first nil inside the Lua array if any)
  2. Lua table with a single ok field -> Redis status reply
  3. Lua table with a single err field -> Redis error reply

So except with special cases 2 and 3, Redis assumes your table is a sequence (i.e list) which means it reads retv[1], retv[2], ... until it encounters a nil element (here is the corresponding source code section).

This explains why retv["test"] is ignored in your case.

If you change your code with:

local retv = {"This", "is", "a", "bug" }
retv[5] = 1000
return retv

Then this additional element gets returned:

1) "This"
2) "is"
3) "a"
4) "bug"
5) (integer) 1000
deltheil
  • 15,496
  • 2
  • 44
  • 64
  • That was it. Redis does not support arbitrary tables of Lua. Didnt know that! Thank you very much. – vivekv Jun 19 '14 at 09:50
  • Yes! This is because it needs to convert the Lua returned value into a valid [Redis protocol](http://redis.io/topics/protocol) (a.k.a RESP) data type, namely Simple Strings, Errors, Integers, Bulk Strings and Arrays - and there is no associative array. – deltheil Jun 19 '14 at 10:16
  • Thank you very much. This helps me a lot! Also deltheil wrote important sentence "...is no associative array", this helps me figure out whats wrong! – psulek Jul 06 '15 at 14:40
11

Answer from @deltheil is valid.

Remember though that you can use cjson library to pack tables and pass them to consumers.

Your lua file:

local retv = {"This", "is", "a", "bug" }
retv["test"] = 1000

return cjson.encode(retv)

Command:

redis-cli EVAL "$(cat bug.lua)" 0

Result:

"{\"1\":\"This\",\"2\":\"is\",\"3\":\"a\",\"4\":\"bug\",\"test\":1000}"
Anvaka
  • 15,658
  • 2
  • 47
  • 56