* [tarantool-patches] [PATCH v2 1/2] box: export mpstream methods to core
2018-08-27 11:11 [tarantool-patches] [PATCH v2 0/2] sql: remove struct Enc Kirill Shcherbatov
@ 2018-08-27 11:11 ` Kirill Shcherbatov
2018-08-28 1:43 ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-27 11:11 ` [tarantool-patches] [PATCH v2 2/2] sql: remove struct Enc Kirill Shcherbatov
` (2 subsequent siblings)
3 siblings, 1 reply; 10+ messages in thread
From: Kirill Shcherbatov @ 2018-08-27 11:11 UTC (permalink / raw)
To: tarantool-patches; +Cc: v.shpilevoy, Kirill Shcherbatov
As we going to use mpstream not only in LUA, let's move this
API in tarantool core.
Part of #3545.
---
src/CMakeLists.txt | 1 +
src/box/lua/call.c | 11 +--
src/box/lua/misc.cc | 1 +
src/box/lua/net_box.c | 127 +++++++++++++++----------------
src/box/lua/tuple.c | 23 +++---
src/lua/msgpack.c | 166 ++++------------------------------------
src/lua/msgpack.h | 102 +------------------------
src/mpstream.c | 205 ++++++++++++++++++++++++++++++++++++++++++++++++++
src/mpstream.h | 124 ++++++++++++++++++++++++++++++
9 files changed, 429 insertions(+), 331 deletions(-)
create mode 100644 src/mpstream.c
create mode 100644 src/mpstream.h
diff --git a/src/CMakeLists.txt b/src/CMakeLists.txt
index 7c8b5cc..0407337 100644
--- a/src/CMakeLists.txt
+++ b/src/CMakeLists.txt
@@ -97,6 +97,7 @@ set (core_sources
http_parser.c
coll.c
coll_def.c
+ mpstream.c
)
if (TARGET_OS_NETBSD)
diff --git a/src/box/lua/call.c b/src/box/lua/call.c
index d20cbbb..1f20426 100644
--- a/src/box/lua/call.c
+++ b/src/box/lua/call.c
@@ -42,6 +42,7 @@
#include "small/obuf.h"
#include "lua_sql.h"
#include "trivia/util.h"
+#include "mpstream.h"
/**
* A helper to find a Lua function by name and put it
@@ -175,7 +176,7 @@ luamp_encode_call_16(lua_State *L, struct luaL_serializer *cfg,
* ..., { scalar }, ...`
*/
lua_pushvalue(L, i);
- luamp_encode_array(cfg, stream, 1);
+ mpstream_encode_array(stream, 1);
luamp_encode_r(L, cfg, stream, &field, 0);
lua_pop(L, 1);
} else {
@@ -202,7 +203,7 @@ luamp_encode_call_16(lua_State *L, struct luaL_serializer *cfg,
* `return scalar`
* `return map`
*/
- luamp_encode_array(cfg, stream, 1);
+ mpstream_encode_array(stream, 1);
assert(lua_gettop(L) == 1);
luamp_encode_r(L, cfg, stream, &root, 0);
return 1;
@@ -211,7 +212,7 @@ luamp_encode_call_16(lua_State *L, struct luaL_serializer *cfg,
assert(root.type == MP_ARRAY);
if (root.size == 0) {
/* `return {}` => `{ box.tuple() }` */
- luamp_encode_array(cfg, stream, 0);
+ mpstream_encode_array(stream, 0);
return 1;
}
@@ -230,7 +231,7 @@ luamp_encode_call_16(lua_State *L, struct luaL_serializer *cfg,
* `return { scalar, ... } =>
* box.tuple.new(scalar, ...)`
*/
- luamp_encode_array(cfg, stream, root.size);
+ mpstream_encode_array(stream, root.size);
/*
* Encode the first field of tuple using
* existing information from luaL_tofield
@@ -250,7 +251,7 @@ luamp_encode_call_16(lua_State *L, struct luaL_serializer *cfg,
* `return { tuple/array, ..., scalar, ... } =>
* { tuple/array, ..., { scalar }, ... }`
*/
- luamp_encode_array(cfg, stream, 1);
+ mpstream_encode_array(stream, 1);
luamp_encode_r(L, cfg, stream, &field, 0);
} else {
/* `return { tuple/array, ..., tuple/array, ... }` */
diff --git a/src/box/lua/misc.cc b/src/box/lua/misc.cc
index bc76065..8bd33ae 100644
--- a/src/box/lua/misc.cc
+++ b/src/box/lua/misc.cc
@@ -38,6 +38,7 @@
#include "box/box.h"
#include "box/port.h"
#include "box/lua/tuple.h"
+#include "mpstream.h"
/** {{{ Miscellaneous utils **/
diff --git a/src/box/lua/net_box.c b/src/box/lua/net_box.c
index 308c9c7..a928a4c 100644
--- a/src/box/lua/net_box.c
+++ b/src/box/lua/net_box.c
@@ -47,6 +47,7 @@
#include "coio.h"
#include "box/errcode.h"
#include "lua/fiber.h"
+#include "mpstream.h"
#define cfg luaL_msgpack_default
@@ -68,13 +69,13 @@ netbox_prepare_request(lua_State *L, struct mpstream *stream, uint32_t r_type)
mpstream_advance(stream, fixheader_size);
/* encode header */
- luamp_encode_map(cfg, stream, 2);
+ mpstream_encode_map(stream, 2);
- luamp_encode_uint(cfg, stream, IPROTO_SYNC);
- luamp_encode_uint(cfg, stream, sync);
+ mpstream_encode_uint(stream, IPROTO_SYNC);
+ mpstream_encode_uint(stream, sync);
- luamp_encode_uint(cfg, stream, IPROTO_REQUEST_TYPE);
- luamp_encode_uint(cfg, stream, r_type);
+ mpstream_encode_uint(stream, IPROTO_REQUEST_TYPE);
+ mpstream_encode_uint(stream, r_type);
/* Caller should remember how many bytes was used in ibuf */
return used;
@@ -139,16 +140,16 @@ netbox_encode_auth(lua_State *L)
return luaL_error(L, "Invalid salt");
/* Adapted from xrow_encode_auth() */
- luamp_encode_map(cfg, &stream, password != NULL ? 2 : 1);
- luamp_encode_uint(cfg, &stream, IPROTO_USER_NAME);
- luamp_encode_str(cfg, &stream, user, user_len);
+ mpstream_encode_map(&stream, password != NULL ? 2 : 1);
+ mpstream_encode_uint(&stream, IPROTO_USER_NAME);
+ mpstream_encode_strn(&stream, user, user_len);
if (password != NULL) { /* password can be omitted */
char scramble[SCRAMBLE_SIZE];
scramble_prepare(scramble, salt, password, password_len);
- luamp_encode_uint(cfg, &stream, IPROTO_TUPLE);
- luamp_encode_array(cfg, &stream, 2);
- luamp_encode_str(cfg, &stream, "chap-sha1", strlen("chap-sha1"));
- luamp_encode_str(cfg, &stream, scramble, SCRAMBLE_SIZE);
+ mpstream_encode_uint(&stream, IPROTO_TUPLE);
+ mpstream_encode_array(&stream, 2);
+ mpstream_encode_str(&stream, "chap-sha1");
+ mpstream_encode_strn(&stream, scramble, SCRAMBLE_SIZE);
}
netbox_encode_request(&stream, svp);
@@ -166,16 +167,16 @@ netbox_encode_call_impl(lua_State *L, enum iproto_type type)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, type);
- luamp_encode_map(cfg, &stream, 2);
+ mpstream_encode_map(&stream, 2);
/* encode proc name */
size_t name_len;
const char *name = lua_tolstring(L, 3, &name_len);
- luamp_encode_uint(cfg, &stream, IPROTO_FUNCTION_NAME);
- luamp_encode_str(cfg, &stream, name, name_len);
+ mpstream_encode_uint(&stream, IPROTO_FUNCTION_NAME);
+ mpstream_encode_strn(&stream, name, name_len);
/* encode args */
- luamp_encode_uint(cfg, &stream, IPROTO_TUPLE);
+ mpstream_encode_uint(&stream, IPROTO_TUPLE);
luamp_encode_tuple(L, cfg, &stream, 4);
netbox_encode_request(&stream, svp);
@@ -205,16 +206,16 @@ netbox_encode_eval(lua_State *L)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, IPROTO_EVAL);
- luamp_encode_map(cfg, &stream, 2);
+ mpstream_encode_map(&stream, 2);
/* encode expr */
size_t expr_len;
const char *expr = lua_tolstring(L, 3, &expr_len);
- luamp_encode_uint(cfg, &stream, IPROTO_EXPR);
- luamp_encode_str(cfg, &stream, expr, expr_len);
+ mpstream_encode_uint(&stream, IPROTO_EXPR);
+ mpstream_encode_strn(&stream, expr, expr_len);
/* encode args */
- luamp_encode_uint(cfg, &stream, IPROTO_TUPLE);
+ mpstream_encode_uint(&stream, IPROTO_TUPLE);
luamp_encode_tuple(L, cfg, &stream, 4);
netbox_encode_request(&stream, svp);
@@ -233,7 +234,7 @@ netbox_encode_select(lua_State *L)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, IPROTO_SELECT);
- luamp_encode_map(cfg, &stream, 6);
+ mpstream_encode_map(&stream, 6);
uint32_t space_id = lua_tonumber(L, 3);
uint32_t index_id = lua_tonumber(L, 4);
@@ -242,27 +243,27 @@ netbox_encode_select(lua_State *L)
uint32_t limit = lua_tonumber(L, 7);
/* encode space_id */
- luamp_encode_uint(cfg, &stream, IPROTO_SPACE_ID);
- luamp_encode_uint(cfg, &stream, space_id);
+ mpstream_encode_uint(&stream, IPROTO_SPACE_ID);
+ mpstream_encode_uint(&stream, space_id);
/* encode index_id */
- luamp_encode_uint(cfg, &stream, IPROTO_INDEX_ID);
- luamp_encode_uint(cfg, &stream, index_id);
+ mpstream_encode_uint(&stream, IPROTO_INDEX_ID);
+ mpstream_encode_uint(&stream, index_id);
/* encode iterator */
- luamp_encode_uint(cfg, &stream, IPROTO_ITERATOR);
- luamp_encode_uint(cfg, &stream, iterator);
+ mpstream_encode_uint(&stream, IPROTO_ITERATOR);
+ mpstream_encode_uint(&stream, iterator);
/* encode offset */
- luamp_encode_uint(cfg, &stream, IPROTO_OFFSET);
- luamp_encode_uint(cfg, &stream, offset);
+ mpstream_encode_uint(&stream, IPROTO_OFFSET);
+ mpstream_encode_uint(&stream, offset);
/* encode limit */
- luamp_encode_uint(cfg, &stream, IPROTO_LIMIT);
- luamp_encode_uint(cfg, &stream, limit);
+ mpstream_encode_uint(&stream, IPROTO_LIMIT);
+ mpstream_encode_uint(&stream, limit);
/* encode key */
- luamp_encode_uint(cfg, &stream, IPROTO_KEY);
+ mpstream_encode_uint(&stream, IPROTO_KEY);
luamp_convert_key(L, cfg, &stream, 8);
netbox_encode_request(&stream, svp);
@@ -279,15 +280,15 @@ netbox_encode_insert_or_replace(lua_State *L, uint32_t reqtype)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, reqtype);
- luamp_encode_map(cfg, &stream, 2);
+ mpstream_encode_map(&stream, 2);
/* encode space_id */
uint32_t space_id = lua_tonumber(L, 3);
- luamp_encode_uint(cfg, &stream, IPROTO_SPACE_ID);
- luamp_encode_uint(cfg, &stream, space_id);
+ mpstream_encode_uint(&stream, IPROTO_SPACE_ID);
+ mpstream_encode_uint(&stream, space_id);
/* encode args */
- luamp_encode_uint(cfg, &stream, IPROTO_TUPLE);
+ mpstream_encode_uint(&stream, IPROTO_TUPLE);
luamp_encode_tuple(L, cfg, &stream, 4);
netbox_encode_request(&stream, svp);
@@ -317,20 +318,20 @@ netbox_encode_delete(lua_State *L)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, IPROTO_DELETE);
- luamp_encode_map(cfg, &stream, 3);
+ mpstream_encode_map(&stream, 3);
/* encode space_id */
uint32_t space_id = lua_tonumber(L, 3);
- luamp_encode_uint(cfg, &stream, IPROTO_SPACE_ID);
- luamp_encode_uint(cfg, &stream, space_id);
+ mpstream_encode_uint(&stream, IPROTO_SPACE_ID);
+ mpstream_encode_uint(&stream, space_id);
/* encode space_id */
uint32_t index_id = lua_tonumber(L, 4);
- luamp_encode_uint(cfg, &stream, IPROTO_INDEX_ID);
- luamp_encode_uint(cfg, &stream, index_id);
+ mpstream_encode_uint(&stream, IPROTO_INDEX_ID);
+ mpstream_encode_uint(&stream, index_id);
/* encode key */
- luamp_encode_uint(cfg, &stream, IPROTO_KEY);
+ mpstream_encode_uint(&stream, IPROTO_KEY);
luamp_convert_key(L, cfg, &stream, 5);
netbox_encode_request(&stream, svp);
@@ -348,30 +349,30 @@ netbox_encode_update(lua_State *L)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, IPROTO_UPDATE);
- luamp_encode_map(cfg, &stream, 5);
+ mpstream_encode_map(&stream, 5);
/* encode space_id */
uint32_t space_id = lua_tonumber(L, 3);
- luamp_encode_uint(cfg, &stream, IPROTO_SPACE_ID);
- luamp_encode_uint(cfg, &stream, space_id);
+ mpstream_encode_uint(&stream, IPROTO_SPACE_ID);
+ mpstream_encode_uint(&stream, space_id);
/* encode index_id */
uint32_t index_id = lua_tonumber(L, 4);
- luamp_encode_uint(cfg, &stream, IPROTO_INDEX_ID);
- luamp_encode_uint(cfg, &stream, index_id);
+ mpstream_encode_uint(&stream, IPROTO_INDEX_ID);
+ mpstream_encode_uint(&stream, index_id);
/* encode index_id */
- luamp_encode_uint(cfg, &stream, IPROTO_INDEX_BASE);
- luamp_encode_uint(cfg, &stream, 1);
+ mpstream_encode_uint(&stream, IPROTO_INDEX_BASE);
+ mpstream_encode_uint(&stream, 1);
/* encode in reverse order for speedup - see luamp_encode() code */
/* encode ops */
- luamp_encode_uint(cfg, &stream, IPROTO_TUPLE);
+ mpstream_encode_uint(&stream, IPROTO_TUPLE);
luamp_encode_tuple(L, cfg, &stream, 6);
lua_pop(L, 1); /* ops */
/* encode key */
- luamp_encode_uint(cfg, &stream, IPROTO_KEY);
+ mpstream_encode_uint(&stream, IPROTO_KEY);
luamp_convert_key(L, cfg, &stream, 5);
netbox_encode_request(&stream, svp);
@@ -389,25 +390,25 @@ netbox_encode_upsert(lua_State *L)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, IPROTO_UPSERT);
- luamp_encode_map(cfg, &stream, 4);
+ mpstream_encode_map(&stream, 4);
/* encode space_id */
uint32_t space_id = lua_tonumber(L, 3);
- luamp_encode_uint(cfg, &stream, IPROTO_SPACE_ID);
- luamp_encode_uint(cfg, &stream, space_id);
+ mpstream_encode_uint(&stream, IPROTO_SPACE_ID);
+ mpstream_encode_uint(&stream, space_id);
/* encode index_base */
- luamp_encode_uint(cfg, &stream, IPROTO_INDEX_BASE);
- luamp_encode_uint(cfg, &stream, 1);
+ mpstream_encode_uint(&stream, IPROTO_INDEX_BASE);
+ mpstream_encode_uint(&stream, 1);
/* encode in reverse order for speedup - see luamp_encode() code */
/* encode ops */
- luamp_encode_uint(cfg, &stream, IPROTO_OPS);
+ mpstream_encode_uint(&stream, IPROTO_OPS);
luamp_encode_tuple(L, cfg, &stream, 5);
lua_pop(L, 1); /* ops */
/* encode tuple */
- luamp_encode_uint(cfg, &stream, IPROTO_TUPLE);
+ mpstream_encode_uint(&stream, IPROTO_TUPLE);
luamp_encode_tuple(L, cfg, &stream, 4);
netbox_encode_request(&stream, svp);
@@ -566,17 +567,17 @@ netbox_encode_execute(lua_State *L)
struct mpstream stream;
size_t svp = netbox_prepare_request(L, &stream, IPROTO_EXECUTE);
- luamp_encode_map(cfg, &stream, 3);
+ mpstream_encode_map(&stream, 3);
size_t len;
const char *query = lua_tolstring(L, 3, &len);
- luamp_encode_uint(cfg, &stream, IPROTO_SQL_TEXT);
- luamp_encode_str(cfg, &stream, query, len);
+ mpstream_encode_uint(&stream, IPROTO_SQL_TEXT);
+ mpstream_encode_strn(&stream, query, len);
- luamp_encode_uint(cfg, &stream, IPROTO_SQL_BIND);
+ mpstream_encode_uint(&stream, IPROTO_SQL_BIND);
luamp_encode_tuple(L, cfg, &stream, 4);
- luamp_encode_uint(cfg, &stream, IPROTO_OPTIONS);
+ mpstream_encode_uint(&stream, IPROTO_OPTIONS);
luamp_encode_tuple(L, cfg, &stream, 5);
netbox_encode_request(&stream, svp);
diff --git a/src/box/lua/tuple.c b/src/box/lua/tuple.c
index 22fe696..126466c 100644
--- a/src/box/lua/tuple.c
+++ b/src/box/lua/tuple.c
@@ -42,6 +42,7 @@
#include "box/tuple_convert.h"
#include "box/errcode.h"
#include "json/path.h"
+#include "mpstream.h"
/** {{{ box.tuple Lua library
*
@@ -111,7 +112,7 @@ lbox_tuple_new(lua_State *L)
luamp_encode_tuple(L, luaL_msgpack_default, &stream, 1);
} else {
/* Backward-compatible format: box.tuple.new(1, 2, 3). */
- luamp_encode_array(luaL_msgpack_default, &stream, argc);
+ mpstream_encode_array(&stream, argc);
for (int k = 1; k <= argc; ++k) {
luamp_encode(L, luaL_msgpack_default, &stream, k);
}
@@ -228,9 +229,9 @@ luamp_convert_key(struct lua_State *L, struct luaL_serializer *cfg,
luamp_encode_r(L, cfg, stream, &field, 0);
lua_pop(L, 1);
} else if (field.type == MP_NIL) {
- luamp_encode_array(cfg, stream, 0);
+ mpstream_encode_array(stream, 0);
} else {
- luamp_encode_array(cfg, stream, 1);
+ mpstream_encode_array(stream, 1);
lua_pushvalue(L, index);
luamp_encode_r(L, cfg, stream, &field, 0);
lua_pop(L, 1);
@@ -393,18 +394,18 @@ lbox_tuple_transform(struct lua_State *L)
/*
* Prepare UPDATE expression
*/
- luamp_encode_array(luaL_msgpack_default, &stream, op_cnt);
+ mpstream_encode_array(&stream, op_cnt);
if (len > 0) {
- luamp_encode_array(luaL_msgpack_default, &stream, 3);
- luamp_encode_str(luaL_msgpack_default, &stream, "#", 1);
- luamp_encode_uint(luaL_msgpack_default, &stream, offset);
- luamp_encode_uint(luaL_msgpack_default, &stream, len);
+ 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--) {
- luamp_encode_array(luaL_msgpack_default, &stream, 3);
- luamp_encode_str(luaL_msgpack_default, &stream, "!", 1);
- luamp_encode_uint(luaL_msgpack_default, &stream, offset);
+ 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);
diff --git a/src/lua/msgpack.c b/src/lua/msgpack.c
index acd860a..b470060 100644
--- a/src/lua/msgpack.c
+++ b/src/lua/msgpack.c
@@ -29,7 +29,7 @@
* SUCH DAMAGE.
*/
#include "lua/msgpack.h"
-
+#include "mpstream.h"
#include "lua/utils.h"
#if defined(LUAJIT)
@@ -50,46 +50,6 @@ luamp_error(void *error_ctx)
luaL_error(L, diag_last_error(diag_get())->errmsg);
}
-void
-mpstream_init(struct mpstream *stream, void *ctx,
- luamp_reserve_f reserve, luamp_alloc_f alloc,
- luamp_error_f error, void *error_ctx)
-{
- stream->ctx = ctx;
- stream->reserve = reserve;
- stream->alloc = alloc;
- stream->error = error;
- stream->error_ctx = error_ctx;
- mpstream_reset(stream);
-}
-
-void
-mpstream_reserve_slow(struct mpstream *stream, size_t size)
-{
- stream->alloc(stream->ctx, stream->pos - stream->buf);
- stream->buf = (char *) stream->reserve(stream->ctx, &size);
- if (stream->buf == NULL) {
- diag_set(OutOfMemory, size, "mpstream", "reserve");
- stream->error(stream->error_ctx);
- }
- stream->pos = stream->buf;
- stream->end = stream->pos + size;
-}
-
-void
-mpstream_reset(struct mpstream *stream)
-{
- size_t size = 0;
- stream->buf = (char *) stream->reserve(stream->ctx, &size);
- if (stream->buf == NULL) {
- diag_set(OutOfMemory, size, "mpstream", "reset");
- stream->error(stream->error_ctx);
- }
- stream->pos = stream->buf;
- stream->end = stream->pos + size;
-}
-
-
static uint32_t CTID_CHAR_PTR;
static uint32_t CTID_STRUCT_IBUF;
@@ -107,104 +67,6 @@ static luamp_encode_extension_f luamp_encode_extension =
static luamp_decode_extension_f luamp_decode_extension =
luamp_decode_extension_default;
-void
-luamp_encode_array(struct luaL_serializer *cfg, struct mpstream *stream,
- uint32_t size)
-{
- (void) cfg;
- assert(mp_sizeof_array(size) <= 5);
- char *data = mpstream_reserve(stream, 5);
- char *pos = mp_encode_array(data, size);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_map(struct luaL_serializer *cfg, struct mpstream *stream,
- uint32_t size)
-{
- (void) cfg;
- assert(mp_sizeof_map(size) <= 5);
- char *data = mpstream_reserve(stream, 5);
- char *pos = mp_encode_map(data, size);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_uint(struct luaL_serializer *cfg, struct mpstream *stream,
- uint64_t num)
-{
- (void) cfg;
- assert(mp_sizeof_uint(num) <= 9);
- char *data = mpstream_reserve(stream, 9);
- char *pos = mp_encode_uint(data, num);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_int(struct luaL_serializer *cfg, struct mpstream *stream,
- int64_t num)
-{
- (void) cfg;
- assert(mp_sizeof_int(num) <= 9);
- char *data = mpstream_reserve(stream, 9);
- char *pos = mp_encode_int(data, num);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_float(struct luaL_serializer *cfg, struct mpstream *stream,
- float num)
-{
- (void) cfg;
- assert(mp_sizeof_float(num) <= 5);
- char *data = mpstream_reserve(stream, 5);
- char *pos = mp_encode_float(data, num);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_double(struct luaL_serializer *cfg, struct mpstream *stream,
- double num)
-{
- (void) cfg;
- assert(mp_sizeof_double(num) <= 9);
- char *data = mpstream_reserve(stream, 9);
- char *pos = mp_encode_double(data, num);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_str(struct luaL_serializer *cfg, struct mpstream *stream,
- const char *str, uint32_t len)
-{
- (void) cfg;
- assert(mp_sizeof_str(len) <= 5 + len);
- char *data = mpstream_reserve(stream, 5 + len);
- char *pos = mp_encode_str(data, str, len);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_nil(struct luaL_serializer *cfg, struct mpstream *stream)
-{
- (void) cfg;
- assert(mp_sizeof_nil() <= 1);
- char *data = mpstream_reserve(stream, 1);
- char *pos = mp_encode_nil(data);
- mpstream_advance(stream, pos - data);
-}
-
-void
-luamp_encode_bool(struct luaL_serializer *cfg, struct mpstream *stream,
- bool val)
-{
- (void) cfg;
- assert(mp_sizeof_bool(val) <= 1);
- char *data = mpstream_reserve(stream, 1);
- char *pos = mp_encode_bool(data, val);
- mpstream_advance(stream, pos - data);
-}
-
static enum mp_type
luamp_encode_extension_default(struct lua_State *L, int idx,
struct mpstream *stream)
@@ -254,38 +116,36 @@ luamp_encode_r(struct lua_State *L, struct luaL_serializer *cfg,
restart: /* used by MP_EXT */
switch (field->type) {
case MP_UINT:
- luamp_encode_uint(cfg, stream, field->ival);
+ mpstream_encode_uint(stream, field->ival);
return MP_UINT;
case MP_STR:
- luamp_encode_str(cfg, stream, field->sval.data,
- field->sval.len);
+ mpstream_encode_strn(stream, field->sval.data, field->sval.len);
return MP_STR;
case MP_BIN:
- luamp_encode_str(cfg, stream, field->sval.data,
- field->sval.len);
+ mpstream_encode_strn(stream, field->sval.data, field->sval.len);
return MP_BIN;
case MP_INT:
- luamp_encode_int(cfg, stream, field->ival);
+ mpstream_encode_int(stream, field->ival);
return MP_INT;
case MP_FLOAT:
- luamp_encode_float(cfg, stream, field->fval);
+ mpstream_encode_float(stream, field->fval);
return MP_FLOAT;
case MP_DOUBLE:
- luamp_encode_double(cfg, stream, field->dval);
+ mpstream_encode_double(stream, field->dval);
return MP_DOUBLE;
case MP_BOOL:
- luamp_encode_bool(cfg, stream, field->bval);
+ mpstream_encode_bool(stream, field->bval);
return MP_BOOL;
case MP_NIL:
- luamp_encode_nil(cfg, stream);
+ mpstream_encode_nil(stream);
return MP_NIL;
case MP_MAP:
/* Map */
if (level >= cfg->encode_max_depth) {
- luamp_encode_nil(cfg, stream); /* Limit nested maps */
+ mpstream_encode_nil(stream); /* Limit nested maps */
return MP_NIL;
}
- luamp_encode_map(cfg, stream, field->size);
+ mpstream_encode_map(stream, field->size);
lua_pushnil(L); /* first key */
while (lua_next(L, top) != 0) {
lua_pushvalue(L, -2); /* push a copy of key to top */
@@ -301,11 +161,11 @@ restart: /* used by MP_EXT */
case MP_ARRAY:
/* Array */
if (level >= cfg->encode_max_depth) {
- luamp_encode_nil(cfg, stream); /* Limit nested arrays */
+ mpstream_encode_nil(stream); /* Limit nested arrays */
return MP_NIL;
}
uint32_t size = field->size;
- luamp_encode_array(cfg, stream, size);
+ mpstream_encode_array(stream, size);
for (uint32_t i = 0; i < size; i++) {
lua_rawgeti(L, top, i + 1);
luaL_tofield(L, cfg, top + 1, field);
diff --git a/src/lua/msgpack.h b/src/lua/msgpack.h
index bacf3e0..d0ade30 100644
--- a/src/lua/msgpack.h
+++ b/src/lua/msgpack.h
@@ -1,7 +1,7 @@
#ifndef TARANTOOL_LUA_MSGPACK_H_INCLUDED
#define TARANTOOL_LUA_MSGPACK_H_INCLUDED
/*
- * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
+ * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS file.
*
* Redistribution and use in source and binary forms, with or
* without modification, are permitted provided that the following
@@ -42,6 +42,8 @@ extern "C" {
#include <lua.h>
struct luaL_serializer;
+struct mpstream;
+
/**
* Default instance of msgpack serializer (msgpack = require('msgpack')).
* This instance is used by all box's Lua/C API bindings (e.g. space:replace()).
@@ -51,111 +53,13 @@ struct luaL_serializer;
extern struct luaL_serializer *luaL_msgpack_default;
/**
- * A streaming API so that it's possible to encode to any output
- * stream.
- */
-
-/**
- * Ask the allocator to reserve at least size bytes. It can reserve
- * more, and update *size with the new size.
- */
-typedef void *(*luamp_reserve_f)(void *ctx, size_t *size);
-
-/** Actually use the bytes. */
-typedef void *(*luamp_alloc_f)(void *ctx, size_t size);
-
-/** Actually use the bytes. */
-typedef void (*luamp_error_f)(void *error_ctx);
-
-struct mpstream {
- /**
- * When pos >= end, or required size doesn't fit in
- * pos..end range alloc() is called to advance the stream
- * and reserve() to get a new chunk.
- */
- char *buf, *pos, *end;
- void *ctx;
- luamp_reserve_f reserve;
- luamp_alloc_f alloc;
- luamp_error_f error;
- void *error_ctx;
-};
-
-/**
* luaL_error()
*/
void
luamp_error(void *);
-void
-mpstream_init(struct mpstream *stream, void *ctx,
- luamp_reserve_f reserve, luamp_alloc_f alloc,
- luamp_error_f error, void *error_ctx);
-
-void
-mpstream_reset(struct mpstream *stream);
-
-void
-mpstream_reserve_slow(struct mpstream *stream, size_t size);
-
-static inline void
-mpstream_flush(struct mpstream *stream)
-{
- stream->alloc(stream->ctx, stream->pos - stream->buf);
- stream->buf = stream->pos;
-}
-
-static inline char *
-mpstream_reserve(struct mpstream *stream, size_t size)
-{
- if (stream->pos + size > stream->end)
- mpstream_reserve_slow(stream, size);
- return stream->pos;
-}
-
-static inline void
-mpstream_advance(struct mpstream *stream, size_t size)
-{
- assert(stream->pos + size <= stream->end);
- stream->pos += size;
-}
-
enum { LUAMP_ALLOC_FACTOR = 256 };
-void
-luamp_encode_array(struct luaL_serializer *cfg, struct mpstream *stream,
- uint32_t size);
-
-void
-luamp_encode_map(struct luaL_serializer *cfg, struct mpstream *stream, uint32_t size);
-
-void
-luamp_encode_uint(struct luaL_serializer *cfg, struct mpstream *stream,
- uint64_t num);
-
-void
-luamp_encode_int(struct luaL_serializer *cfg, struct mpstream *stream,
- int64_t num);
-
-void
-luamp_encode_float(struct luaL_serializer *cfg, struct mpstream *stream,
- float num);
-
-void
-luamp_encode_double(struct luaL_serializer *cfg, struct mpstream *stream,
- double num);
-
-void
-luamp_encode_str(struct luaL_serializer *cfg, struct mpstream *stream,
- const char *str, uint32_t len);
-
-void
-luamp_encode_nil(struct luaL_serializer *cfg, struct mpstream *stream);
-
-void
-luamp_encode_bool(struct luaL_serializer *cfg, struct mpstream *stream,
- bool val);
-
/* low-level function needed for execute_lua_call() */
enum mp_type
luamp_encode_r(struct lua_State *L, struct luaL_serializer *cfg,
diff --git a/src/mpstream.c b/src/mpstream.c
new file mode 100644
index 0000000..23d27f9
--- /dev/null
+++ b/src/mpstream.c
@@ -0,0 +1,205 @@
+/*
+ * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "mpstream.h"
+#include <assert.h>
+#include <stdint.h>
+#include "msgpuck.h"
+
+void
+mpstream_reserve_slow(struct mpstream *stream, size_t size)
+{
+ stream->alloc(stream->ctx, stream->pos - stream->buf);
+ stream->buf = (char *) stream->reserve(stream->ctx, &size);
+ if (stream->buf == NULL) {
+ diag_set(OutOfMemory, size, "mpstream", "reserve");
+ stream->error(stream->error_ctx);
+ }
+ stream->pos = stream->buf;
+ stream->end = stream->pos + size;
+}
+
+void
+mpstream_reset(struct mpstream *stream)
+{
+ size_t size = 0;
+ stream->buf = (char *) stream->reserve(stream->ctx, &size);
+ if (stream->buf == NULL) {
+ diag_set(OutOfMemory, size, "mpstream", "reset");
+ stream->error(stream->error_ctx);
+ }
+ stream->pos = stream->buf;
+ stream->end = stream->pos + size;
+}
+
+/**
+ * A streaming API so that it's possible to encode to any output
+ * stream.
+ */
+void
+mpstream_init(struct mpstream *stream, void *ctx,
+ mpstream_reserve_f reserve, mpstream_alloc_f alloc,
+ mpstream_error_f error, void *error_ctx)
+{
+ stream->ctx = ctx;
+ stream->reserve = reserve;
+ stream->alloc = alloc;
+ stream->error = error;
+ stream->error_ctx = error_ctx;
+ mpstream_reset(stream);
+}
+
+void
+mpstream_flush(struct mpstream *stream)
+{
+ stream->alloc(stream->ctx, stream->pos - stream->buf);
+ stream->buf = stream->pos;
+}
+
+char *
+mpstream_reserve(struct mpstream *stream, size_t size)
+{
+ if (stream->pos + size > stream->end)
+ mpstream_reserve_slow(stream, size);
+ return stream->pos;
+}
+
+void
+mpstream_advance(struct mpstream *stream, size_t size)
+{
+ assert(stream->pos + size <= stream->end);
+ stream->pos += size;
+}
+
+void
+mpstream_encode_array(struct mpstream *stream, uint32_t size)
+{
+ assert(mp_sizeof_array(size) <= 5);
+ char *data = mpstream_reserve(stream, 5);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_array(data, size);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_map(struct mpstream *stream, uint32_t size)
+{
+ assert(mp_sizeof_map(size) <= 5);
+ char *data = mpstream_reserve(stream, 5);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_map(data, size);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_uint(struct mpstream *stream, uint64_t num)
+{
+ assert(mp_sizeof_uint(num) <= 9);
+ char *data = mpstream_reserve(stream, 9);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_uint(data, num);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_int(struct mpstream *stream, int64_t num)
+{
+ assert(mp_sizeof_int(num) <= 9);
+ char *data = mpstream_reserve(stream, 9);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_int(data, num);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_float(struct mpstream *stream, float num)
+{
+ assert(mp_sizeof_float(num) <= 5);
+ char *data = mpstream_reserve(stream, 5);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_float(data, num);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_double(struct mpstream *stream, double num)
+{
+ assert(mp_sizeof_double(num) <= 9);
+ char *data = mpstream_reserve(stream, 9);
+ char *pos = mp_encode_double(data, num);
+ if (data == NULL)
+ return;
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_strn(struct mpstream *stream, const char *str, uint32_t len)
+{
+ assert(mp_sizeof_str(len) <= 5 + len);
+ char *data = mpstream_reserve(stream, 5 + len);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_str(data, str, len);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_str(struct mpstream *stream, const char *str)
+{
+ mpstream_encode_strn(stream, str, strlen(str));
+}
+
+void
+mpstream_encode_nil(struct mpstream *stream)
+{
+ assert(mp_sizeof_nil() <= 1);
+ char *data = mpstream_reserve(stream, 1);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_nil(data);
+ mpstream_advance(stream, pos - data);
+}
+
+void
+mpstream_encode_bool(struct mpstream *stream, bool val)
+{
+ assert(mp_sizeof_bool(val) <= 1);
+ char *data = mpstream_reserve(stream, 1);
+ if (data == NULL)
+ return;
+ char *pos = mp_encode_bool(data, val);
+ mpstream_advance(stream, pos - data);
+}
diff --git a/src/mpstream.h b/src/mpstream.h
new file mode 100644
index 0000000..789bd74
--- /dev/null
+++ b/src/mpstream.h
@@ -0,0 +1,124 @@
+#ifndef TARANTOOL_LUA_MPSTREAM_H_INCLUDED
+#define TARANTOOL_LUA_MPSTREAM_H_INCLUDED
+/*
+ * Copyright 2010-2015, Tarantool AUTHORS, please see AUTHORS file.
+ *
+ * Redistribution and use in source and binary forms, with or
+ * without modification, are permitted provided that the following
+ * conditions are met:
+ *
+ * 1. Redistributions of source code must retain the above
+ * copyright notice, this list of conditions and the
+ * following disclaimer.
+ *
+ * 2. Redistributions in binary form must reproduce the above
+ * copyright notice, this list of conditions and the following
+ * disclaimer in the documentation and/or other materials
+ * provided with the distribution.
+ *
+ * THIS SOFTWARE IS PROVIDED BY <COPYRIGHT HOLDER> ``AS IS'' AND
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL
+ * <COPYRIGHT HOLDER> OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS; OR
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY OF
+ * SUCH DAMAGE.
+ */
+
+#include "diag.h"
+
+#if defined(__cplusplus)
+extern "C" {
+#endif /* defined(__cplusplus) */
+
+/**
+* Ask the allocator to reserve at least size bytes. It can reserve
+* more, and update *size with the new size.
+*/
+typedef void *(*mpstream_reserve_f)(void *ctx, size_t *size);
+
+/** Actually use the bytes. */
+typedef void *(*mpstream_alloc_f)(void *ctx, size_t size);
+
+/** Actually use the bytes. */
+typedef void (*mpstream_error_f)(void *error_ctx);
+
+struct mpstream {
+ /**
+ * When pos >= end, or required size doesn't fit in
+ * pos..end range alloc() is called to advance the stream
+ * and reserve() to get a new chunk.
+ */
+ char *buf, *pos, *end;
+ void *ctx;
+ mpstream_reserve_f reserve;
+ mpstream_alloc_f alloc;
+ mpstream_error_f error;
+ void *error_ctx;
+};
+
+void
+mpstream_reserve_slow(struct mpstream *stream, size_t size);
+
+void
+mpstream_reset(struct mpstream *stream);
+
+/**
+ * A streaming API so that it's possible to encode to any output
+ * stream.
+ */
+void
+mpstream_init(struct mpstream *stream, void *ctx,
+ mpstream_reserve_f reserve, mpstream_alloc_f alloc,
+ mpstream_error_f error, void *error_ctx);
+
+void
+mpstream_flush(struct mpstream *stream);
+
+char *
+mpstream_reserve(struct mpstream *stream, size_t size);
+
+void
+mpstream_advance(struct mpstream *stream, size_t size);
+
+void
+mpstream_encode_array(struct mpstream *stream, uint32_t size);
+
+void
+mpstream_encode_map(struct mpstream *stream, uint32_t size);
+
+void
+mpstream_encode_uint(struct mpstream *stream, uint64_t num);
+
+void
+mpstream_encode_int(struct mpstream *stream, int64_t num);
+
+void
+mpstream_encode_float(struct mpstream *stream, float num);
+
+void
+mpstream_encode_double(struct mpstream *stream, double num);
+
+void
+mpstream_encode_strn(struct mpstream *stream, const char *str, uint32_t len);
+
+void
+mpstream_encode_str(struct mpstream *stream, const char *str);
+
+void
+mpstream_encode_nil(struct mpstream *stream);
+
+void
+mpstream_encode_bool(struct mpstream *stream, bool val);
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
+
+#endif /* TARANTOOL_LUA_MPSTREAM_H_INCLUDED */
--
2.7.4
^ permalink raw reply [flat|nested] 10+ messages in thread
* [tarantool-patches] [PATCH v2 2/2] sql: remove struct Enc
2018-08-27 11:11 [tarantool-patches] [PATCH v2 0/2] sql: remove struct Enc Kirill Shcherbatov
2018-08-27 11:11 ` [tarantool-patches] [PATCH v2 1/2] box: export mpstream methods to core Kirill Shcherbatov
@ 2018-08-27 11:11 ` Kirill Shcherbatov
2018-08-28 1:43 ` [tarantool-patches] " Vladislav Shpilevoy
2018-08-28 1:43 ` [tarantool-patches] Re: [PATCH v2 0/2] " Vladislav Shpilevoy
2018-08-29 14:12 ` Kirill Yukhin
3 siblings, 1 reply; 10+ messages in thread
From: Kirill Shcherbatov @ 2018-08-27 11:11 UTC (permalink / raw)
To: tarantool-patches; +Cc: v.shpilevoy, Kirill Shcherbatov
We shouldn't use legacy Enc structure in SQL as we have
featured class mpstream in tarantool core. With this path
all allocations temporally commited with mpstream initialized
on region and then duplicated in dynamic persistent memory via
sqlite3DbMallocRaw.
Closes #3545.
---
src/box/sql.c | 473 +++++++++++++++++++++++----------------------
src/box/sql/build.c | 156 ++++++++-------
src/box/sql/tarantoolInt.h | 80 +++++---
src/box/sql/trigger.c | 62 +++---
4 files changed, 416 insertions(+), 355 deletions(-)
diff --git a/src/box/sql.c b/src/box/sql.c
index b98593b..6bf832b 100644
--- a/src/box/sql.c
+++ b/src/box/sql.c
@@ -56,6 +56,8 @@
#include "xrow.h"
#include "iproto_constants.h"
#include "fkey.h"
+#include "mpstream.h"
+#include "small/region.h"
static sqlite3 *db = NULL;
@@ -840,6 +842,32 @@ rename_fail:
return SQL_TARANTOOL_ERROR;
}
+/** Callback to forward and error from mpstream methods. */
+static void
+set_encode_error(void *error_ctx)
+{
+ *(bool *)error_ctx = true;
+}
+
+void
+mpstream_encode_index_opts(struct mpstream *stream, struct index_opts *opts)
+{
+ mpstream_encode_map(stream, 2);
+ /* Mark as unique pk and unique indexes */
+ mpstream_encode_str(stream, "unique");
+ /* If user didn't defined ON CONFLICT OPTIONS, all uniqueness checks
+ * will be made by Tarantool. However, Tarantool doesn't have ON
+ * CONFLIT option, so in that case (except ON CONFLICT ABORT, which is
+ * default behavior) uniqueness will be checked by SQL.
+ * INSERT OR REPLACE/IGNORE uniqueness checks will be also done by
+ * Tarantool.
+ */
+ mpstream_encode_bool(stream, opts->is_unique);
+ mpstream_encode_str(stream, "sql");
+ mpstream_encode_strn(stream, opts->sql,
+ opts->sql != NULL ? strlen(opts->sql) : 0);
+}
+
int
sql_index_update_table_name(struct index_def *def, const char *new_tbl_name,
char **sql_stmt)
@@ -851,33 +879,43 @@ sql_index_update_table_name(struct index_def *def, const char *new_tbl_name,
if (*sql_stmt == NULL)
return -1;
- uint32_t key_len = mp_sizeof_uint(def->space_id) +
- mp_sizeof_uint(def->iid) + mp_sizeof_array(2);
+ struct region *region = &fiber()->gc;
+ 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);
+
+ /* Encode key. */
+ mpstream_encode_array(&stream, 2);
+ mpstream_encode_uint(&stream, def->space_id);
+ mpstream_encode_uint(&stream, def->iid);
+
+ /* Encode op. */
+ uint32_t op_offset = stream.pos - stream.buf;
+ mpstream_encode_array(&stream, 1);
+ mpstream_encode_array(&stream, 3);
+ mpstream_encode_str(&stream, "=");
+ mpstream_encode_uint(&stream, BOX_INDEX_FIELD_OPTS);
+
+ /* Encode index opts. */
struct index_opts opts = def->opts;
opts.sql = *sql_stmt;
- uint32_t new_opts_sz = sql_encode_index_opts(&opts, NULL);
- uint32_t op_sz = mp_sizeof_array(1) + mp_sizeof_array(3) +
- mp_sizeof_str(1) + mp_sizeof_uint(4) + new_opts_sz;
+ mpstream_encode_index_opts(&stream, &opts);
- char *key_begin = (char*) region_alloc(&fiber()->gc, key_len + op_sz);
- if (key_begin == NULL) {
- diag_set(OutOfMemory, key_len + op_sz, "region_alloc",
- "key_begin");
+ mpstream_flush(&stream);
+ if (is_error) {
+ diag_set(OutOfMemory, stream.pos - stream.buf,
+ "mpstream_flush", "stream");
return -1;
}
- char *key = mp_encode_array(key_begin, 2);
- key = mp_encode_uint(key, def->space_id);
- key = mp_encode_uint(key, def->iid);
-
- char *op_begin = key;
- char *op = mp_encode_array(op_begin, 1);
- op = mp_encode_array(op, 3);
- op = mp_encode_str(op, "=", 1);
- op = mp_encode_uint(op, BOX_INDEX_FIELD_OPTS);
- op += sql_encode_index_opts(&opts, op);
-
- if (box_update(BOX_INDEX_ID, 0, key_begin, key, op_begin, op,
- 0, NULL) != 0)
+ size_t sz = region_used(region) - used;
+ char *raw = region_join(region, sz);
+ if (raw == NULL)
+ diag_set(OutOfMemory, sz, "region_join", "raw");
+
+ if (box_update(BOX_INDEX_ID, 0, raw, raw + op_offset, raw + op_offset,
+ raw + sz, 0, NULL) != 0)
return -1;
return 0;
@@ -1233,66 +1271,6 @@ void tarantoolSqlite3LoadSchema(struct init_data *init)
*/
/*
- * Resulting data is of the variable length. Routines are called twice:
- * 1. with a NULL buffer, yielding result size estimation;
- * 2. with a buffer of the estimated size, rendering the result.
- *
- * For convenience, formatting routines use Enc structure to call
- * Enc is either configured to perform size estimation
- * or to render the result.
- */
-struct Enc {
- char *(*encode_uint)(char *data, uint64_t num);
- char *(*encode_str)(char *data, const char *str, uint32_t len);
- char *(*encode_bool)(char *data, bool v);
- char *(*encode_array)(char *data, uint32_t len);
- char *(*encode_map)(char *data, uint32_t len);
-};
-
-/* no_encode_XXX functions estimate result size */
-
-static char *no_encode_uint(char *data, uint64_t num)
-{
- /* MsgPack UINT is encoded in 9 bytes or less */
- (void)num; return data + 9;
-}
-
-static char *no_encode_str(char *data, const char *str, uint32_t len)
-{
- /* MsgPack STR header is encoded in 5 bytes or less, followed by
- * the string data. */
- (void)str; return data + 5 + len;
-}
-
-static char *no_encode_bool(char *data, bool v)
-{
- /* MsgPack BOOL is encoded in 1 byte. */
- (void)v; return data + 1;
-}
-
-static char *no_encode_array_or_map(char *data, uint32_t len)
-{
- /* MsgPack ARRAY or MAP header is encoded in 5 bytes or less. */
- (void)len; return data + 5;
-}
-
-/*
- * If buf==NULL, return Enc that will perform size estimation;
- * otherwize, return Enc that renders results in the provided buf.
- */
-static const struct Enc *get_enc(void *buf)
-{
- static const struct Enc mp_enc = {
- mp_encode_uint, mp_encode_str, mp_encode_bool,
- mp_encode_array, mp_encode_map
- }, no_enc = {
- no_encode_uint, no_encode_str, no_encode_bool,
- no_encode_array_or_map, no_encode_array_or_map
- };
- return buf ? &mp_enc : &no_enc;
-}
-
-/*
* Convert SQLite affinity value to the corresponding Tarantool type
* string which is suitable for _index.parts field.
*/
@@ -1321,34 +1299,31 @@ static const char *convertSqliteAffinity(int affinity, bool allow_nulls)
}
}
-/*
- * Render "format" array for _space entry.
- * Returns result size.
- * If buf==NULL estimate result size.
- *
- * Ex: [{"name": "col1", "type": "integer"}, ... ]
- */
-int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
+char *
+sql_encode_table(struct region *region, struct Table *table, uint32_t *size)
{
- const struct Enc *enc = get_enc(buf);
- const struct space_def *def = pTable->def;
- assert(def != NULL);
- struct SqliteIndex *pk_idx = sqlite3PrimaryKeyIndex(pTable);
- int pk_forced_int = -1;
- char *base = buf, *p;
- int i, n = def->field_count;
-
- p = enc->encode_array(base, n);
+ 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);
- /* If table's PK is single column which is INTEGER, then
- * treat it as strict type, not affinity. */
+ const struct space_def *def = table->def;
+ assert(def != NULL);
+ /*
+ * If table's PK is single column which is INTEGER, then
+ * treat it as strict type, not affinity.
+ */
+ struct SqliteIndex *pk_idx = sqlite3PrimaryKeyIndex(table);
+ uint32_t pk_forced_int = UINT32_MAX;
if (pk_idx != NULL && pk_idx->def->key_def->part_count == 1) {
int pk = pk_idx->def->key_def->parts[0].fieldno;
if (def->fields[pk].type == FIELD_TYPE_INTEGER)
pk_forced_int = pk;
}
-
- for (i = 0; i < n; i++) {
+ uint32_t field_count = def->field_count;
+ mpstream_encode_array(&stream, field_count);
+ for (uint32_t i = 0; i < field_count && !is_error; i++) {
const char *t;
uint32_t cid = def->fields[i].coll_id;
struct field_def *field = &def->fields[i];
@@ -1358,10 +1333,10 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
base_len += 1;
if (default_str != NULL)
base_len += 1;
- p = enc->encode_map(p, base_len);
- p = enc->encode_str(p, "name", 4);
- p = enc->encode_str(p, field->name, strlen(field->name));
- p = enc->encode_str(p, "type", 4);
+ mpstream_encode_map(&stream, base_len);
+ mpstream_encode_str(&stream, "name");
+ mpstream_encode_str(&stream, field->name);
+ mpstream_encode_str(&stream, "type");
if (i == pk_forced_int) {
t = "integer";
} else {
@@ -1370,114 +1345,145 @@ int tarantoolSqlite3MakeTableFormat(Table *pTable, void *buf)
convertSqliteAffinity(affinity,
def->fields[i].is_nullable);
}
-
assert(def->fields[i].is_nullable ==
- action_is_nullable(def->fields[i].nullable_action));
- p = enc->encode_str(p, t, strlen(t));
- p = enc->encode_str(p, "affinity", 8);
- p = enc->encode_uint(p, def->fields[i].affinity);
- p = enc->encode_str(p, "is_nullable", 11);
- p = enc->encode_bool(p, def->fields[i].is_nullable);
- p = enc->encode_str(p, "nullable_action", 15);
+ action_is_nullable(def->fields[i].nullable_action));
+ mpstream_encode_str(&stream, t);
+ mpstream_encode_str(&stream, "affinity");
+ mpstream_encode_uint(&stream, def->fields[i].affinity);
+ mpstream_encode_str(&stream, "is_nullable");
+ mpstream_encode_bool(&stream, def->fields[i].is_nullable);
+ mpstream_encode_str(&stream, "nullable_action");
assert(def->fields[i].nullable_action < on_conflict_action_MAX);
const char *action =
on_conflict_action_strs[def->fields[i].nullable_action];
- p = enc->encode_str(p, action, strlen(action));
+ mpstream_encode_str(&stream, action);
if (cid != COLL_NONE) {
- p = enc->encode_str(p, "collation", strlen("collation"));
- p = enc->encode_uint(p, cid);
+ mpstream_encode_str(&stream, "collation");
+ mpstream_encode_uint(&stream, cid);
}
if (default_str != NULL) {
- p = enc->encode_str(p, "default", strlen("default"));
- p = enc->encode_str(p, default_str, strlen(default_str));
+ mpstream_encode_str(&stream, "default");
+ mpstream_encode_str(&stream, default_str);
}
}
- return (int)(p - base);
+ mpstream_flush(&stream);
+ if (is_error) {
+ diag_set(OutOfMemory, stream.pos - stream.buf,
+ "mpstream_flush", "stream");
+ return NULL;
+ }
+ *size = region_used(region) - used;
+ char *raw = region_join(region, *size);
+ if (raw == NULL)
+ diag_set(OutOfMemory, *size, "region_join", "raw");
+ return raw;
}
-/*
- * Format "opts" dictionary for _space entry.
- * Returns result size.
- * If buf==NULL estimate result size.
- *
- * Ex: {"temporary": true, "sql": "CREATE TABLE student (name, grade)"}
- */
-int
-tarantoolSqlite3MakeTableOpts(Table *pTable, const char *zSql, char *buf)
+char *
+sql_encode_table_opts(struct region *region, struct Table *table,
+ const char *sql, uint32_t *size)
{
- const struct Enc *enc = get_enc(buf);
- bool is_view = pTable != NULL && pTable->def->opts.is_view;
- bool has_checks = pTable != NULL && pTable->def->opts.checks != NULL;
- int checks_cnt = has_checks ? pTable->def->opts.checks->nExpr : 0;
- char *p = enc->encode_map(buf, 1 + is_view + (checks_cnt > 0));
-
- p = enc->encode_str(p, "sql", 3);
- p = enc->encode_str(p, zSql, strlen(zSql));
+ assert(sql != NULL);
+ 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);
+ bool is_view = false;
+ int checks_cnt = 0;
+ struct ExprList_item *a;
+ if (table != NULL) {
+ is_view = table->def->opts.is_view;
+ struct ExprList *checks = table->def->opts.checks;
+ if (checks != NULL) {
+ checks_cnt = checks->nExpr;
+ a = checks->a;
+ }
+ }
+ mpstream_encode_map(&stream, 1 + is_view + (checks_cnt > 0));
+
+ mpstream_encode_str(&stream, "sql");
+ mpstream_encode_str(&stream, sql);
if (is_view) {
- p = enc->encode_str(p, "view", 4);
- p = enc->encode_bool(p, true);
+ mpstream_encode_str(&stream, "view");
+ mpstream_encode_bool(&stream, true);
}
- if (checks_cnt == 0)
- return p - buf;
- /* Encode checks. */
- struct ExprList_item *a = pTable->def->opts.checks->a;
- p = enc->encode_str(p, "checks", 6);
- p = enc->encode_array(p, checks_cnt);
- for (int i = 0; i < checks_cnt; ++i) {
- int items = (a[i].pExpr != NULL) + (a[i].zName != NULL);
- p = enc->encode_map(p, items);
- /*
- * a[i].pExpr could be NULL for VIEW column names
- * represented as checks.
- */
- if (a[i].pExpr != NULL) {
- Expr *pExpr = a[i].pExpr;
- assert(pExpr->u.zToken != NULL);
- p = enc->encode_str(p, "expr", 4);
- p = enc->encode_str(p, pExpr->u.zToken,
- strlen(pExpr->u.zToken));
- }
- if (a[i].zName != NULL) {
- p = enc->encode_str(p, "name", 4);
- p = enc->encode_str(p, a[i].zName, strlen(a[i].zName));
+ if (checks_cnt > 0) {
+ mpstream_encode_str(&stream, "checks");
+ mpstream_encode_array(&stream, checks_cnt);
+ }
+ for (int i = 0; i < checks_cnt && !is_error; ++i, ++a) {
+ int items = (a->pExpr != NULL) + (a->zName != NULL);
+ mpstream_encode_map(&stream, items);
+ assert(a->pExpr != NULL);
+ struct Expr *pExpr = a->pExpr;
+ assert(pExpr->u.zToken != NULL);
+ mpstream_encode_str(&stream, "expr");
+ mpstream_encode_str(&stream, pExpr->u.zToken);
+ if (a->zName != NULL) {
+ mpstream_encode_str(&stream, "name");
+ mpstream_encode_str(&stream, a->zName);
}
}
- return p - buf;
+ mpstream_flush(&stream);
+ if (is_error) {
+ diag_set(OutOfMemory, stream.pos - stream.buf,
+ "mpstream_flush", "stream");
+ return NULL;
+ }
+ *size = region_used(region) - used;
+ char *raw = region_join(region, *size);
+ if (raw == NULL)
+ diag_set(OutOfMemory, *size, "region_join", "raw");
+ return raw;
}
-int
-fkey_encode_links(const struct fkey_def *def, int type, char *buf)
+char *
+fkey_encode_links(struct region *region, const struct fkey_def *def, int type,
+ uint32_t *size)
{
- const struct Enc *enc = get_enc(buf);
- char *p = enc->encode_array(buf, def->field_count);
- for (uint32_t i = 0; i < def->field_count; ++i)
- p = enc->encode_uint(p, def->links[i].fields[type]);
- return p - buf;
+ 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);
+ uint32_t field_count = def->field_count;
+ mpstream_encode_array(&stream, field_count);
+ for (uint32_t i = 0; i < field_count && !is_error; ++i)
+ mpstream_encode_uint(&stream, def->links[i].fields[type]);
+ mpstream_flush(&stream);
+ if (is_error) {
+ diag_set(OutOfMemory, stream.pos - stream.buf,
+ "mpstream_flush", "stream");
+ return NULL;
+ }
+ *size = region_used(region) - used;
+ char *raw = region_join(region, *size);
+ if (raw == NULL)
+ diag_set(OutOfMemory, *size, "region_join", "raw");
+ return raw;
}
-/*
- * Format "parts" array for _index entry.
- * Returns result size.
- * If buf==NULL estimate result size.
- *
- * Ex: [[0, "integer"]]
- */
-int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)
+char *
+sql_encode_index_parts(struct region *region, struct SqliteIndex *index,
+ uint32_t *size)
{
- struct field_def *fields = pIndex->pTable->def->fields;
- struct key_def *key_def = pIndex->def->key_def;
- const struct Enc *enc = get_enc(buf);
- char *base = buf;
+ 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);
+ /*
+ * If table's PK is single column which is INTEGER, then
+ * treat it as strict type, not affinity.
+ */
uint32_t pk_forced_int = UINT32_MAX;
- struct SqliteIndex *primary_index =
- sqlite3PrimaryKeyIndex(pIndex->pTable);
-
- /* If table's PK is single column which is INTEGER, then
- * treat it as strict type, not affinity. */
- if (primary_index->def->key_def->part_count == 1) {
- int pk = primary_index->def->key_def->parts[0].fieldno;
- if (fields[pk].type == FIELD_TYPE_INTEGER)
- pk_forced_int = pk;
+ struct SqliteIndex *pk = sqlite3PrimaryKeyIndex(index->pTable);
+ struct field_def *fields = index->pTable->def->fields;
+ if (pk->def->key_def->part_count == 1) {
+ int fieldno = pk->def->key_def->parts[0].fieldno;
+ if (fields[fieldno].type == FIELD_TYPE_INTEGER)
+ pk_forced_int = fieldno;
}
/* gh-2187
@@ -1486,8 +1492,9 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)
* primary key columns. Query planner depends on this particular
* data layout.
*/
+ struct key_def *key_def = index->def->key_def;
struct key_part *part = key_def->parts;
- char *p = enc->encode_array(base, key_def->part_count);
+ mpstream_encode_array(&stream, key_def->part_count);
for (uint32_t i = 0; i < key_def->part_count; ++i, ++part) {
uint32_t col = part->fieldno;
assert(fields[col].is_nullable ==
@@ -1499,54 +1506,64 @@ int tarantoolSqlite3MakeIdxParts(SqliteIndex *pIndex, void *buf)
t = convertSqliteAffinity(fields[col].affinity,
fields[col].is_nullable);
}
- /* do not decode default collation */
+ /* Do not decode default collation. */
uint32_t cid = part->coll_id;
- p = enc->encode_map(p, cid == COLL_NONE ? 5 : 6);
- p = enc->encode_str(p, "type", sizeof("type")-1);
- p = enc->encode_str(p, t, strlen(t));
- p = enc->encode_str(p, "field", sizeof("field")-1);
- p = enc->encode_uint(p, col);
+ mpstream_encode_map(&stream, 5 + (cid != COLL_NONE));
+ mpstream_encode_str(&stream, "type");
+ mpstream_encode_str(&stream, t);
+ mpstream_encode_str(&stream, "field");
+ mpstream_encode_uint(&stream, col);
if (cid != COLL_NONE) {
- p = enc->encode_str(p, "collation",
- sizeof("collation") - 1);
- p = enc->encode_uint(p, cid);
+ mpstream_encode_str(&stream, "collation");
+ mpstream_encode_uint(&stream, cid);
}
- p = enc->encode_str(p, "is_nullable", 11);
- p = enc->encode_bool(p, fields[col].is_nullable);
- p = enc->encode_str(p, "nullable_action", 15);
+ mpstream_encode_str(&stream, "is_nullable");
+ mpstream_encode_bool(&stream, fields[col].is_nullable);
+ mpstream_encode_str(&stream, "nullable_action");
const char *action_str =
on_conflict_action_strs[fields[col].nullable_action];
- p = enc->encode_str(p, action_str, strlen(action_str));
+ mpstream_encode_str(&stream, action_str);
- p = enc->encode_str(p, "sort_order", 10);
+ mpstream_encode_str(&stream, "sort_order");
enum sort_order sort_order = part->sort_order;
assert(sort_order < sort_order_MAX);
const char *sort_order_str = sort_order_strs[sort_order];
- p = enc->encode_str(p, sort_order_str, strlen(sort_order_str));
+ mpstream_encode_str(&stream, sort_order_str);
}
- return p - base;
+ mpstream_flush(&stream);
+ if (is_error) {
+ diag_set(OutOfMemory, stream.pos - stream.buf,
+ "mpstream_flush", "stream");
+ return NULL;
+ }
+ *size = region_used(region) - used;
+ char *raw = region_join(region, *size);
+ if (raw == NULL)
+ diag_set(OutOfMemory, *size, "region_join", "raw");
+ return raw;
}
-int
-sql_encode_index_opts(struct index_opts *opts, void *buf)
+char *
+sql_encode_index_opts(struct region *region, struct index_opts *opts,
+ uint32_t *size)
{
- const struct Enc *enc = get_enc(buf);
- char *base = buf, *p;
-
- p = enc->encode_map(base, 2);
- /* Mark as unique pk and unique indexes */
- p = enc->encode_str(p, "unique", 6);
- /* If user didn't defined ON CONFLICT OPTIONS, all uniqueness checks
- * will be made by Tarantool. However, Tarantool doesn't have ON
- * CONFLIT option, so in that case (except ON CONFLICT ABORT, which is
- * default behavior) uniqueness will be checked by SQL.
- * INSERT OR REPLACE/IGNORE uniqueness checks will be also done by
- * Tarantool.
- */
- p = enc->encode_bool(p, opts->is_unique);
- p = enc->encode_str(p, "sql", 3);
- p = enc->encode_str(p, opts->sql, opts->sql ? strlen(opts->sql) : 0);
- return (int)(p - base);
+ 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);
+ mpstream_encode_index_opts(&stream, opts);
+ mpstream_flush(&stream);
+ if (is_error) {
+ diag_set(OutOfMemory, stream.pos - stream.buf, "mpstream_flush",
+ "stream");
+ return NULL;
+ }
+ *size = region_used(region) - used;
+ char *raw = region_join(region, *size);
+ if (raw == NULL)
+ diag_set(OutOfMemory, *size, "region_join", "raw");
+ return raw;
}
void
diff --git a/src/box/sql/build.c b/src/box/sql/build.c
index da7668b..c422a66 100644
--- a/src/box/sql/build.c
+++ b/src/box/sql/build.c
@@ -1241,26 +1241,29 @@ createIndex(Parse * pParse, Index * pIndex, int iSpaceId, int iIndexId,
Vdbe *v = sqlite3GetVdbe(pParse);
int iFirstCol = ++pParse->nMem;
int iRecord = (pParse->nMem += 6); /* 6 total columns */
- char *zOpts, *zParts;
- int zOptsSz, zPartsSz;
-
- /* Format "opts" and "parts" for _index entry. */
struct index_opts opts = pIndex->def->opts;
opts.sql = (char *)zSql;
- zOpts = sqlite3DbMallocRaw(pParse->db,
- sql_encode_index_opts(&opts, NULL) +
- tarantoolSqlite3MakeIdxParts(pIndex,
- NULL) + 2);
- if (!zOpts)
+ struct region *region = &pParse->region;
+ uint32_t index_opts_sz = 0;
+ char *index_opts =
+ sql_encode_index_opts(region, &opts, &index_opts_sz);
+ if (index_opts == NULL)
+ goto error;
+ uint32_t index_parts_sz = 0;
+ char *index_parts =
+ sql_encode_index_parts(region, pIndex, &index_parts_sz);
+ if (index_parts == NULL)
+ goto error;
+ char *raw = sqlite3DbMallocRaw(pParse->db,
+ index_opts_sz + index_parts_sz);
+ if (raw == NULL)
return;
- zOptsSz = sql_encode_index_opts(&opts, zOpts);
- zParts = zOpts + zOptsSz + 1;
- zPartsSz = tarantoolSqlite3MakeIdxParts(pIndex, zParts);
-#if SQLITE_DEBUG
- /* NUL-termination is necessary for VDBE trace facility only */
- zOpts[zOptsSz] = 0;
- zParts[zPartsSz] = 0;
-#endif
+
+ memcpy(raw, index_opts, index_opts_sz);
+ index_opts = raw;
+ raw += index_opts_sz;
+ memcpy(raw, index_parts, index_parts_sz);
+ index_parts = raw;
if (pParse->pNewTable) {
int reg;
@@ -1296,16 +1299,20 @@ createIndex(Parse * pParse, Index * pIndex, int iSpaceId, int iIndexId,
P4_DYNAMIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 3, 0, "tree",
P4_STATIC);
- sqlite3VdbeAddOp4(v, OP_Blob, zOptsSz, iFirstCol + 4,
- SQL_SUBTYPE_MSGPACK, zOpts, P4_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_Blob, index_opts_sz, iFirstCol + 4,
+ SQL_SUBTYPE_MSGPACK, index_opts, P4_DYNAMIC);
/* zOpts and zParts are co-located, hence STATIC */
- sqlite3VdbeAddOp4(v, OP_Blob, zPartsSz, iFirstCol + 5,
- SQL_SUBTYPE_MSGPACK,zParts, P4_STATIC);
+ sqlite3VdbeAddOp4(v, OP_Blob, index_parts_sz, iFirstCol + 5,
+ SQL_SUBTYPE_MSGPACK, index_parts, P4_STATIC);
sqlite3VdbeAddOp3(v, OP_MakeRecord, iFirstCol, 6, iRecord);
sqlite3VdbeAddOp2(v, OP_SInsert, BOX_INDEX_ID, iRecord);
if (pIndex->index_type == SQL_INDEX_TYPE_NON_UNIQUE ||
pIndex->index_type == SQL_INDEX_TYPE_UNIQUE)
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
+ return;
+error:
+ pParse->rc = SQL_TARANTOOL_ERROR;
+ pParse->nErr++;
}
/*
@@ -1360,50 +1367,54 @@ makeIndexSchemaRecord(Parse * pParse,
static void
createSpace(Parse * pParse, int iSpaceId, char *zStmt)
{
- Table *p = pParse->pNewTable;
+ struct Table *table = pParse->pNewTable;
Vdbe *v = sqlite3GetVdbe(pParse);
int iFirstCol = ++pParse->nMem;
int iRecord = (pParse->nMem += 7);
- char *zOpts, *zFormat;
- int zOptsSz, zFormatSz;
-
- zOpts = sqlite3DbMallocRaw(pParse->db,
- tarantoolSqlite3MakeTableFormat(p, NULL) +
- tarantoolSqlite3MakeTableOpts(p, zStmt,
- NULL) + 2);
- if (!zOpts) {
- zOptsSz = 0;
- zFormat = NULL;
- zFormatSz = 0;
- } else {
- zOptsSz = tarantoolSqlite3MakeTableOpts(p, zStmt, zOpts);
- zFormat = zOpts + zOptsSz + 1;
- zFormatSz = tarantoolSqlite3MakeTableFormat(p, zFormat);
-#if SQLITE_DEBUG
- /* NUL-termination is necessary for VDBE-tracing facility only */
- zOpts[zOptsSz] = 0;
- zFormat[zFormatSz] = 0;
-#endif
- }
+ struct region *region = &pParse->region;
+ uint32_t table_opts_stmt_sz = 0;
+ char *table_opts_stmt = sql_encode_table_opts(region, table, zStmt,
+ &table_opts_stmt_sz);
+ if (table_opts_stmt == NULL)
+ goto error;
+ uint32_t table_stmt_sz = 0;
+ char *table_stmt = sql_encode_table(region, table, &table_stmt_sz);
+ if (table_stmt == NULL)
+ goto error;
+ char *raw = sqlite3DbMallocRaw(pParse->db,
+ table_stmt_sz + table_opts_stmt_sz);
+ if (raw == NULL)
+ return;
+
+ memcpy(raw, table_opts_stmt, table_opts_stmt_sz);
+ table_opts_stmt = raw;
+ raw += table_opts_stmt_sz;
+ memcpy(raw, table_stmt, table_stmt_sz);
+ table_stmt = raw;
sqlite3VdbeAddOp2(v, OP_SCopy, iSpaceId, iFirstCol /* spaceId */ );
sqlite3VdbeAddOp2(v, OP_Integer, effective_user()->uid,
iFirstCol + 1 /* owner */ );
sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 2 /* name */ , 0,
- sqlite3DbStrDup(pParse->db, p->def->name), P4_DYNAMIC);
+ sqlite3DbStrDup(pParse->db, table->def->name),
+ P4_DYNAMIC);
sqlite3VdbeAddOp4(v, OP_String8, 0, iFirstCol + 3 /* engine */ , 0,
- sqlite3DbStrDup(pParse->db, p->def->engine_name),
+ sqlite3DbStrDup(pParse->db, table->def->engine_name),
P4_DYNAMIC);
- sqlite3VdbeAddOp2(v, OP_Integer, p->def->field_count,
+ sqlite3VdbeAddOp2(v, OP_Integer, table->def->field_count,
iFirstCol + 4 /* field_count */ );
- sqlite3VdbeAddOp4(v, OP_Blob, zOptsSz, iFirstCol + 5,
- SQL_SUBTYPE_MSGPACK, zOpts, P4_DYNAMIC);
+ sqlite3VdbeAddOp4(v, OP_Blob, table_opts_stmt_sz, iFirstCol + 5,
+ SQL_SUBTYPE_MSGPACK, table_opts_stmt, P4_DYNAMIC);
/* zOpts and zFormat are co-located, hence STATIC */
- sqlite3VdbeAddOp4(v, OP_Blob, zFormatSz, iFirstCol + 6,
- SQL_SUBTYPE_MSGPACK, zFormat, P4_STATIC);
+ sqlite3VdbeAddOp4(v, OP_Blob, table_stmt_sz, iFirstCol + 6,
+ SQL_SUBTYPE_MSGPACK, table_stmt, P4_STATIC);
sqlite3VdbeAddOp3(v, OP_MakeRecord, iFirstCol, 7, iRecord);
sqlite3VdbeAddOp2(v, OP_SInsert, BOX_SPACE_ID, iRecord);
sqlite3VdbeChangeP5(v, OPFLAG_NCHANGE);
+ return;
+error:
+ pParse->nErr++;
+ pParse->rc = SQL_TARANTOOL_ERROR;
}
/*
@@ -1592,10 +1603,8 @@ vdbe_emit_fkey_create(struct Parse *parse_context, const struct fkey_def *fk)
BOX_FK_CONSTRAINT_ID, 0,
constr_tuple_reg, 2,
ER_CONSTRAINT_EXISTS, error_msg,
- false, OP_NoConflict) != 0) {
- sqlite3DbFree(parse_context->db, name_copy);
+ false, OP_NoConflict) != 0)
return;
- }
sqlite3VdbeAddOp2(vdbe, OP_Bool, 0, constr_tuple_reg + 3);
sqlite3VdbeChangeP4(vdbe, -1, (char*)&fk->is_deferred, P4_BOOL);
sqlite3VdbeAddOp4(vdbe, OP_String8, 0, constr_tuple_reg + 4, 0,
@@ -1604,33 +1613,48 @@ vdbe_emit_fkey_create(struct Parse *parse_context, const struct fkey_def *fk)
fkey_action_strs[fk->on_delete], P4_STATIC);
sqlite3VdbeAddOp4(vdbe, OP_String8, 0, constr_tuple_reg + 6, 0,
fkey_action_strs[fk->on_update], P4_STATIC);
- size_t parent_size = fkey_encode_links(fk, FIELD_LINK_PARENT, NULL);
- size_t child_size = fkey_encode_links(fk, FIELD_LINK_CHILD, NULL);
+ struct region *region = &parse_context->region;
+ uint32_t parent_links_size = 0;
+ char *parent_links = fkey_encode_links(region, fk, FIELD_LINK_PARENT,
+ &parent_links_size);
+ if (parent_links == NULL)
+ goto error;
+ uint32_t child_links_size = 0;
+ char *child_links = fkey_encode_links(region, fk, FIELD_LINK_CHILD,
+ &child_links_size);
+ if (child_links == NULL)
+ goto error;
/*
* We are allocating memory for both parent and child
* arrays in the same chunk. Thus, first OP_Blob opcode
* interprets it as static memory, and the second one -
* as dynamic and releases memory.
*/
- char *parent_links = sqlite3DbMallocRaw(parse_context->db,
- parent_size + child_size);
- if (parent_links == NULL) {
- sqlite3DbFree(parse_context->db, (void *) name_copy);
+ char *raw = sqlite3DbMallocRaw(parse_context->db,
+ parent_links_size + child_links_size);
+ if (raw == NULL)
return;
- }
- parent_size = fkey_encode_links(fk, FIELD_LINK_PARENT, parent_links);
- char *child_links = parent_links + parent_size;
- child_size = fkey_encode_links(fk, FIELD_LINK_CHILD, child_links);
- sqlite3VdbeAddOp4(vdbe, OP_Blob, child_size, constr_tuple_reg + 7,
+ memcpy(raw, parent_links, parent_links_size);
+ parent_links = raw;
+ raw += parent_links_size;
+ memcpy(raw, child_links, child_links_size);
+ child_links = raw;
+
+ sqlite3VdbeAddOp4(vdbe, OP_Blob, child_links_size, constr_tuple_reg + 7,
SQL_SUBTYPE_MSGPACK, child_links, P4_STATIC);
- sqlite3VdbeAddOp4(vdbe, OP_Blob, parent_size, constr_tuple_reg + 8,
- SQL_SUBTYPE_MSGPACK, parent_links, P4_DYNAMIC);
+ sqlite3VdbeAddOp4(vdbe, OP_Blob, parent_links_size,
+ constr_tuple_reg + 8, SQL_SUBTYPE_MSGPACK,
+ parent_links, P4_DYNAMIC);
sqlite3VdbeAddOp3(vdbe, OP_MakeRecord, constr_tuple_reg, 9,
constr_tuple_reg + 9);
sqlite3VdbeAddOp2(vdbe, OP_SInsert, BOX_FK_CONSTRAINT_ID,
constr_tuple_reg + 9);
sqlite3VdbeChangeP5(vdbe, OPFLAG_NCHANGE);
sqlite3ReleaseTempRange(parse_context, constr_tuple_reg, 10);
+ return;
+error:
+ parse_context->nErr++;
+ parse_context->rc = SQL_TARANTOOL_ERROR;
}
/**
diff --git a/src/box/sql/tarantoolInt.h b/src/box/sql/tarantoolInt.h
index a3ad52a..07372c1 100644
--- a/src/box/sql/tarantoolInt.h
+++ b/src/box/sql/tarantoolInt.h
@@ -151,49 +151,73 @@ tarantoolSqlite3IdxKeyCompare(struct BtCursor *cursor,
int
tarantoolSqlite3IncrementMaxid(uint64_t *space_max_id);
-/*
- * Render "format" array for _space entry.
- * Returns result size.
- * If buf==NULL estimate result size.
+/**
+ * Encode format as entry to be inserted to _space on @region.
+ * @param region Region to use.
+ * @param table Table to encode.
+ * @param[out] size Size of result allocation.
+ *
+ * @retval NULL Error.
+ * @retval not NULL Pointer to msgpack on success.
*/
-int tarantoolSqlite3MakeTableFormat(Table * pTable, void *buf);
+char *
+sql_encode_table(struct region *region, struct Table *table, uint32_t *size);
-/*
- * Format "opts" dictionary for _space entry.
- * Returns result size.
- * If buf==NULL estimate result size.
+/**
+ * Encode "opts" dictionary for _space entry on @region.
+ * @param region Region to use.
+ * @param table Table containing opts to encode.
+ * @param sql Source request to encode.
+ * @param[out] size Size of result allocation.
+ *
+ * @retval NULL Error.
+ * @retval not NULL Pointer to msgpack on success.
*/
-int tarantoolSqlite3MakeTableOpts(Table * pTable, const char *zSql, char *buf);
+char *
+sql_encode_table_opts(struct region *region, struct Table *table,
+ const char *sql, uint32_t *size);
/**
- * Encode links of given foreign key constraint into MsgPack.
- *
+ * Encode links of given foreign key constraint into MsgPack on
+ * @region.
+ * @param region Wegion to use.
* @param def FK def to encode links of.
* @param type Links type to encode.
- * @param buf Buffer to hold encoded links. Can be NULL. In this
- * case function would simply calculate memory required
- * for such buffer.
- * @retval Length of encoded array.
+ * @param[out] Size size of result allocation.
+ *
+ * @retval NULL Error.
+ * @retval not NULL Pointer to msgpack on success.
*/
-int
-fkey_encode_links(const struct fkey_def *def, int type, char *buf);
+char *
+fkey_encode_links(struct region *region, const struct fkey_def *def, int type,
+ uint32_t *size);
-/*
- * Format "parts" array for _index entry.
- * Returns result size.
- * If buf==NULL estimate result size.
+/**
+ * Encode index parts of given foreign key constraint into
+ * MsgPack on @region.
+ * @param region Region to use.
+ * @param index Index to encode.
+ * @param[out] size Size of result allocation.
+ *
+ * @retval NULL Error.
+ * @retval not NULL Pointer to msgpack on success
*/
-int tarantoolSqlite3MakeIdxParts(Index * index, void *buf);
+char *
+sql_encode_index_parts(struct region *region, struct Index *index,
+ uint32_t *size);
/**
- * Format "opts" dictionary for _index entry.
+ * Encode "opts" dictionary for _index entry on @region.
*
+ * @param region region to use.
* @param opts Options to encode.
- * @param[out] buf destination buffer.
- * @retval Result size or size estimation if buf == NULL.
+ * @param[out] size size of result allocation.
+ * @retval NULL on error.
+ * @retval not NULL pointer to msgpack on success
*/
-int
-sql_encode_index_opts(struct index_opts *opts, void *buf);
+char *
+sql_encode_index_opts(struct region *region, struct index_opts *opts,
+ uint32_t *size);
/**
* Extract next id from _sequence space.
diff --git a/src/box/sql/trigger.c b/src/box/sql/trigger.c
index bd730c4..f400c25 100644
--- a/src/box/sql/trigger.c
+++ b/src/box/sql/trigger.c
@@ -173,16 +173,12 @@ sql_trigger_finish(struct Parse *parse, struct TriggerStep *step_list,
{
/* Trigger being finished. */
struct sql_trigger *trigger = parse->parsed_ast.trigger;
- /* SQL text. */
- char *sql_str = NULL;
- /* MsgPack containing SQL options. */
- char *opts_buff = NULL;
/* The database. */
struct sqlite3 *db = parse->db;
parse->parsed_ast.trigger = NULL;
if (NEVER(parse->nErr) || trigger == NULL)
- goto triggerfinish_cleanup;
+ goto cleanup;
char *trigger_name = trigger->zName;
trigger->step_list = step_list;
while (step_list != NULL) {
@@ -202,17 +198,18 @@ sql_trigger_finish(struct Parse *parse, struct TriggerStep *step_list,
/* Make an entry in the _trigger space. */
struct Vdbe *v = sqlite3GetVdbe(parse);
if (v == 0)
- goto triggerfinish_cleanup;
+ goto cleanup;
struct Table *sys_trigger =
- sqlite3HashFind(&parse->db->pSchema->tblHash,
+ sqlite3HashFind(&db->pSchema->tblHash,
TARANTOOL_SYS_TRIGGER_NAME);
if (NEVER(sys_trigger == NULL))
- goto triggerfinish_cleanup;
+ goto cleanup;
- sql_str = sqlite3MPrintf(db, "CREATE TRIGGER %s", token->z);
- if (db->mallocFailed)
- goto triggerfinish_cleanup;
+ char *sql_str =
+ sqlite3MPrintf(db, "CREATE TRIGGER %s", token->z);
+ if (sql_str == NULL)
+ goto cleanup;
int cursor = parse->nTab++;
sqlite3OpenTable(parse, cursor, sys_trigger, OP_OpenWrite);
@@ -225,24 +222,27 @@ sql_trigger_finish(struct Parse *parse, struct TriggerStep *step_list,
parse->nMem += 3;
int record = ++parse->nMem;
- opts_buff =
- sqlite3DbMallocRaw(parse->db,
- tarantoolSqlite3MakeTableOpts(0,
- sql_str,
- NULL) +
- 1);
- if (db->mallocFailed)
- goto triggerfinish_cleanup;
-
- int opts_buff_sz =
- tarantoolSqlite3MakeTableOpts(0, sql_str, opts_buff);
-
- trigger_name = sqlite3DbStrDup(parse->db, trigger_name);
- if (db->mallocFailed)
- goto triggerfinish_cleanup;
+ uint32_t opts_buff_sz = 0;
+ char *data = sql_encode_table_opts(&fiber()->gc, NULL, sql_str,
+ &opts_buff_sz);
+ sqlite3DbFree(db, sql_str);
+ if (data == NULL) {
+ parse->nErr++;
+ parse->rc = SQL_TARANTOOL_ERROR;
+ goto cleanup;
+ }
+ char *opts_buff = sqlite3DbMallocRaw(db, opts_buff_sz);
+ if (opts_buff == NULL)
+ goto cleanup;
+ memcpy(opts_buff, data, opts_buff_sz);
+
+ trigger_name = sqlite3DbStrDup(db, trigger_name);
+ if (trigger_name == NULL) {
+ sqlite3DbFree(db, opts_buff);
+ goto cleanup;
+ }
- sqlite3VdbeAddOp4(v,
- OP_String8, 0, first_col, 0,
+ sqlite3VdbeAddOp4(v, OP_String8, 0, first_col, 0,
trigger_name, P4_DYNAMIC);
sqlite3VdbeAddOp2(v, OP_Integer, trigger->space_id,
first_col + 1);
@@ -261,11 +261,7 @@ sql_trigger_finish(struct Parse *parse, struct TriggerStep *step_list,
trigger = NULL;
}
- triggerfinish_cleanup:
- if (db->mallocFailed) {
- sqlite3DbFree(db, sql_str);
- sqlite3DbFree(db, opts_buff);
- }
+cleanup:
sql_trigger_delete(db, trigger);
assert(parse->parsed_ast.trigger == NULL || parse->parse_only);
sqlite3DeleteTriggerStep(db, step_list);
--
2.7.4
^ permalink raw reply [flat|nested] 10+ messages in thread