Commit 9ed32ba0 authored by antirez's avatar antirez
Browse files

Redis.call is now split into two variants of the same function. Redis.call...

Redis.call is now split into two variants of the same function. Redis.call will raise an error by default. Redis.pcall will return the error object instead.
parent 2f5abbfe
...@@ -128,7 +128,7 @@ void luaPushError(lua_State *lua, char *error) { ...@@ -128,7 +128,7 @@ void luaPushError(lua_State *lua, char *error) {
lua_settable(lua,-3); lua_settable(lua,-3);
} }
int luaRedisCommand(lua_State *lua) { int luaRedisGenericCommand(lua_State *lua, int raise_error) {
int j, argc = lua_gettop(lua); int j, argc = lua_gettop(lua);
struct redisCommand *cmd; struct redisCommand *cmd;
robj **argv; robj **argv;
...@@ -205,6 +205,7 @@ int luaRedisCommand(lua_State *lua) { ...@@ -205,6 +205,7 @@ int luaRedisCommand(lua_State *lua) {
reply = sdscatlen(reply,o->ptr,sdslen(o->ptr)); reply = sdscatlen(reply,o->ptr,sdslen(o->ptr));
listDelNode(c->reply,listFirst(c->reply)); listDelNode(c->reply,listFirst(c->reply));
} }
if (raise_error && reply[0] != '-') raise_error = 0;
redisProtocolToLuaType(lua,reply); redisProtocolToLuaType(lua,reply);
sdsfree(reply); sdsfree(reply);
...@@ -215,9 +216,25 @@ cleanup: ...@@ -215,9 +216,25 @@ cleanup:
decrRefCount(c->argv[j]); decrRefCount(c->argv[j]);
zfree(c->argv); 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; 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 luaLogCommand(lua_State *lua) {
int j, argc = lua_gettop(lua); int j, argc = lua_gettop(lua);
int level; int level;
...@@ -301,7 +318,12 @@ void scriptingInit(void) { ...@@ -301,7 +318,12 @@ void scriptingInit(void) {
/* redis.call */ /* redis.call */
lua_pushstring(lua,"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); lua_settable(lua,-3);
/* redis.log and log levels. */ /* redis.log and log levels. */
......
...@@ -54,7 +54,7 @@ start_server {tags {"scripting"}} { ...@@ -54,7 +54,7 @@ start_server {tags {"scripting"}} {
test {EVAL - Redis integer -> Lua type conversion} { test {EVAL - Redis integer -> Lua type conversion} {
r eval { r eval {
local foo = redis.call('incr','x') local foo = redis.pcall('incr','x')
return {type(foo),foo} return {type(foo),foo}
} 0 } 0
} {number 1} } {number 1}
...@@ -62,7 +62,7 @@ start_server {tags {"scripting"}} { ...@@ -62,7 +62,7 @@ start_server {tags {"scripting"}} {
test {EVAL - Redis bulk -> Lua type conversion} { test {EVAL - Redis bulk -> Lua type conversion} {
r set mykey myval r set mykey myval
r eval { r eval {
local foo = redis.call('get','mykey') local foo = redis.pcall('get','mykey')
return {type(foo),foo} return {type(foo),foo}
} 0 } 0
} {string myval} } {string myval}
...@@ -73,14 +73,14 @@ start_server {tags {"scripting"}} { ...@@ -73,14 +73,14 @@ start_server {tags {"scripting"}} {
r rpush mylist b r rpush mylist b
r rpush mylist c r rpush mylist c
r eval { 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} return {type(foo),foo[1],foo[2],foo[3],# foo}
} 0 } 0
} {table a b c 3} } {table a b c 3}
test {EVAL - Redis status reply -> Lua type conversion} { test {EVAL - Redis status reply -> Lua type conversion} {
r eval { r eval {
local foo = redis.call('set','mykey','myval') local foo = redis.pcall('set','mykey','myval')
return {type(foo),foo['ok']} return {type(foo),foo['ok']}
} 0 } 0
} {table OK} } {table OK}
...@@ -88,7 +88,7 @@ start_server {tags {"scripting"}} { ...@@ -88,7 +88,7 @@ start_server {tags {"scripting"}} {
test {EVAL - Redis error reply -> Lua type conversion} { test {EVAL - Redis error reply -> Lua type conversion} {
r set mykey myval r set mykey myval
r eval { r eval {
local foo = redis.call('incr','mykey') local foo = redis.pcall('incr','mykey')
return {type(foo),foo['err']} return {type(foo),foo['err']}
} 0 } 0
} {table {ERR value is not an integer or out of range}} } {table {ERR value is not an integer or out of range}}
...@@ -96,7 +96,7 @@ start_server {tags {"scripting"}} { ...@@ -96,7 +96,7 @@ start_server {tags {"scripting"}} {
test {EVAL - Redis nil bulk reply -> Lua type conversion} { test {EVAL - Redis nil bulk reply -> Lua type conversion} {
r del mykey r del mykey
r eval { r eval {
local foo = redis.call('get','mykey') local foo = redis.pcall('get','mykey')
return {type(foo),foo == false} return {type(foo),foo == false}
} 0 } 0
} {boolean 1} } {boolean 1}
...@@ -105,11 +105,11 @@ start_server {tags {"scripting"}} { ...@@ -105,11 +105,11 @@ start_server {tags {"scripting"}} {
r set mykey "this is DB 9" r set mykey "this is DB 9"
r select 10 r select 10
r set mykey "this is DB 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} } {this is DB 10}
test {EVAL - Is Lua seleced DB retained?} { 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 r get mykey
} {this is DB 9} } {this is DB 9}
...@@ -126,18 +126,42 @@ start_server {tags {"scripting"}} { ...@@ -126,18 +126,42 @@ start_server {tags {"scripting"}} {
test {EVAL - Scripts can't run certain commands} { test {EVAL - Scripts can't run certain commands} {
set e {} set e {}
catch {r eval {return redis.call('spop','x')} 0} e catch {r eval {return redis.pcall('spop','x')} 0} e
set e set e
} {*not allowed*} } {*not allowed*}
test {EVAL - Scripts can't run certain commands} { test {EVAL - Scripts can't run certain commands} {
set e {} set e {}
catch { 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 } e
set e set e
} {*not allowed after*} } {*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"}} { start_server {tags {"scripting repl"}} {
......
Markdown is supported
0% or .
You are about to add 0 people to the discussion. Proceed with caution.
Finish editing this message first!
Please register or to comment