diff --git a/src/box/bind.c b/src/box/bind.c index e75e36283574dfdfc2f1ef594006777f77873256..af9f9eac54c491e16f142f786e27eaf6b381ecb0 100644 --- a/src/box/bind.c +++ b/src/box/bind.c @@ -99,15 +99,12 @@ sql_bind_decode(struct sql_bind *bind, int i, const char **packet) case MP_BIN: bind->s = mp_decode_bin(packet, &bind->bytes); break; + case MP_ARRAY: case MP_EXT: bind->s = *packet; mp_next(packet); bind->bytes = *packet - bind->s; break; - case MP_ARRAY: - diag_set(ClientError, ER_SQL_BIND_TYPE, "ARRAY", - sql_bind_name(bind)); - return -1; case MP_MAP: diag_set(ClientError, ER_SQL_BIND_TYPE, "MAP", sql_bind_name(bind)); @@ -190,6 +187,8 @@ sql_bind_column(struct sql_stmt *stmt, const struct sql_bind *p, return sql_bind_null(stmt, pos); case MP_BIN: return sql_bind_bin_static(stmt, pos, p->s, p->bytes); + case MP_ARRAY: + return sql_bind_array_static(stmt, pos, p->s, p->bytes); case MP_EXT: assert(p->ext_type == MP_UUID || p->ext_type == MP_DECIMAL); if (p->ext_type == MP_UUID) diff --git a/src/box/lua/execute.c b/src/box/lua/execute.c index 18a45a5d5b908666770b8632199a8bc91b51d9aa..71d4d7faed03e0f475de4ba3322b0e551da09135 100644 --- a/src/box/lua/execute.c +++ b/src/box/lua/execute.c @@ -8,6 +8,8 @@ #include "box/bind.h" #include "box/sql_stmt_cache.h" #include "box/schema.h" +#include "mpstream/mpstream.h" +#include "box/sql/vdbeInt.h" /** * Serialize a description of the prepared statement. @@ -331,6 +333,8 @@ lua_sql_bind_decode(struct lua_State *L, struct sql_bind *bind, int idx, int i) } if (luaL_tofield(L, luaL_msgpack_default, -1, &field) < 0) return -1; + bind->type = field.type; + bind->ext_type = field.ext_type; switch (field.type) { case MP_UINT: bind->u64 = field.ival; @@ -382,10 +386,30 @@ lua_sql_bind_decode(struct lua_State *L, struct sql_bind *bind, int idx, int i) diag_set(ClientError, ER_SQL_BIND_TYPE, "USERDATA", sql_bind_name(bind)); return -1; - case MP_ARRAY: - diag_set(ClientError, ER_SQL_BIND_TYPE, "ARRAY", - sql_bind_name(bind)); + case MP_ARRAY: { + size_t used = region_used(region); + struct mpstream stream; + bool is_error = false; + mpstream_init(&stream, region, region_reserve_cb, + region_alloc_cb, set_encode_error, &is_error); + lua_pushvalue(L, -1); + luamp_encode_r(L, luaL_msgpack_default, &stream, &field, 0); + lua_pop(L, 1); + mpstream_flush(&stream); + if (is_error) { + region_truncate(region, used); + diag_set(OutOfMemory, stream.pos - stream.buf, + "mpstream_flush", "stream"); + return -1; + } + bind->bytes = region_used(region) - used; + bind->s = region_join(region, bind->bytes); + if (bind->s != NULL) + break; + region_truncate(region, used); + diag_set(OutOfMemory, bind->bytes, "region_join", "bind->s"); return -1; + } case MP_MAP: diag_set(ClientError, ER_SQL_BIND_TYPE, "MAP", sql_bind_name(bind)); @@ -393,8 +417,6 @@ lua_sql_bind_decode(struct lua_State *L, struct sql_bind *bind, int idx, int i) default: unreachable(); } - bind->type = field.type; - bind->ext_type = field.ext_type; lua_pop(L, lua_gettop(L) - idx); return 0; } diff --git a/src/box/sql/sqlInt.h b/src/box/sql/sqlInt.h index dcd71e5bd82ff64dca6d64d969c17341b76751c0..716110edc69b58c1fb7babf0023819da81be5c98 100644 --- a/src/box/sql/sqlInt.h +++ b/src/box/sql/sqlInt.h @@ -556,6 +556,9 @@ sql_bind_str_static(sql_stmt *stmt, int i, const char *str, uint32_t len); int sql_bind_bin_static(sql_stmt *stmt, int i, const char *str, uint32_t size); +int +sql_bind_array_static(sql_stmt *stmt, int i, const char *str, uint32_t size); + int sql_bind_uuid(struct sql_stmt *stmt, int i, const struct tt_uuid *uuid); diff --git a/src/box/sql/vdbeapi.c b/src/box/sql/vdbeapi.c index 4ce5feeae9909103876130efa89306f97a1beda7..3ea155d17bce81119f44e7a7351cb74432675e49 100644 --- a/src/box/sql/vdbeapi.c +++ b/src/box/sql/vdbeapi.c @@ -524,6 +524,14 @@ sql_bind_bin_static(sql_stmt *stmt, int i, const char *str, uint32_t size) return sql_bind_type(vdbe, i, "text"); } +int +sql_bind_array_static(sql_stmt *stmt, int i, const char *str, uint32_t size) +{ + struct Vdbe *vdbe = (struct Vdbe *)stmt; + mem_set_array_static(&vdbe->aVar[i - 1], (char *)str, size); + return sql_bind_type(vdbe, i, "array"); +} + int sql_bind_uuid(struct sql_stmt *stmt, int i, const struct tt_uuid *uuid) { diff --git a/test/sql-tap/array.test.lua b/test/sql-tap/array.test.lua index 79a1c831dfcc1c104a12458305a9a08e1acb823d..3387742bf974ae5416fda533d596bfe9c0a60f7a 100755 --- a/test/sql-tap/array.test.lua +++ b/test/sql-tap/array.test.lua @@ -1,6 +1,6 @@ #!/usr/bin/env tarantool local test = require("sqltester") -test:plan(115) +test:plan(117) box.schema.func.create('A1', { language = 'Lua', @@ -1024,6 +1024,29 @@ test:do_execsql_test( "array" }) +-- Make sure that ARRAY values can be used as bound variable. +test:do_test( + "builtins-14.1", + function() + local res = box.execute([[SELECT #a;]], {{['#a'] = {1, 2, 3}}}) + return {res.rows[1][1]} + end, { + {1, 2, 3} + }) + +local remote = require('net.box') +box.cfg{listen = os.getenv('LISTEN')} +local cn = remote.connect(box.cfg.listen) +test:do_test( + "builtins-14.2", + function() + local res = cn:execute([[SELECT #a;]], {{['#a'] = {1, 2, 3}}}) + return {res.rows[1][1]} + end, { + {1, 2, 3} + }) +cn:close() + box.execute([[DROP TABLE t1;]]) box.execute([[DROP TABLE t;]]) diff --git a/test/sql/bind.result b/test/sql/bind.result index cb03028854492d214fdcce0817efd53af8adcfc5..f269056e22c98715baaf1ccdfddd0c45f436a89d 100644 --- a/test/sql/bind.result +++ b/test/sql/bind.result @@ -249,13 +249,6 @@ execute('SELECT ? AS big_uint', {0xefffffffffffffff}) - [17293822569102704640] ... -- Bind incorrect parameters. -ok, err = pcall(execute, 'SELECT ?', { {1, 2, 3} }) ---- -... -ok ---- -- false -... parameters = {} --- ... diff --git a/test/sql/bind.test.lua b/test/sql/bind.test.lua index 2ced7775a29ac1a74e8759a0756675efd2350c68..4ad227d95e3923967f166db82046541f2a77f12b 100644 --- a/test/sql/bind.test.lua +++ b/test/sql/bind.test.lua @@ -82,8 +82,6 @@ execute(sql, parameters) -- suitable method in its bind API. execute('SELECT ? AS big_uint', {0xefffffffffffffff}) -- Bind incorrect parameters. -ok, err = pcall(execute, 'SELECT ?', { {1, 2, 3} }) -ok parameters = {} parameters[1] = {} parameters[1][100] = 200