Esempio n. 1
0
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;
}
Esempio n. 2
0
struct tuple *
luaT_tuple_new(struct lua_State *L, int idx, box_tuple_format_t *format)
{
	if (idx != 0 && !lua_istable(L, idx) && !luaT_istuple(L, idx)) {
		diag_set(IllegalParams, "A tuple or a table expected, got %s",
			 lua_typename(L, lua_type(L, idx)));
		return NULL;
	}

	struct ibuf *buf = tarantool_lua_ibuf;
	ibuf_reset(buf);
	struct mpstream stream;
	mpstream_init(&stream, buf, ibuf_reserve_cb, ibuf_alloc_cb,
		      luamp_error, L);
	if (idx == 0) {
		/*
		 * Create the tuple from lua stack
		 * objects.
		 */
		int argc = lua_gettop(L);
		mpstream_encode_array(&stream, argc);
		for (int k = 1; k <= argc; ++k) {
			luamp_encode(L, luaL_msgpack_default, &stream, k);
		}
	} else {
		/* Create the tuple from a Lua table. */
		luamp_encode_tuple(L, &tuple_serializer, &stream, idx);
	}
	mpstream_flush(&stream);
	struct tuple *tuple = box_tuple_new(format, buf->buf,
					    buf->buf + ibuf_used(buf));
	if (tuple == NULL)
		return NULL;
	ibuf_reinit(tarantool_lua_ibuf);
	return tuple;
}
Esempio n. 3
0
/**
 * Tuple transforming function.
 *
 * Remove the fields designated by 'offset' and 'len' from an tuple,
 * and replace them with the elements of supplied data fields,
 * if any.
 *
 * Function returns newly allocated tuple.
 * It does not change any parent tuple data.
 */
static int
lbox_tuple_transform(struct lua_State *L)
{
	struct tuple *tuple = lua_checktuple(L, 1);
	int argc = lua_gettop(L);
	if (argc < 3)
		luaL_error(L, "tuple.transform(): bad arguments");
	lua_Integer offset = lua_tointeger(L, 2);  /* Can be negative and can be > INT_MAX */
	lua_Integer len = lua_tointeger(L, 3);

	lua_Integer field_count = box_tuple_field_count(tuple);
	/* validate offset and len */
	if (offset == 0) {
		luaL_error(L, "tuple.transform(): offset is out of bound");
	} else if (offset < 0) {
		if (-offset > field_count)
			luaL_error(L, "tuple.transform(): offset is out of bound");
		offset += field_count + 1;
	} else if (offset > field_count) {
		offset = field_count + 1;
	}
	if (len < 0)
		luaL_error(L, "tuple.transform(): len is negative");
	if (len > field_count + 1 - offset)
		len = field_count + 1 - offset;

	assert(offset + len <= field_count + 1);

	/*
	 * Calculate the number of operations and length of UPDATE expression
	 */
	uint32_t op_cnt = 0;
	if (offset < field_count + 1 && len > 0)
		op_cnt++;
	if (argc > 3)
		op_cnt += argc - 3;

	if (op_cnt == 0) {
		/* tuple_update() does not accept an empty operation list. */
		luaT_pushtuple(L, tuple);
		return 1;
	}

	struct ibuf *buf = tarantool_lua_ibuf;
	ibuf_reset(buf);
	struct mpstream stream;
	mpstream_init(&stream, buf, ibuf_reserve_cb, ibuf_alloc_cb,
		      luamp_error, L);

	/*
	 * Prepare UPDATE expression
	 */
	mpstream_encode_array(&stream, op_cnt);
	if (len > 0) {
		mpstream_encode_array(&stream, 3);
		mpstream_encode_str(&stream, "#");
		mpstream_encode_uint(&stream, offset);
		mpstream_encode_uint(&stream, len);
	}

	for (int i = argc ; i > 3; i--) {
		mpstream_encode_array(&stream, 3);
		mpstream_encode_str(&stream, "!");
		mpstream_encode_uint(&stream, offset);
		luamp_encode(L, luaL_msgpack_default, &stream, i);
	}
	mpstream_flush(&stream);

	uint32_t new_size = 0, bsize;
	const char *old_data = tuple_data_range(tuple, &bsize);
	struct region *region = &fiber()->gc;
	size_t used = region_used(region);
	struct tuple *new_tuple = NULL;
	/*
	 * Can't use box_tuple_update() since transform must reset
	 * the tuple format to default. The new tuple most likely
	 * won't coerce into the original space format, so we have
	 * to use the default one with no restrictions on field
	 * count or types.
	 */
	const char *new_data = tuple_update_execute(region_aligned_alloc_cb,
						    region, buf->buf,
						    buf->buf + ibuf_used(buf),
						    old_data, old_data + bsize,
						    &new_size, 1, NULL);
	if (new_data != NULL)
		new_tuple = tuple_new(box_tuple_format_default(),
				      new_data, new_data + new_size);
	region_truncate(region, used);

	if (new_tuple == NULL)
		luaT_error(L);

	luaT_pushtuple(L, new_tuple);
	ibuf_reset(buf);
	return 1;
}
Esempio n. 4
0
/**
 * 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 */
}