Support returning arrays from lua scripts

This commit is contained in:
Roman Gershman 2022-03-29 17:27:48 +03:00
parent 789724584a
commit e46f2b5384
3 changed files with 20 additions and 8 deletions

View File

@ -397,6 +397,8 @@ bool Interpreter::Exists(string_view sha) const {
} }
auto Interpreter::RunFunction(string_view sha, std::string* error) -> RunResult { auto Interpreter::RunFunction(string_view sha, std::string* error) -> RunResult {
DVLOG(1) << "RunFunction " << sha << " " << lua_gettop(lua_);
DCHECK_EQ(40u, sha.size()); DCHECK_EQ(40u, sha.size());
lua_getglobal(lua_, "__redis__err__handler"); lua_getglobal(lua_, "__redis__err__handler");
@ -413,6 +415,8 @@ auto Interpreter::RunFunction(string_view sha, std::string* error) -> RunResult
return NOT_EXISTS; return NOT_EXISTS;
} }
// At this point lua stack has 2 globals.
/* We have zero arguments and expect /* We have zero arguments and expect
* a single return value. */ * a single return value. */
int err = lua_pcall(lua_, 0, 1, -2); int err = lua_pcall(lua_, 0, 1, -2);
@ -438,7 +442,11 @@ bool Interpreter::IsResultSafe() const {
return true; return true;
bool res = IsTableSafe(); bool res = IsTableSafe();
lua_settop(lua_, top);
// Stack can contain intermediate unwindings that were not clean up.
DCHECK_GE(lua_gettop(lua_), top);
lua_settop(lua_, top); // restore to the original setting.
return res; return res;
} }
@ -506,7 +514,6 @@ bool Interpreter::IsTableSafe() const {
lua_pop(lua_, 1); lua_pop(lua_, 1);
}; };
DCHECK_EQ(1, lua_gettop(lua_));
return true; return true;
} }

View File

@ -248,10 +248,7 @@ TEST_F(DflyEngineTest, FlushDb) {
} }
TEST_F(DflyEngineTest, Eval) { TEST_F(DflyEngineTest, Eval) {
auto resp = Run({"eval", "return 43", "0"}); auto resp = Run({"incrby", "foo", "42"});
EXPECT_THAT(resp[0], IntArg(43));
resp = Run({"incrby", "foo", "42"});
EXPECT_THAT(resp[0], IntArg(42)); EXPECT_THAT(resp[0], IntArg(42));
resp = Run({"eval", "return redis.call('get', 'foo')", "0"}); resp = Run({"eval", "return redis.call('get', 'foo')", "0"});
@ -272,6 +269,14 @@ TEST_F(DflyEngineTest, Eval) {
ASSERT_FALSE(service_->IsShardSetLocked()); ASSERT_FALSE(service_->IsShardSetLocked());
} }
TEST_F(DflyEngineTest, EvalResp) {
auto resp = Run({"eval", "return 43", "0"});
EXPECT_THAT(resp[0], IntArg(43));
resp = Run({"eval", "return {5, 'foo', 17.5}", "0"});
EXPECT_THAT(resp, ElementsAre(IntArg(5), "foo", "17.5"));
}
TEST_F(DflyEngineTest, EvalSha) { TEST_F(DflyEngineTest, EvalSha) {
auto resp = Run({"script", "load", "return 5"}); auto resp = Run({"script", "load", "return 5"});
EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::STRING))); EXPECT_THAT(resp, ElementsAre(ArgType(RespExpr::STRING)));

View File

@ -120,11 +120,10 @@ class EvalSerializer : public ObjectExplorer {
} }
void OnArrayStart(unsigned len) final { void OnArrayStart(unsigned len) final {
LOG(FATAL) << "TBD"; rb_->StartArray(len);
} }
void OnArrayEnd() final { void OnArrayEnd() final {
LOG(FATAL) << "TBD";
} }
void OnNil() final { void OnNil() final {
@ -802,6 +801,7 @@ void Service::EvalInternal(const EvalArgs& eval_args, Interpreter* interpreter,
string resp = absl::StrCat("Error running script (call to ", eval_args.sha, "): ", error); string resp = absl::StrCat("Error running script (call to ", eval_args.sha, "): ", error);
return (*cntx)->SendError(resp, facade::kScriptErrType); return (*cntx)->SendError(resp, facade::kScriptErrType);
} }
CHECK(result == Interpreter::RUN_OK); CHECK(result == Interpreter::RUN_OK);
EvalSerializer ser{static_cast<RedisReplyBuilder*>(cntx->reply_builder())}; EvalSerializer ser{static_cast<RedisReplyBuilder*>(cntx->reply_builder())};