int RedisGenericCommand()

in src/storage/scripting.cc [728:837]


int RedisGenericCommand(lua_State *lua, int raise_error) {
  auto *script_run_ctx = GetFromRegistry<ScriptRunCtx>(lua, REGISTRY_SCRIPT_RUN_CTX_NAME);
  CHECK(script_run_ctx != nullptr);

  int argc = lua_gettop(lua);
  if (argc == 0) {
    PushError(lua, "Please specify at least one argument for redis.call()");
    return raise_error ? RaiseError(lua) : 1;
  }

  std::vector<std::string> args;
  for (int j = 1; j <= argc; j++) {
    if (lua_type(lua, j) == LUA_TNUMBER) {
      lua_Number num = lua_tonumber(lua, j);
      args.emplace_back(fmt::format("{:.17g}", static_cast<double>(num)));
    } else {
      size_t obj_len = 0;
      const char *obj_s = lua_tolstring(lua, j, &obj_len);
      if (obj_s == nullptr) {
        PushError(lua, "Lua redis.call() command arguments must be strings or integers");
        return raise_error ? RaiseError(lua) : 1;
      }
      args.emplace_back(obj_s, obj_len);
    }
  }

  auto cmd_s = Server::LookupAndCreateCommand(args[0]);
  if (!cmd_s) {
    PushError(lua, "Unknown Redis command called from Lua script");
    return raise_error ? RaiseError(lua) : 1;
  }
  auto cmd = *std::move(cmd_s);

  auto attributes = cmd->GetAttributes();
  if (!attributes->CheckArity(argc)) {
    PushError(lua, "Wrong number of args while calling Redis command from Lua script");
    return raise_error ? RaiseError(lua) : 1;
  }

  auto cmd_flags = attributes->GenerateFlags(args);

  if ((script_run_ctx->flags & ScriptFlagType::kScriptNoWrites) && !(cmd_flags & redis::kCmdReadOnly)) {
    PushError(lua, "Write commands are not allowed from read-only scripts");
    return raise_error ? RaiseError(lua) : 1;
  }

  if ((cmd_flags & redis::kCmdNoScript) || (cmd_flags & redis::kCmdExclusive)) {
    PushError(lua, "This Redis command is not allowed from scripts");
    return raise_error ? RaiseError(lua) : 1;
  }

  std::string cmd_name = attributes->name;

  auto *conn = script_run_ctx->conn;
  auto *srv = conn->GetServer();
  Config *config = srv->GetConfig();

  cmd->SetArgs(args);
  auto s = cmd->Parse();
  if (!s) {
    PushError(lua, s.Msg().data());
    return raise_error ? RaiseError(lua) : 1;
  }

  if (config->cluster_enabled) {
    if (script_run_ctx->flags & ScriptFlagType::kScriptNoCluster) {
      PushError(lua, "Can not run script on cluster, 'no-cluster' flag is set");
      return raise_error ? RaiseError(lua) : 1;
    }
    auto s = srv->cluster->CanExecByMySelf(attributes, args, conn, script_run_ctx);
    if (!s.IsOK()) {
      if (s.Is<Status::RedisMoved>()) {
        PushError(lua, "Script attempted to access a non local key in a cluster node script");
      } else {
        PushError(lua, redis::StatusToRedisErrorMsg(s).c_str());
      }
      return raise_error ? RaiseError(lua) : 1;
    }
  }

  if ((cmd_flags & redis::kCmdAdmin) && !conn->IsAdmin()) {
    PushError(lua, redis::errAdminPermissionRequired);
    return raise_error ? RaiseError(lua) : 1;
  }

  if (config->slave_readonly && srv->IsSlave() && (cmd_flags & redis::kCmdWrite)) {
    PushError(lua, "READONLY You can't write against a read only slave.");
    return raise_error ? RaiseError(lua) : 1;
  }

  if (!config->slave_serve_stale_data && srv->IsSlave() && cmd_name != "info" && cmd_name != "slaveof" &&
      srv->GetReplicationState() != kReplConnected) {
    PushError(lua,
              "MASTERDOWN Link with MASTER is down "
              "and slave-serve-stale-data is set to 'no'.");
    return raise_error ? RaiseError(lua) : 1;
  }

  std::string output;
  s = conn->ExecuteCommand(*script_run_ctx->ctx, cmd_name, args, cmd.get(), &output);
  if (!s) {
    PushError(lua, s.Msg().data());
    return raise_error ? RaiseError(lua) : 1;
  }

  srv->FeedMonitorConns(conn, args);

  RedisProtocolToLuaType(lua, output.data());
  return 1;
}