| 646 | } |
| 647 | |
| 648 | Status EvalGenericCommand(redis::Connection *conn, engine::Context *ctx, const std::string &body_or_sha, |
| 649 | const std::vector<std::string> &keys, const std::vector<std::string> &argv, bool evalsha, |
| 650 | std::string *output, bool read_only) { |
| 651 | Server *srv = conn->GetServer(); |
| 652 | // Use the worker's private Lua VM when entering the read-only mode |
| 653 | lua_State *lua = conn->Owner()->Lua(); |
| 654 | |
| 655 | /* We obtain the script SHA1, then check if this function is already |
| 656 | * defined into the Lua state */ |
| 657 | char funcname[2 + 40 + 1] = {}; |
| 658 | memcpy(funcname, REDIS_LUA_FUNC_SHA_PREFIX, sizeof(REDIS_LUA_FUNC_SHA_PREFIX)); |
| 659 | |
| 660 | if (!evalsha) { |
| 661 | SHA1Hex(funcname + 2, body_or_sha.c_str(), body_or_sha.size()); |
| 662 | } else { |
| 663 | for (int j = 0; j < 40; j++) { |
| 664 | funcname[j + 2] = static_cast<char>(tolower(body_or_sha[j])); |
| 665 | } |
| 666 | } |
| 667 | |
| 668 | /* Push the pcall error handler function on the stack. */ |
| 669 | lua_getglobal(lua, "__redis__err__handler"); |
| 670 | |
| 671 | /* Try to lookup the Lua function */ |
| 672 | lua_getglobal(lua, funcname); |
| 673 | if (lua_isnil(lua, -1)) { |
| 674 | lua_pop(lua, 1); /* remove the nil from the stack */ |
| 675 | std::string body; |
| 676 | if (evalsha) { |
| 677 | auto s = srv->ScriptGet(funcname + 2, &body); |
| 678 | if (!s.IsOK()) { |
| 679 | lua_pop(lua, 1); /* remove the error handler from the stack. */ |
| 680 | return {Status::RedisNoScript, redis::errNoMatchingScript}; |
| 681 | } |
| 682 | } else { |
| 683 | body = body_or_sha; |
| 684 | } |
| 685 | |
| 686 | std::string sha = funcname + 2; |
| 687 | auto s = CreateFunction(srv, body, &sha, lua, false); |
| 688 | if (!s.IsOK()) { |
| 689 | lua_pop(lua, 1); /* remove the error handler from the stack. */ |
| 690 | return s; |
| 691 | } |
| 692 | /* Now the following is guaranteed to return non nil */ |
| 693 | lua_getglobal(lua, funcname); |
| 694 | } |
| 695 | |
| 696 | ScriptRunCtx current_script_run_ctx; |
| 697 | current_script_run_ctx.conn = conn; |
| 698 | current_script_run_ctx.ctx = ctx; |
| 699 | current_script_run_ctx.flags = read_only ? ScriptFlagType::kScriptNoWrites : 0; |
| 700 | lua_getglobal(lua, fmt::format(REDIS_LUA_FUNC_SHA_FLAGS, funcname + 2).c_str()); |
| 701 | if (!lua_isnil(lua, -1)) { |
| 702 | // It should be ensured that the conversion is successful |
| 703 | auto script_flags = lua_tointeger(lua, -1); |
| 704 | current_script_run_ctx.flags |= script_flags; |
| 705 | } |
no test coverage detected