diff --git a/src/box/errcode.h b/src/box/errcode.h index d5d396d8783cbddcabf520e86e30bd3ce110f160..05bc46e9b28cfa0e6a9cf730c625460ed51fa343 100644 --- a/src/box/errcode.h +++ b/src/box/errcode.h @@ -256,6 +256,7 @@ struct errcode_record { /*201 */_(ER_NO_SUCH_FIELD_NAME, "Field '%s' was not found in the tuple") \ /*202 */_(ER_FUNC_WRONG_ARG_COUNT, "Wrong number of arguments is passed to %s(): expected %s, got %d") \ /*203 */_(ER_BOOTSTRAP_READONLY, "Trying to bootstrap a local read-only instance as master") \ + /*204 */_(ER_SQL_FUNC_WRONG_RET_COUNT, "SQL expects exactly one argument returned from %s, got %d")\ /* * !IMPORTANT! Please follow instructions at start of the file diff --git a/src/box/sql/func.c b/src/box/sql/func.c index 60efd0d9aa31c5c6404b46023d1efd763599e768..a710c368b3646b456b25ab35f1e834006e27b6d8 100644 --- a/src/box/sql/func.c +++ b/src/box/sql/func.c @@ -242,12 +242,13 @@ port_lua_get_vdbemem(struct port *base, uint32_t *size) struct port_lua *port = (struct port_lua *) base; struct lua_State *L = port->L; int argc = lua_gettop(L); - if (argc == 0) { - diag_set(ClientError, ER_SQL_EXECUTE, - "No value was passed from Lua"); + if (argc == 0 || argc > 1) { + diag_set(ClientError, ER_SQL_FUNC_WRONG_RET_COUNT, "Lua", argc); return NULL; } *size = argc; + /** FIXME: Implement an ability to return a vector. */ + assert(*size == 1); struct region *region = &fiber()->gc; size_t region_svp = region_used(region); struct Mem *val = vdbemem_alloc_on_region(argc); @@ -288,11 +289,12 @@ port_tuple_get_vdbemem(struct port *base, uint32_t *size) { struct port_tuple *port = (struct port_tuple *)base; *size = port->size; - if (*size == 0) { - diag_set(ClientError, ER_SQL_EXECUTE, - "No value was passed from C"); + if (*size == 0 || *size > 1) { + diag_set(ClientError, ER_SQL_FUNC_WRONG_RET_COUNT, "C", *size); return NULL; } + /** FIXME: Implement an ability to return a vector. */ + assert(*size == 1); struct region *region = &fiber()->gc; size_t region_svp = region_used(region); struct Mem *val = vdbemem_alloc_on_region(port->size); @@ -321,10 +323,10 @@ port_tuple_get_vdbemem(struct port *base, uint32_t *size) sqlVdbeMemSetDouble(&val[i], mp_decode_double(&data)); break; case MP_INT: - mem_set_i64(val, mp_decode_int(&data)); + mem_set_i64(&val[i], mp_decode_int(&data)); break; case MP_UINT: - mem_set_u64(val, mp_decode_uint(&data)); + mem_set_u64(&val[i], mp_decode_uint(&data)); break; case MP_STR: str = mp_decode_str(&data, &len); @@ -333,7 +335,7 @@ port_tuple_get_vdbemem(struct port *base, uint32_t *size) goto error; break; case MP_NIL: - sqlVdbeMemSetNull(val); + sqlVdbeMemSetNull(&val[i]); break; default: diag_set(ClientError, ER_SQL_EXECUTE, diff --git a/test/box/function1.c b/test/box/function1.c index ee5a422b51af5213df44e2c340d5777ce8ea311a..b0d983e2b5b962aad1fc4d06a5e5f99fe4950729 100644 --- a/test/box/function1.c +++ b/test/box/function1.c @@ -12,6 +12,25 @@ function1(box_function_ctx_t *ctx, const char *args, const char *args_end) return 0; } +int +multireturn(box_function_ctx_t *ctx, const char *args, const char *args_end) +{ + char tuple_buf[512]; + char *d = tuple_buf; + d = mp_encode_array(d, 1); + d = mp_encode_uint(d, 1); + assert(d <= tuple_buf + sizeof(tuple_buf)); + + box_tuple_format_t *fmt = box_tuple_format_default(); + box_tuple_t *tuple_a = box_tuple_new(fmt, tuple_buf, d); + if (tuple_a == NULL) + return -1; + int rc = box_return_tuple(ctx, tuple_a); + if (rc != 0) + return rc; + return box_return_tuple(ctx, tuple_a); +} + int args(box_function_ctx_t *ctx, const char *args, const char *args_end) { diff --git a/test/box/function1.result b/test/box/function1.result index a41ca4e3cd49177fda7690d7c9c08e7b89a31837..b91d63c5154116c1e6929007073ee43b16a39522 100644 --- a/test/box/function1.result +++ b/test/box/function1.result @@ -532,7 +532,7 @@ box.execute('SELECT lua(\'return box.cfg\')') box.execute('SELECT lua(\'return box.cfg()\')') --- - null -- 'Failed to execute SQL statement: No value was passed from Lua' +- SQL expects exactly one argument returned from Lua, got 0 ... box.execute('SELECT lua(\'return box.cfg.memtx_memory\')') --- @@ -757,6 +757,39 @@ box.schema.func.drop('secret_leak') box.schema.func.drop('secret') --- ... +-- UDF corner cases for SQL: no value returned, too many values returned +box.execute("SELECT LUA('a = 1 + 1')") +--- +- null +- SQL expects exactly one argument returned from Lua, got 0 +... +box.execute("SELECT LUA('return 1, 2')") +--- +- null +- SQL expects exactly one argument returned from Lua, got 2 +... +box.schema.func.create('function1', {language = "C", exports = {'LUA', 'SQL'}}) +--- +... +box.execute("SELECT \"function1\"()") +--- +- null +- SQL expects exactly one argument returned from C, got 0 +... +box.schema.func.drop("function1") +--- +... +box.schema.func.create('function1.multireturn', {language = "C", exports = {'LUA', 'SQL'}}) +--- +... +box.execute("SELECT \"function1.multireturn\"()") +--- +- null +- SQL expects exactly one argument returned from C, got 2 +... +box.schema.func.drop("function1.multireturn") +--- +... -- -- gh-4182: Introduce persistent Lua functions. -- diff --git a/test/box/function1.test.lua b/test/box/function1.test.lua index e576cbb6f68ceece13133623e5cedb87927f811c..b1841f3adb5892a7040d65550d3e07d4ddd59840 100644 --- a/test/box/function1.test.lua +++ b/test/box/function1.test.lua @@ -256,6 +256,18 @@ box.schema.user.revoke('guest', 'execute', 'function', 'secret_leak') box.schema.func.drop('secret_leak') box.schema.func.drop('secret') +-- UDF corner cases for SQL: no value returned, too many values returned +box.execute("SELECT LUA('a = 1 + 1')") +box.execute("SELECT LUA('return 1, 2')") + +box.schema.func.create('function1', {language = "C", exports = {'LUA', 'SQL'}}) +box.execute("SELECT \"function1\"()") +box.schema.func.drop("function1") + +box.schema.func.create('function1.multireturn', {language = "C", exports = {'LUA', 'SQL'}}) +box.execute("SELECT \"function1.multireturn\"()") +box.schema.func.drop("function1.multireturn") + -- -- gh-4182: Introduce persistent Lua functions. -- diff --git a/test/box/misc.result b/test/box/misc.result index 33e5ce88689049c1526a40ee3dfbbd7e5215b443..784ff4686a751f2d4a6c3da9755a554cf8f6a816 100644 --- a/test/box/misc.result +++ b/test/box/misc.result @@ -533,6 +533,7 @@ t; 201: box.error.NO_SUCH_FIELD_NAME 202: box.error.FUNC_WRONG_ARG_COUNT 203: box.error.BOOTSTRAP_READONLY + 204: box.error.SQL_FUNC_WRONG_RET_COUNT ... test_run:cmd("setopt delimiter ''"); ---