/** * Convert a tuple into lua table. Named fields are stored as * {name = value} pairs. Not named fields are stored as * {1-based_index_in_tuple = value}. */ static int lbox_tuple_to_map(struct lua_State *L) { int argc = lua_gettop(L); if (argc < 1 || argc > 2) goto error; bool names_only = false; if (argc == 2) { if (!lua_istable(L, 2)) goto error; lua_getfield(L, 2, "names_only"); if (!lua_isboolean(L, -1) && !lua_isnil(L, -1)) goto error; names_only = lua_toboolean(L, -1); } struct tuple *tuple = lua_checktuple(L, 1); struct tuple_format *format = tuple_format(tuple); const char *pos = tuple_data(tuple); int field_count = (int)mp_decode_array(&pos); int n_named = format->dict->name_count; lua_createtable(L, field_count, n_named); int named_and_presented = MIN(field_count, n_named); for (int i = 0; i < named_and_presented; ++i) { /* Access by name. */ const char *name = format->dict->names[i]; lua_pushstring(L, name); luamp_decode(L, luaL_msgpack_default, &pos); lua_rawset(L, -3); if (names_only) continue; /* * Access the same field by an index. There is no * copy for tables - lua optimizes it and uses * references. */ lua_pushstring(L, name); lua_rawget(L, -2); lua_rawseti(L, -2, i + TUPLE_INDEX_BASE); } if (names_only) return 1; /* Access for not named fields by index. */ for (int i = n_named; i < field_count; ++i) { luamp_decode(L, luaL_msgpack_default, &pos); lua_rawseti(L, -2, i + TUPLE_INDEX_BASE); } return 1; error: luaL_error(L, "Usage: tuple:tomap(opts)"); return 1; }
static int execute_lua_eval(lua_State *L) { struct lua_function_ctx *ctx = (struct lua_function_ctx *) lua_topointer(L, 1); struct request *request = ctx->request; struct obuf *out = ctx->out; struct obuf_svp *svp = &ctx->svp; lua_settop(L, 0); /* clear the stack to simplify the logic below */ /* Compile expression */ const char *expr = request->key; uint32_t expr_len = mp_decode_strl(&expr); if (luaL_loadbuffer(L, expr, expr_len, "=eval")) { diag_set(LuajitError, lua_tostring(L, -1)); lbox_error(L); } /* Unpack arguments */ const char *args = request->tuple; uint32_t arg_count = mp_decode_array(&args); luaL_checkstack(L, arg_count, "eval: out of stack"); for (uint32_t i = 0; i < arg_count; i++) { luamp_decode(L, luaL_msgpack_default, &args); } /* Call compiled code */ lua_call(L, arg_count, LUA_MULTRET); /* Send results of the called procedure to the client. */ if (iproto_prepare_select(out, svp) != 0) diag_raise(); ctx->out_is_dirty = true; struct mpstream stream; mpstream_init(&stream, out, obuf_reserve_cb, obuf_alloc_cb, luamp_error, L); int nrets = lua_gettop(L); for (int k = 1; k <= nrets; ++k) { luamp_encode(L, luaL_msgpack_default, &stream, k); } mpstream_flush(&stream); iproto_reply_select(out, svp, request->header->sync, nrets); return 0; }
static int lbox_tuple_slice_wrapper(struct lua_State *L) { box_tuple_iterator_t *it = (box_tuple_iterator_t *) lua_topointer(L, 1); uint32_t start = lua_tonumber(L, 2); uint32_t end = lua_tonumber(L, 3); assert(end >= start); const char *field; uint32_t field_no = start; field = box_tuple_seek(it, start); while (field && field_no < end) { luamp_decode(L, luaL_msgpack_default, &field); ++field_no; field = box_tuple_next(it); } assert(field_no == end); return end - start; }
/** * Find a tuple field by JSON path. If a field was not found and a * path contains JSON syntax errors, then an exception is raised. * @param L Lua state. * @param tuple 1-th argument on a lua stack, tuple to get field * from. * @param path 2-th argument on lua stack. Can be field name or a * JSON path to a field. * * @retval not nil Found field value. * @retval nil A field is NULL or does not exist. */ static int lbox_tuple_field_by_path(struct lua_State *L) { struct tuple *tuple = luaT_istuple(L, 1); /* Is checked in Lua wrapper. */ assert(tuple != NULL); assert(lua_isstring(L, 2)); size_t len; const char *field = NULL, *path = lua_tolstring(L, 2, &len); if (len == 0) return 0; field = tuple_field_raw_by_full_path(tuple_format(tuple), tuple_data(tuple), tuple_field_map(tuple), path, (uint32_t)len, lua_hashstring(L, 2)); if (field == NULL) return 0; luamp_decode(L, luaL_msgpack_default, &field); return 1; }
/** * Invoke a Lua stored procedure from the binary protocol * (implementation of 'CALL' command code). */ static inline int execute_lua_call(lua_State *L) { struct lua_function_ctx *ctx = (struct lua_function_ctx *) lua_topointer(L, 1); struct request *request = ctx->request; struct obuf *out = ctx->out; struct obuf_svp *svp = &ctx->svp; lua_settop(L, 0); /* clear the stack to simplify the logic below */ const char *name = request->key; uint32_t name_len = mp_decode_strl(&name); int oc = 0; /* how many objects are on stack after box_lua_find */ /* Try to find a function by name in Lua */ oc = box_lua_find(L, name, name + name_len); /* Push the rest of args (a tuple). */ const char *args = request->tuple; uint32_t arg_count = mp_decode_array(&args); luaL_checkstack(L, arg_count, "call: out of stack"); for (uint32_t i = 0; i < arg_count; i++) luamp_decode(L, luaL_msgpack_default, &args); lua_call(L, arg_count + oc - 1, LUA_MULTRET); /** * Add all elements from Lua stack to iproto. * * To allow clients to understand a complex return from * a procedure, we are compatible with SELECT protocol, * and return the number of return values first, and * then each return value as a tuple. * * If a Lua stack contains at least one scalar, each * value on the stack is converted to a tuple. A single * Lua with scalars is converted to a tuple with multiple * fields. * * If the stack is a Lua table, each member of which is * not scalar, each member of the table is converted to * a tuple. This way very large lists of return values can * be used, since Lua stack size is limited by 8000 elements, * while Lua table size is pretty much unlimited. */ /* TODO: forbid explicit yield from __serialize or __index here */ if (iproto_prepare_select(out, svp) != 0) lbox_error(L); ctx->out_is_dirty = true; struct luaL_serializer *cfg = luaL_msgpack_default; struct mpstream stream; mpstream_init(&stream, out, obuf_reserve_cb, obuf_alloc_cb, luamp_error, L); uint32_t count = luamp_encode_call(L, cfg, &stream); mpstream_flush(&stream); iproto_reply_select(out, svp, request->header->sync, count); return 0; /* truncate Lua stack */ }