| 295 | } |
| 296 | |
| 297 | Status FunctionLoad(redis::Connection *conn, engine::Context *ctx, const std::string &script, bool need_to_store, |
| 298 | bool replace, [[maybe_unused]] std::string *lib_name) { |
| 299 | std::string first_line, lua_code; |
| 300 | if (auto pos = script.find('\n'); pos != std::string::npos) { |
| 301 | first_line = script.substr(0, pos); |
| 302 | lua_code = script.substr(pos + 1); |
| 303 | } else { |
| 304 | return {Status::NotOK, "Expect a Shebang statement in the first line"}; |
| 305 | } |
| 306 | |
| 307 | const auto libname = GET_OR_RET(ExtractLibNameFromShebang(first_line)); |
| 308 | |
| 309 | if (FunctionIsLibExist(conn, ctx, libname, need_to_store)) { |
| 310 | if (!replace) { |
| 311 | return {Status::NotOK, "library already exists, please specify REPLACE to force load"}; |
| 312 | } |
| 313 | auto s = FunctionDelete(*ctx, conn, libname); |
| 314 | if (!s) return s; |
| 315 | } |
| 316 | |
| 317 | auto srv = conn->GetServer(); |
| 318 | auto lua = conn->Owner()->Lua(); |
| 319 | |
| 320 | ScriptRunCtx script_run_ctx; |
| 321 | script_run_ctx.conn = conn; |
| 322 | script_run_ctx.ctx = ctx; |
| 323 | // in FunctionLoad(), the script MUST be read-only, |
| 324 | // because this function can be called multiple times |
| 325 | // for one script from multiple threads, |
| 326 | // and it is dangerous and unexpected to allow writes here. |
| 327 | script_run_ctx.flags = ScriptFlagType::kScriptNoWrites; |
| 328 | |
| 329 | SaveOnRegistry(lua, REGISTRY_SCRIPT_RUN_CTX_NAME, &script_run_ctx); |
| 330 | |
| 331 | lua_pushstring(lua, libname.c_str()); |
| 332 | lua_setglobal(lua, REDIS_FUNCTION_LIBNAME); |
| 333 | auto libname_exit = MakeScopeExit([lua] { |
| 334 | lua_pushnil(lua); |
| 335 | lua_setglobal(lua, REDIS_FUNCTION_LIBNAME); |
| 336 | }); |
| 337 | |
| 338 | lua_pushboolean(lua, need_to_store); |
| 339 | lua_setglobal(lua, REDIS_FUNCTION_NEEDSTORE); |
| 340 | auto need_store_exit = MakeScopeExit([lua] { |
| 341 | lua_pushnil(lua); |
| 342 | lua_setglobal(lua, REDIS_FUNCTION_NEEDSTORE); |
| 343 | }); |
| 344 | |
| 345 | if (luaL_loadbuffer(lua, lua_code.data(), lua_code.size(), "@user_script")) { |
| 346 | std::string err_msg = lua_tostring(lua, -1); |
| 347 | lua_pop(lua, 1); |
| 348 | return {Status::NotOK, "Error while compiling new function lib: " + err_msg}; |
| 349 | } |
| 350 | |
| 351 | if (lua_pcall(lua, 0, 0, 0)) { |
| 352 | std::string err_msg = lua_tostring(lua, -1); |
| 353 | lua_pop(lua, 1); |
| 354 | return {Status::NotOK, "Error while running new function lib: " + err_msg}; |
no test coverage detected