There seems to be a bug with redis.call() inside Lua scripting when calling the type function. Specifically, it returns a table as a result instead of a string.
127.0.0.1:6379> set foo 1
127.0.0.1:6379> eval "return redis.call('type', KEYS) == 'string'" 1 foo
127.0.0.1:6379> eval "return redis.call('type', KEYS).ok == 'string'" 1 foo
127.0.0.1:6379> eval "return redis.pcall('type', KEYS).ok == 'string'" 1 foo
I had expected that redis.call('type', KEYS) would return a string. It might have previously done so, I'm not sure. I haven't gone back to check previous versions of Redis.
This is using vanilla Redis 3.2.0 from the repository, freshly built:
127.0.0.1:6379> info server
os:Linux 3.16.0-30-generic x86_64
Please close if this is expected behavior.
I guess that is bug but you can use this code to convert it to string:
if type(t) == "table" then
for k, v in pairs(t) do t = v; end;
I am not looking for a workaround for bugs. I already have a workaround that is better and faster in every way: use redis.pcall() - whose expected return value is a table.
local typ = redis.pcall('TYPE', idx).ok
Thanks, buf I guess pcall should return table only on errors, so better is:
if type(t) == "table" then t = t.ok; end;
t = t.ok or t;
(both are using redis.call without t.err checking)
Except that redis.pcall('type', 'key') should only fail if Redis itself was failing. This is a type-less function that doesn't even require the key to exist. Aside from memory corruption or system out of memory conditions (can't malloc, not that Redis hit user-defined limits), this shouldn't ever fail. And failing here isn't likely to be recoverable.
The same happens with PING, for example, because simple strings are interpreted as status replies when pushed back to the Lua script (https://github.com/antirez/redis/blob/unstable/src/scripting.c#L133).
You've got the inside scoop @itamarhaber, bug or feature? ;)
I assumed it was a feature when I came across it a while ago. I admit it's not nice or intuitive, but it will break backwards compatibility to change it now.
Hello! THis is actually a feature... It's an odd one but the Lua type system did not offer many choices. It is also a very documented feature! Since day one of Lua scripting, but the current scripting documentation in the EVAL man page is not exactly the best in order to read it all.
So why it is like that? Because Lua scripts can return strings in three different forms:
Lua should be able to return them all in their different forms. Normal clients don't really need to distinguish between 1 and 2, but Lua must, because if you do:
You really want it to reply with a +PING in the protocol.
So what I did was to map all the Redis types that mapped into Lua types directly, but then I was left with this two that did not map, that are 2 and 3 of the list above. Simple strings (previously called status replies) and Errors. The only way to model them was to use a Lua table.
Okay, feature. Have worked around it. Thank you :)