TODO: we do not want to repeat same logic as Connection::ExecuteCommands, so the function need to be refactored
| 769 | // TODO: we do not want to repeat same logic as Connection::ExecuteCommands, |
| 770 | // so the function need to be refactored |
| 771 | int RedisGenericCommand(lua_State *lua, int raise_error) { |
| 772 | auto *script_run_ctx = GetFromRegistry<ScriptRunCtx>(lua, REGISTRY_SCRIPT_RUN_CTX_NAME); |
| 773 | CHECK(script_run_ctx != nullptr); |
| 774 | |
| 775 | int argc = lua_gettop(lua); |
| 776 | if (argc == 0) { |
| 777 | PushError(lua, "Please specify at least one argument for redis.call()"); |
| 778 | return raise_error ? RaiseError(lua) : 1; |
| 779 | } |
| 780 | |
| 781 | std::vector<std::string> args; |
| 782 | for (int j = 1; j <= argc; j++) { |
| 783 | if (lua_type(lua, j) == LUA_TNUMBER) { |
| 784 | lua_Number num = lua_tonumber(lua, j); |
| 785 | args.emplace_back(fmt::format("{:.17g}", static_cast<double>(num))); |
| 786 | } else { |
| 787 | size_t obj_len = 0; |
| 788 | const char *obj_s = lua_tolstring(lua, j, &obj_len); |
| 789 | if (obj_s == nullptr) { |
| 790 | PushError(lua, "Lua redis.call() command arguments must be strings or integers"); |
| 791 | return raise_error ? RaiseError(lua) : 1; |
| 792 | } |
| 793 | args.emplace_back(obj_s, obj_len); |
| 794 | } |
| 795 | } |
| 796 | |
| 797 | auto cmd_s = Server::LookupAndCreateCommand(args[0]); |
| 798 | if (!cmd_s) { |
| 799 | PushError(lua, "Unknown Redis command called from Lua script"); |
| 800 | return raise_error ? RaiseError(lua) : 1; |
| 801 | } |
| 802 | auto cmd = *std::move(cmd_s); |
| 803 | |
| 804 | auto attributes = cmd->GetAttributes(); |
| 805 | if (!attributes->CheckArity(argc)) { |
| 806 | PushError(lua, "Wrong number of args while calling Redis command from Lua script"); |
| 807 | return raise_error ? RaiseError(lua) : 1; |
| 808 | } |
| 809 | |
| 810 | auto *conn = script_run_ctx->conn; |
| 811 | auto *srv = conn->GetServer(); |
| 812 | Config *config = srv->GetConfig(); |
| 813 | |
| 814 | auto cmd_flags = attributes->GenerateFlags(args, *config); |
| 815 | |
| 816 | if ((script_run_ctx->flags & ScriptFlagType::kScriptNoWrites) && !(cmd_flags & redis::kCmdReadOnly)) { |
| 817 | PushError(lua, "Write commands are not allowed from read-only scripts"); |
| 818 | return raise_error ? RaiseError(lua) : 1; |
| 819 | } |
| 820 | |
| 821 | if ((cmd_flags & redis::kCmdNoScript) || (cmd_flags & redis::kCmdExclusive)) { |
| 822 | PushError(lua, "This Redis command is not allowed from scripts"); |
| 823 | return raise_error ? RaiseError(lua) : 1; |
| 824 | } |
| 825 | |
| 826 | std::string cmd_name = attributes->name; |
| 827 | cmd->SetArgs(args); |
| 828 | auto s = cmd->Parse(); |
no test coverage detected