Skip to content

Commit

Permalink
Redis.call is now split into two variants of the same function. Redis…
Browse files Browse the repository at this point in the history
….call will raise an error by default. Redis.pcall will return the error object instead.
  • Loading branch information
antirez committed Oct 20, 2011
1 parent 2f5abbf commit 9ed32ba
Show file tree
Hide file tree
Showing 2 changed files with 58 additions and 12 deletions.
26 changes: 24 additions & 2 deletions src/scripting.c
Expand Up @@ -128,7 +128,7 @@ void luaPushError(lua_State *lua, char *error) {
lua_settable(lua,-3);
}

int luaRedisCommand(lua_State *lua) {
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
int j, argc = lua_gettop(lua);
struct redisCommand *cmd;
robj **argv;
Expand Down Expand Up @@ -205,6 +205,7 @@ int luaRedisCommand(lua_State *lua) {
reply = sdscatlen(reply,o->ptr,sdslen(o->ptr));
listDelNode(c->reply,listFirst(c->reply));
}
if (raise_error && reply[0] != '-') raise_error = 0;
redisProtocolToLuaType(lua,reply);
sdsfree(reply);

Expand All @@ -215,9 +216,25 @@ int luaRedisCommand(lua_State *lua) {
decrRefCount(c->argv[j]);
zfree(c->argv);

if (raise_error) {
/* If we are here we should have an error in the stack, in the
* form of a table with an "err" field. Extract the string to
* return the plain error. */
lua_pushstring(lua,"err");
lua_gettable(lua,-2);
return lua_error(lua);
}
return 1;
}

int luaRedisCallCommand(lua_State *lua) {
return luaRedisGenericCommand(lua,1);
}

int luaRedisPCallCommand(lua_State *lua) {
return luaRedisGenericCommand(lua,0);
}

int luaLogCommand(lua_State *lua) {
int j, argc = lua_gettop(lua);
int level;
Expand Down Expand Up @@ -301,7 +318,12 @@ void scriptingInit(void) {

/* redis.call */
lua_pushstring(lua,"call");
lua_pushcfunction(lua,luaRedisCommand);
lua_pushcfunction(lua,luaRedisCallCommand);
lua_settable(lua,-3);

/* redis.pcall */
lua_pushstring(lua,"pcall");
lua_pushcfunction(lua,luaRedisPCallCommand);
lua_settable(lua,-3);

/* redis.log and log levels. */
Expand Down
44 changes: 34 additions & 10 deletions tests/unit/scripting.tcl
Expand Up @@ -54,15 +54,15 @@ start_server {tags {"scripting"}} {

test {EVAL - Redis integer -> Lua type conversion} {
r eval {
local foo = redis.call('incr','x')
local foo = redis.pcall('incr','x')
return {type(foo),foo}
} 0
} {number 1}

test {EVAL - Redis bulk -> Lua type conversion} {
r set mykey myval
r eval {
local foo = redis.call('get','mykey')
local foo = redis.pcall('get','mykey')
return {type(foo),foo}
} 0
} {string myval}
Expand All @@ -73,30 +73,30 @@ start_server {tags {"scripting"}} {
r rpush mylist b
r rpush mylist c
r eval {
local foo = redis.call('lrange','mylist',0,-1)
local foo = redis.pcall('lrange','mylist',0,-1)
return {type(foo),foo[1],foo[2],foo[3],# foo}
} 0
} {table a b c 3}

test {EVAL - Redis status reply -> Lua type conversion} {
r eval {
local foo = redis.call('set','mykey','myval')
local foo = redis.pcall('set','mykey','myval')
return {type(foo),foo['ok']}
} 0
} {table OK}

test {EVAL - Redis error reply -> Lua type conversion} {
r set mykey myval
r eval {
local foo = redis.call('incr','mykey')
local foo = redis.pcall('incr','mykey')
return {type(foo),foo['err']}
} 0
} {table {ERR value is not an integer or out of range}}

test {EVAL - Redis nil bulk reply -> Lua type conversion} {
r del mykey
r eval {
local foo = redis.call('get','mykey')
local foo = redis.pcall('get','mykey')
return {type(foo),foo == false}
} 0
} {boolean 1}
Expand All @@ -105,11 +105,11 @@ start_server {tags {"scripting"}} {
r set mykey "this is DB 9"
r select 10
r set mykey "this is DB 10"
r eval {return redis.call('get','mykey')} 0
r eval {return redis.pcall('get','mykey')} 0
} {this is DB 10}

test {EVAL - Is Lua seleced DB retained?} {
r eval {return redis.call('select','9')} 0
r eval {return redis.pcall('select','9')} 0
r get mykey
} {this is DB 9}

Expand All @@ -126,18 +126,42 @@ start_server {tags {"scripting"}} {

test {EVAL - Scripts can't run certain commands} {
set e {}
catch {r eval {return redis.call('spop','x')} 0} e
catch {r eval {return redis.pcall('spop','x')} 0} e
set e
} {*not allowed*}

test {EVAL - Scripts can't run certain commands} {
set e {}
catch {
r eval "redis.call('randomkey'); return redis.call('set','x','ciao')" 0
r eval "redis.pcall('randomkey'); return redis.pcall('set','x','ciao')" 0
} e
set e
} {*not allowed after*}

test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
set e {}
catch {
r eval "redis.call('nosuchcommand')" 0
} e
set e
} {*Unknown Redis*}

test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
set e {}
catch {
r eval "redis.call('get','a','b','c')" 0
} e
set e
} {*number of args*}

test {EVAL - redis.call variant raises a Lua error on Redis cmd error (1)} {
set e {}
r set foo bar
catch {
r eval "redis.call('lpush','foo','val')" 0
} e
set e
} {*against a key*}
}

start_server {tags {"scripting repl"}} {
Expand Down

0 comments on commit 9ed32ba

Please sign in to comment.