Exemplo n.º 1
0
    int LUAInterpreter::Assert2(lua_State *lua)
    {
        lua_Debug ar;
        lua_getstack(lua, 1, &ar);
        lua_getinfo(lua, "nSl", &ar);
        int lua_line = ar.currentline;

        int argc = lua_gettop(lua);

        /* Require at least one argument */
        if (argc != 2)
        {
            luaPushError(lua, "Please specify 2 arguments for assert2()");
            return -1;
        }
        if (!lua_isboolean(lua, 1))
        {
            luaPushError(lua, "Lua assert2() command argument[0] must be boolean");
            return -1;
        }

        int b = lua_toboolean(lua, 1);
        if (b)
        {
            fprintf(stdout, "\e[1;32m%-6s\e[m %s:%d\n", "[PASS]", g_lua_file, lua_line);
        }
        else
        {
Exemplo n.º 2
0
int luaLogCommand(lua_State *lua) {
    int j, argc = lua_gettop(lua);
    int level;
    sds log;

    if (argc < 2) {
        luaPushError(lua, "redis.log() requires two arguments or more.");
        return 1;
    } else if (!lua_isnumber(lua,-argc)) {
        luaPushError(lua, "First argument must be a number (log level).");
        return 1;
    }
    level = lua_tonumber(lua,-argc);
    if (level < REDIS_DEBUG || level > REDIS_WARNING) {
        luaPushError(lua, "Invalid debug level.");
        return 1;
    }

    /* Glue together all the arguments */
    log = sdsempty();
    for (j = 1; j < argc; j++) {
        size_t len;
        char *s;

        s = (char*)lua_tolstring(lua,(-argc)+j,&len);
        if (s) {
            if (j != 1) log = sdscatlen(log," ",1);
            log = sdscatlen(log,s,len);
        }
    }
    redisLogRaw(level,log);
    sdsfree(log);
    return 0;
}
Exemplo n.º 3
0
int luaLogCommand(lua_State *lua) {
	int j, argc = lua_gettop(lua);
	int level;
	char *log;
	char **strs;
	size_t *strlens;

	if (argc < 2) {
		luaPushError(lua, "rlite.log() requires two arguments or more.");
		return 1;
	} else if (!lua_isnumber(lua,-argc)) {
		luaPushError(lua, "First argument must be a number (log level).");
		return 1;
	}
	level = lua_tonumber(lua,-argc);
	if (level < RLITE_DEBUG || level > RLITE_WARNING) {
		luaPushError(lua, "Invalid debug level.");
		return 1;
	}

	size_t totalsize = 0;
	strs = malloc(sizeof(char *) * (argc - 1));
	if (!strs) {
		return 1;
	}
	strlens = malloc(sizeof(size_t) * (argc - 1));
	if (!strlens) {
		free(strs);
		return 1;
	}
	strlens = malloc(sizeof(size_t) * (argc - 1));
	for (j = 1; j < argc; j++) {
		strs[j - 1] = (char*)lua_tolstring(lua,(-argc)+j,&strlens[j - 1]);
		totalsize += strlens[j - 1];
	}
	log = malloc(sizeof(char) * (totalsize + 1));
	if (!log) {
		free(strs);
		free(strlens);
		return 1;
	}

	totalsize = 0;
	for (j = 0; j < argc - 1; j++) {
		memcpy(&log[totalsize], strs[j], strlens[j]);
		totalsize += strlens[j];
	}
	log[totalsize] = 0;
	rliteLogRaw(level,log);
	return 0;
}
Exemplo n.º 4
0
int luaSetHttp304Command(lua_State *lua) {
    int argc = lua_gettop(lua);
    if (argc != 0) {
        CLEAR_LUA_STACK
        luaPushError(lua, "Lua SetHttp304() takes ZERO args"); return 1;
    }
    server.alc.CurrClient->http.retcode = 304;
    return 0;
}
Exemplo n.º 5
0
int luaSetHttpRedirectCommand(lua_State *lua) {
    int argc = lua_gettop(lua);
    if (argc != 1 || !lua_isstring(lua, 1)) {
        CLEAR_LUA_STACK
        luaPushError(lua, "Lua SetHttpRedirect() takes 1 string arg"); return 1;
    }
    server.alc.CurrClient->http.retcode = 302;
    server.alc.CurrClient->http.redir   = sdsnew(lua_tostring(lua, 1));//FREE079
    return 0;
}
Exemplo n.º 6
0
 int LUAInterpreter::IsMergeSupported(lua_State *lua)
 {
     int argc = lua_gettop(lua);
     if (argc != 0)
     {
         luaPushError(lua, "wrong number of arguments");
         return 1;
     }
     lua_pushboolean(lua, g_engine->GetFeatureSet().support_merge);
     return 1;
 }
Exemplo n.º 7
0
/* Returns a table with a single field 'field' set to the string value
 * passed as argument. This helper function is handy when returning
 * a Redis Protocol error or status reply from Lua:
 *
 * return redis.error_reply("ERR Some Error")
 * return redis.status_reply("ERR Some Error")
 */
int luaRedisReturnSingleFieldTable(lua_State *lua, char *field) {
    if (lua_gettop(lua) != 1 || lua_type(lua,-1) != LUA_TSTRING) {
        luaPushError(lua, "wrong number or type of arguments");
        return 1;
    }

    lua_newtable(lua);
    lua_pushstring(lua, field);
    lua_pushvalue(lua, -3);
    lua_settable(lua, -3);
    return 1;
}
Exemplo n.º 8
0
int luaSetHttpResponseHeaderCommand(lua_State *lua) {
    int argc = lua_gettop(lua);
    if (argc != 2 || !lua_isstring(lua, 1) || !lua_isstring(lua, 2)) {
        CLEAR_LUA_STACK
        luaPushError(lua, "Lua SetHttpResponseHeader() takes 2 string args");
        return 1;
    }
    sds a    = sdsnew(lua_tostring(lua, 1));
    sds b    = sdsnew(lua_tostring(lua, 2));
    addHttpResponseHeader(a, b);
    return 0;
}
Exemplo n.º 9
0
/* This adds redis.sha1hex(string) to Lua scripts using the same hashing
 * function used for sha1ing lua scripts. */
int luaRedisSha1hexCommand(lua_State *lua) {
    int argc = lua_gettop(lua);
    char digest[41];
    size_t len;
    char *s;

    if (argc != 1) {
        luaPushError(lua, "wrong number of arguments");
        return 1;
    }

    s = (char*)lua_tolstring(lua,1,&len);
    sha1hex(digest,s,len);
    lua_pushstring(lua,digest);
    return 1;
}
Exemplo n.º 10
0
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
    int j, argc = lua_gettop(lua);
    struct redisCommand *cmd;
    robj **argv;
    redisClient *c = server.lua_client;
    sds reply;

    /* Require at least one argument */
    if (argc == 0) {
        luaPushError(lua,
            "Please specify at least one argument for redis.call()");
        return 1;
    }

    /* Build the arguments vector */
    argv = zmalloc(sizeof(robj*)*argc);
    for (j = 0; j < argc; j++) {
        if (!lua_isstring(lua,j+1)) break;
        argv[j] = createStringObject((char*)lua_tostring(lua,j+1),
                                     lua_strlen(lua,j+1));
    }
    
    /* Check if one of the arguments passed by the Lua script
     * is not a string or an integer (lua_isstring() return true for
     * integers as well). */
    if (j != argc) {
        j--;
        while (j >= 0) {
            decrRefCount(argv[j]);
            j--;
        }
        zfree(argv);
        luaPushError(lua,
            "Lua redis() command arguments must be strings or integers");
        return 1;
    }

    /* Setup our fake client for command execution */
    c->argv = argv;
    c->argc = argc;

    /* Command lookup */
    cmd = lookupCommand(argv[0]->ptr);
    if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) ||
                   (argc < -cmd->arity)))
    {
        if (cmd)
            luaPushError(lua,
                "Wrong number of args calling Redis command From Lua script");
        else
            luaPushError(lua,"Unknown Redis command called from Lua script");
        goto cleanup;
    }

    /* There are commands that are not allowed inside scripts. */
    if (cmd->flags & REDIS_CMD_NOSCRIPT) {
        luaPushError(lua, "This Redis command is not allowed from scripts");
        goto cleanup;
    }

    /* Write commands are forbidden against read-only slaves, or if a
     * command marked as non-deterministic was already called in the context
     * of this script. */
    if (cmd->flags & REDIS_CMD_WRITE) {
        if (server.lua_random_dirty) {
            luaPushError(lua,
                "Write commands not allowed after non deterministic commands");
            goto cleanup;
        } else if (server.masterhost && server.repl_slave_ro &&
                   !server.loading &&
                   !(server.lua_caller->flags & REDIS_MASTER))
        {
            luaPushError(lua, shared.roslaveerr->ptr);
            goto cleanup;
        } else if (server.stop_writes_on_bgsave_err &&
                   server.saveparamslen > 0 &&
                   server.lastbgsave_status == REDIS_ERR)
        {
            luaPushError(lua, shared.bgsaveerr->ptr);
            goto cleanup;
        }
    }

    /* If we reached the memory limit configured via maxmemory, commands that
     * could enlarge the memory usage are not allowed, but only if this is the
     * first write in the context of this script, otherwise we can't stop
     * in the middle. */
    if (server.maxmemory && server.lua_write_dirty == 0 &&
        (cmd->flags & REDIS_CMD_DENYOOM))
    {
        if (freeMemoryIfNeeded() == REDIS_ERR) {
            luaPushError(lua, shared.oomerr->ptr);
            goto cleanup;
        }
    }

    if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1;
    if (cmd->flags & REDIS_CMD_WRITE) server.lua_write_dirty = 1;

    /* Run the command */
    c->cmd = cmd;
    call(c,REDIS_CALL_SLOWLOG | REDIS_CALL_STATS);

    /* Convert the result of the Redis command into a suitable Lua type.
     * The first thing we need is to create a single string from the client
     * output buffers. */
    reply = sdsempty();
    if (c->bufpos) {
        reply = sdscatlen(reply,c->buf,c->bufpos);
        c->bufpos = 0;
    }
    while(listLength(c->reply)) {
        robj *o = listNodeValue(listFirst(c->reply));

        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);
    /* Sort the output array if needed, assuming it is a non-null multi bulk
     * reply as expected. */
    if ((cmd->flags & REDIS_CMD_SORT_FOR_SCRIPT) &&
        (reply[0] == '*' && reply[1] != '-')) {
            luaSortArray(lua);
    }
    sdsfree(reply);
    c->reply_bytes = 0;

cleanup:
    /* Clean up. Command code may have changed argv/argc so we use the
     * argv/argc of the client instead of the local variables. */
    for (j = 0; j < c->argc; j++)
        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;
}
Exemplo n.º 11
0
    int LUAInterpreter::CallArdb(lua_State *lua, bool raise_error)
    {
        int j, argc = lua_gettop(lua);
        ArgumentArray cmdargs;

        /* Require at least one argument */
        if (argc == 0)
        {
            luaPushError(lua, "Please specify at least one argument for redis.call()");
            return 1;
        }

        /* Build the arguments vector */
        for (j = 0; j < argc; j++)
        {
            if (!lua_isstring(lua, j + 1))
                break;
            std::string arg;
            arg.append(lua_tostring(lua, j + 1), lua_strlen(lua, j + 1));
            cmdargs.push_back(arg);
        }

        /* Check if one of the arguments passed by the Lua script
         * is not a string or an integer (lua_isstring() return true for
         * integers as well). */
        if (j != argc)
        {
            luaPushError(lua, "Lua redis() command arguments must be strings or integers");
            return 1;
        }

        /* Setup our fake client for command execution */

        RedisCommandFrame cmd(cmdargs);
        Ardb::RedisCommandHandlerSetting* setting = g_db->FindRedisCommandHandlerSetting(cmd);
        /* Command lookup */
        if (NULL == setting)
        {
            luaPushError(lua, "Unknown Redis command called from Lua script");
            return -1;
        }

        /* There are commands that are not allowed inside scripts. */
        if (!setting->IsAllowedInScript())
        {
            luaPushError(lua, "This Redis command is not allowed from scripts");
            return -1;
        }
        LuaExecContext* ctx = g_lua_exec_ctx.GetValue();

        /* Write commands are forbidden against read-only slaves, or if a
         * command marked as non-deterministic was already called in the context
         * of this script. */
        if (setting->IsWriteCommand())
        {
            if (!g_db->GetConf().master_host.empty() && g_db->GetConf().slave_readonly && !g_db->IsLoadingData() && !(ctx->caller->flags.slave))
            {
                luaPushError(lua, "-READONLY You can't write against a read only slave.");
                return -1;
            }
        }

        Context& lua_ctx = ctx->exec;
        RedisReply& reply = lua_ctx.GetReply();
        reply.Clear();
        lua_ctx.ClearFlags();
        lua_ctx.flags.lua = 1;
        g_db->DoCall(lua_ctx, *setting, cmd);
        if (raise_error && reply.type != REDIS_REPLY_ERROR)
        {
            raise_error = 0;
        }
        redisProtocolToLuaType(lua, reply);

        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;
    }
Exemplo n.º 12
0
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
    int j, argc = lua_gettop(lua);
    struct redisCommand *cmd;
    redisClient *c = server.lua_client;
    sds reply;

    /* Cached across calls. */
    static robj **argv = NULL;
    static int argv_size = 0;
    static robj *cached_objects[LUA_CMD_OBJCACHE_SIZE];
    static size_t cached_objects_len[LUA_CMD_OBJCACHE_SIZE];
    static int inuse = 0;   /* Recursive calls detection. */

    /* By using Lua debug hooks it is possible to trigger a recursive call
     * to luaRedisGenericCommand(), which normally should never happen.
     * To make this function reentrant is futile and makes it slower, but
     * we should at least detect such a misuse, and abort. */
    if (inuse) {
        char *recursion_warning =
            "luaRedisGenericCommand() recursive call detected. "
            "Are you doing funny stuff with Lua debug hooks?";
        redisLog(REDIS_WARNING,"%s",recursion_warning);
        luaPushError(lua,recursion_warning);
        return 1;
    }
    inuse++;

    /* Require at least one argument */
    if (argc == 0) {
        luaPushError(lua,
            "Please specify at least one argument for redis.call()");
        inuse--;
        return 1;
    }

    /* Build the arguments vector */
    if (argv_size < argc) {
        argv = zrealloc(argv,sizeof(robj*)*argc);
        argv_size = argc;
    }

    for (j = 0; j < argc; j++) {
        char *obj_s;
        size_t obj_len;
        char dbuf[64];

        if (lua_type(lua,j+1) == LUA_TNUMBER) {
            /* We can't use lua_tolstring() for number -> string conversion
             * since Lua uses a format specifier that loses precision. */
            lua_Number num = lua_tonumber(lua,j+1);

            obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
            obj_s = dbuf;
        } else {
            obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
            if (obj_s == NULL) break; /* Not a string. */
        }

        /* Try to use a cached object. */
        if (j < LUA_CMD_OBJCACHE_SIZE && cached_objects[j] &&
            cached_objects_len[j] >= obj_len)
        {
            char *s = cached_objects[j]->ptr;
            struct sdshdr *sh = (void*)(s-(sizeof(struct sdshdr)));

            argv[j] = cached_objects[j];
            cached_objects[j] = NULL;
            memcpy(s,obj_s,obj_len+1);
            sh->free += sh->len - obj_len;
            sh->len = obj_len;
        } else {
            argv[j] = createStringObject(obj_s, obj_len);
        }
    }

    /* Check if one of the arguments passed by the Lua script
     * is not a string or an integer (lua_isstring() return true for
     * integers as well). */
    if (j != argc) {
        j--;
        while (j >= 0) {
            decrRefCount(argv[j]);
            j--;
        }
        luaPushError(lua,
            "Lua redis() command arguments must be strings or integers");
        inuse--;
        return 1;
    }

    /* Setup our fake client for command execution */
    c->argv = argv;
    c->argc = argc;

    /* Command lookup */
    cmd = lookupCommand(argv[0]->ptr);
    if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) ||
                   (argc < -cmd->arity)))
    {
        if (cmd)
            luaPushError(lua,
                "Wrong number of args calling Redis command From Lua script");
        else
            luaPushError(lua,"Unknown Redis command called from Lua script");
        goto cleanup;
    }
    c->cmd = cmd;

    /* There are commands that are not allowed inside scripts. */
    if (cmd->flags & REDIS_CMD_NOSCRIPT) {
        luaPushError(lua, "This Redis command is not allowed from scripts");
        goto cleanup;
    }

    /* Write commands are forbidden against read-only slaves, or if a
     * command marked as non-deterministic was already called in the context
     * of this script. */
    if (cmd->flags & REDIS_CMD_WRITE) {
        if (server.lua_random_dirty) {
            luaPushError(lua,
                "Write commands not allowed after non deterministic commands");
            goto cleanup;
        } else if (server.masterhost && server.repl_slave_ro &&
                   !server.loading &&
                   !(server.lua_caller->flags & REDIS_MASTER))
        {
            luaPushError(lua, shared.roslaveerr->ptr);
            goto cleanup;
        } else if (server.stop_writes_on_bgsave_err &&
                   server.saveparamslen > 0 &&
                   server.lastbgsave_status == REDIS_ERR)
        {
            luaPushError(lua, shared.bgsaveerr->ptr);
            goto cleanup;
        }
    }

    /* If we reached the memory limit configured via maxmemory, commands that
     * could enlarge the memory usage are not allowed, but only if this is the
     * first write in the context of this script, otherwise we can't stop
     * in the middle. */
    if (server.maxmemory && server.lua_write_dirty == 0 &&
        (cmd->flags & REDIS_CMD_DENYOOM))
    {
        if (freeMemoryIfNeeded() == REDIS_ERR) {
            luaPushError(lua, shared.oomerr->ptr);
            goto cleanup;
        }
    }

    if (cmd->flags & REDIS_CMD_RANDOM) server.lua_random_dirty = 1;
    if (cmd->flags & REDIS_CMD_WRITE) server.lua_write_dirty = 1;

    /* If this is a Redis Cluster node, we need to make sure Lua is not
     * trying to access non-local keys, with the exception of commands
     * received from our master. */
    if (server.cluster_enabled && !(server.lua_caller->flags & REDIS_MASTER)) {
        /* Duplicate relevant flags in the lua client. */
        c->flags &= ~(REDIS_READONLY|REDIS_ASKING);
        c->flags |= server.lua_caller->flags & (REDIS_READONLY|REDIS_ASKING);
        if (getNodeByQuery(c,c->cmd,c->argv,c->argc,NULL,NULL) !=
                           server.cluster->myself)
        {
            luaPushError(lua,
                "Lua script attempted to access a non local key in a "
                "cluster node");
            goto cleanup;
        }
    }

    /* Run the command */
    call(c,REDIS_CALL_SLOWLOG | REDIS_CALL_STATS);

    /* Convert the result of the Redis command into a suitable Lua type.
     * The first thing we need is to create a single string from the client
     * output buffers. */
    if (listLength(c->reply) == 0 && c->bufpos < REDIS_REPLY_CHUNK_BYTES) {
        /* This is a fast path for the common case of a reply inside the
         * client static buffer. Don't create an SDS string but just use
         * the client buffer directly. */
        c->buf[c->bufpos] = '\0';
        reply = c->buf;
        c->bufpos = 0;
    } else {
        reply = sdsnewlen(c->buf,c->bufpos);
        c->bufpos = 0;
        while(listLength(c->reply)) {
            robj *o = listNodeValue(listFirst(c->reply));

            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);
    /* Sort the output array if needed, assuming it is a non-null multi bulk
     * reply as expected. */
    if ((cmd->flags & REDIS_CMD_SORT_FOR_SCRIPT) &&
        (reply[0] == '*' && reply[1] != '-')) {
            luaSortArray(lua);
    }
    if (reply != c->buf) sdsfree(reply);
    c->reply_bytes = 0;

cleanup:
    /* Clean up. Command code may have changed argv/argc so we use the
     * argv/argc of the client instead of the local variables. */
    for (j = 0; j < c->argc; j++) {
        robj *o = c->argv[j];

        /* Try to cache the object in the cached_objects array.
         * The object must be small, SDS-encoded, and with refcount = 1
         * (we must be the only owner) for us to cache it. */
        if (j < LUA_CMD_OBJCACHE_SIZE &&
            o->refcount == 1 &&
            (o->encoding == REDIS_ENCODING_RAW ||
             o->encoding == REDIS_ENCODING_EMBSTR) &&
            sdslen(o->ptr) <= LUA_CMD_OBJCACHE_MAX_LEN)
        {
            struct sdshdr *sh = (void*)(((char*)(o->ptr))-(sizeof(struct sdshdr)));

            if (cached_objects[j]) decrRefCount(cached_objects[j]);
            cached_objects[j] = o;
            cached_objects_len[j] = sh->free + sh->len;
        } else {
            decrRefCount(o);
        }
    }

    if (c->argv != argv) {
        zfree(c->argv);
        argv = NULL;
        argv_size = 0;
    }

    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);
        inuse--;
        return lua_error(lua);
    }
    inuse--;
    return 1;
}
Exemplo n.º 13
0
int luaRedisGenericCommand(lua_State *lua, int raise_error) {
	int j, argc = lua_gettop(lua);
	struct rliteCommand *cmd;
	rliteClient *c = lua_client;
	rliteReply *reply;

	/* Cached across calls. */
	static char **argv = NULL;
	static size_t *argvlen = NULL;
	static int argv_size = 0;
	static int inuse = 0;   /* Recursive calls detection. */

	/* By using Lua debug hooks it is possible to trigger a recursive call
	 * to luaRedisGenericCommand(), which normally should never happen.
	 * To make this function reentrant is futile and makes it slower, but
	 * we should at least detect such a misuse, and abort. */
	if (inuse) {
		char *recursion_warning =
			"luaRedisGenericCommand() recursive call detected. "
			"Are you doing funny stuff with Lua debug hooks?";
		rliteLog(RLITE_WARNING,"%s",recursion_warning);
		luaPushError(lua,recursion_warning);
		return 1;
	}
	inuse++;

	/* Require at least one argument */
	if (argc == 0) {
		luaPushError(lua,
			"Please specify at least one argument for rlite.call()");
		inuse--;
		return 1;
	}

	/* Build the arguments vector */
	if (argv_size < argc) {
		argv = realloc(argv, sizeof(char *) * argc);
		argvlen = realloc(argvlen, sizeof(size_t) * argc);
		argv_size = argc;
	}

	for (j = 0; j < argc; j++) {
		char *obj_s;
		size_t obj_len;
		char dbuf[64];

		if (lua_type(lua,j+1) == LUA_TNUMBER) {
			/* We can't use lua_tolstring() for number -> string conversion
			 * since Lua uses a format specifier that loses precision. */
			lua_Number num = lua_tonumber(lua,j+1);

			obj_len = snprintf(dbuf,sizeof(dbuf),"%.17g",(double)num);
			obj_s = dbuf;
		} else {
			obj_s = (char*)lua_tolstring(lua,j+1,&obj_len);
			if (obj_s == NULL) break; /* Not a string. */
		}

		argv[j] = obj_s;
		argvlen[j] = obj_len;
	}

	/* Check if one of the arguments passed by the Lua script
	 * is not a string or an integer (lua_isstring() return true for
	 * integers as well). */
	if (j != argc) {
		j--;
		while (j >= 0) {
			free(argv[j]);
			j--;
		}
		luaPushError(lua,
			"Lua rlite() command arguments must be strings or integers");
		inuse--;
		return 1;
	}

	/* Setup our fake client for command execution */
	c->argvlen = argvlen;
	c->argv = argv;
	c->argc = argc;

	/* Command lookup */
	cmd = rliteLookupCommand(argv[0], argvlen[0]);
	if (!cmd || ((cmd->arity > 0 && cmd->arity != argc) ||
				   (argc < -cmd->arity)))
	{
		if (cmd)
			luaPushError(lua,
				"Wrong number of args calling Redis command From Lua script");
		else
			luaPushError(lua,"Unknown Redis command called from Lua script");
		goto cleanup;
	}

	/* There are commands that are not allowed inside scripts. */
	if (cmd->flags & RLITE_CMD_NOSCRIPT) {
		luaPushError(lua, "This Redis command is not allowed from scripts");
		goto cleanup;
	}

	/* Write commands are forbidden against read-only slaves, or if a
	 * command marked as non-deterministic was already called in the context
	 * of this script. */
	if (cmd->flags & RLITE_CMD_WRITE) {
		if (lua_random_dirty) {
			luaPushError(lua,
				"Write commands not allowed after non deterministic commands");
			goto cleanup;
		}
	}

	if (cmd->flags & RLITE_CMD_RANDOM) lua_random_dirty = 1;
	if (cmd->flags & RLITE_CMD_WRITE) lua_write_dirty = 1;

	/* Run the command */
	rliteAppendCommandClient(c);
	rliteGetReply(c->context, (void **)&reply);

	if (raise_error && reply->type != RLITE_REPLY_ERROR) raise_error = 0;
	rliteToLuaType(lua,reply);
	/* Sort the output array if needed, assuming it is a non-null multi bulk
	 * reply as expected. */
	if ((cmd->flags & RLITE_CMD_SORT_FOR_SCRIPT) &&
		(reply->type == RLITE_REPLY_ARRAY && reply->elements > 0)) {
			luaSortArray(lua);
	}
	rliteFreeReplyObject(reply);
cleanup:
	if (c->argv != argv) {
		free(c->argv);
		argv = NULL;
		argv_size = 0;
	}

	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);
		inuse--;
		return lua_error(lua);
	}
	inuse--;
	return 1;
}