<html>
<head>
<meta http-equiv="Content-Type" content="text/html; charset=UTF-8">
</head>
<body text="#000000" bgcolor="#FFFFFF">
<p>Hi! Thank you for review and fixes! I squashed you fixes and done<br>
some changes:<br>
- vstream_encode_port() now uses port_dump_msgpack() instead of<br>
port_dump_msgpack_16()<br>
- vstream now contains only inheritance_padding and vtab.<br>
<br>
New patch and some answers below.<br>
<br>
</p>
<div class="moz-cite-prefix">On 11/23/18 12:49 AM, Vladislav
Shpilevoy wrote:<br>
</div>
<blockquote type="cite"
cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org">Thanks
for the fixes! See my 4 comments below, fix <br>
at the end of the email and on the branch. <br>
<br>
On 22/11/2018 22:11, <a class="moz-txt-link-abbreviated"
href="mailto:imeevma@tarantool.org">imeevma@tarantool.org</a>
wrote: <br>
<blockquote type="cite">If we want to use functions from execute.h
not only in IPROTO we <br>
should create special interface. This interface will allow us to
<br>
create different implementations for mpstream and lua_State and
<br>
use functions from execute.c without changing them. This patch <br>
creates such interface and its implementation for mpstream and <br>
replaces mpstream functions in execute.c by methods of this <br>
interface. <br>
<br>
Needed for #3505 <br>
--- <br>
src/box/execute.c | 69 ++++++++++++----------- <br>
src/box/execute.h | 6 +- <br>
src/box/iproto.cc | 11 ++-- <br>
src/box/vstream.h | 164
++++++++++++++++++++++++++++++++++++++++++++++++++++++ <br>
src/mpstream.c | 78 ++++++++++++++++++++++++++ <br>
5 files changed, 291 insertions(+), 37 deletions(-) <br>
create mode 100644 src/box/vstream.h <br>
<br>
diff --git a/src/box/execute.h b/src/box/execute.h <br>
index 940f3a3..5a11a8a 100644 <br>
--- a/src/box/execute.h <br>
+++ b/src/box/execute.h <br>
@@ -75,6 +75,8 @@ struct sql_response { <br>
struct port port; <br>
/** Prepared SQL statement with metadata. */ <br>
void *prep_stmt; <br>
+ /** Result should be flatten if true. */ <br>
+ bool is_flatten; <br>
</blockquote>
<br>
1. What does it mean 'result should be flatten'? Are all <br>
tuples merged into a single flattened one? Or are all metafields <br>
merged into a single array? Please, be more specific. It is far <br>
from obvious now what is it 'flattened result'. <br>
<br>
Also, I guess, 'flatten' is a verb, so you can not say 'is
flatten'. <br>
Only 'is flattened'. <br>
</blockquote>
Squashed.<br>
<blockquote type="cite"
cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org"> <br>
2. I do not see where do you initialize this field for <br>
iproto. So it is now initialized with stack garbage. <br>
<br>
(I've fixed all these things since we hurry.) <br>
</blockquote>
Squashed.
<blockquote type="cite"
cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org"> <br>
<blockquote type="cite"> }; <br>
/** <br>
diff --git a/src/box/vstream.h b/src/box/vstream.h <br>
new file mode 100644 <br>
index 0000000..a8dcfc2 <br>
--- /dev/null <br>
+++ b/src/box/vstream.h <br>
@@ -0,0 +1,164 @@ <br>
+#ifndef TARANTOOL_VSTREAM_H_INCLUDED <br>
+#define TARANTOOL_VSTREAM_H_INCLUDED <br>
+/* <br>
+ * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS
file. <br>
+ * <br>
+ * Redistribution and use in source and binary forms, with or <br>
+ * without modification, are permitted provided that the
following <br>
+ * conditions are met: <br>
+ * <br>
+ * 1. Redistributions of source code must retain the above <br>
+ * copyright notice, this list of conditions and the <br>
+ * following disclaimer. <br>
+ * <br>
+ * 2. Redistributions in binary form must reproduce the above <br>
+ * copyright notice, this list of conditions and the
following <br>
+ * disclaimer in the documentation and/or other materials <br>
+ * provided with the distribution. <br>
+ * <br>
+ * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND <br>
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT
LIMITED <br>
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS
FOR <br>
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL <br>
+ * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT, <br>
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL <br>
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF <br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR <br>
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF <br>
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT <br>
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT
OF <br>
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF <br>
+ * SUCH DAMAGE. <br>
+ */ <br>
+ <br>
+#include "diag.h" <br>
+#include "mpstream.h" <br>
</blockquote>
<br>
3. vstream should not depend on mpstream, but vice versa. <br>
Please, look at how struct port is done. It uses padding <br>
into which its descendants can lay anything. <br>
</blockquote>
Squashed. Also removed "struct lua_State *" from vstream.<br>
<blockquote type="cite"
cite="mid:bca652ee-8489-f444-7a25-ccdb240c0afd@tarantool.org"> <br>
<blockquote type="cite">+ <br>
+#if defined(__cplusplus) <br>
+extern "C" { <br>
+#endif /* defined(__cplusplus) */ <br>
+ <br>
+struct vstream; <br>
+struct lua_State; <br>
+struct port; <br>
+ <br>
diff --git a/src/mpstream.c b/src/mpstream.c <br>
index e4f7950..f9943e4 100644 <br>
--- a/src/mpstream.c <br>
+++ b/src/mpstream.c <br>
@@ -175,3 +180,76 @@ mpstream_encode_bool(struct mpstream
*stream, bool val) <br>
char *pos = mp_encode_bool(data, val); <br>
mpstream_advance(stream, pos - data); <br>
} <br>
+ <br>
+typedef void (*encode_array_f)(struct vstream *stream, uint32_t
size); <br>
+typedef void (*encode_map_f)(struct vstream *stream, uint32_t
size); <br>
+typedef void (*encode_uint_f)(struct vstream *stream, uint64_t
num); <br>
+typedef void (*encode_int_f)(struct vstream *stream, int64_t
num); <br>
+typedef void (*encode_float_f)(struct vstream *stream, float
num); <br>
+typedef void (*encode_double_f)(struct vstream *stream, double
num); <br>
+typedef void (*encode_strn_f)(struct vstream *stream, const
char *str, <br>
+ uint32_t len); <br>
+typedef void (*encode_nil_f)(struct vstream *stream); <br>
+typedef void (*encode_bool_f)(struct vstream *stream, bool
val); <br>
+ <br>
</blockquote>
<br>
4. I think, it should be part of vstream.h. And struct vstream
members should be <br>
defined with these types. <br>
</blockquote>
Squashed.
<p><br>
</p>
<p><b>New version:</b></p>
<p>commit 795ccb629260269c8ffffb52d5e426e35ed0a088<br>
Author: Mergen Imeev <a class="moz-txt-link-rfc2396E"
href="mailto:imeevma@gmail.com"><imeevma@gmail.com></a><br>
Date: Sat Nov 10 11:18:32 2018 +0300<br>
<br>
sql: create interface vstream<br>
<br>
If we want to use functions from execute.h not only in IPROTO
we<br>
should create special interface. This interface will allow us
to<br>
create different implementations for mpstream and lua_State
and<br>
use functions from execute.c without changing them. This patch<br>
creates such interface and its implementation for mpstream and<br>
replaces mpstream functions in execute.c by methods of this<br>
interface.<br>
<br>
Needed for #3505<br>
<br>
diff --git a/src/box/execute.c b/src/box/execute.c<br>
index 9ba9e66..0fee5c1 100644<br>
--- a/src/box/execute.c<br>
+++ b/src/box/execute.c<br>
@@ -42,7 +42,7 @@<br>
#include "port.h"<br>
#include "tuple.h"<br>
#include "sql/vdbe.h"<br>
-#include "mpstream.h"<br>
+#include "vstream.h"<br>
<br>
const char *sql_type_strs[] = {<br>
NULL,<br>
@@ -530,12 +530,12 @@ sql_bind(const struct sql_request *request,
struct sqlite3_stmt *stmt)<br>
* @retval -1 Client or memory error.<br>
*/<br>
static inline int<br>
-sql_get_description(struct sqlite3_stmt *stmt, struct mpstream
*stream,<br>
+sql_get_description(struct sqlite3_stmt *stmt, struct vstream
*stream,<br>
int column_count)<br>
{<br>
assert(column_count > 0);<br>
- mpstream_encode_uint(stream, IPROTO_METADATA);<br>
- mpstream_encode_array(stream, column_count);<br>
+ vstream_encode_enum(stream, IPROTO_METADATA, "metadata");<br>
+ vstream_encode_array(stream, column_count);<br>
for (int i = 0; i < column_count; ++i) {<br>
const char *name = sqlite3_column_name(stmt, i);<br>
const char *type = sqlite3_column_datatype(stmt, i);<br>
@@ -547,12 +547,19 @@ sql_get_description(struct sqlite3_stmt
*stmt, struct mpstream *stream,<br>
assert(name != NULL);<br>
if (type == NULL)<br>
type = "UNKNOWN";<br>
- mpstream_encode_map(stream, 2);<br>
- mpstream_encode_uint(stream, IPROTO_FIELD_NAME);<br>
- mpstream_encode_str(stream, name);<br>
- mpstream_encode_uint(stream, IPROTO_FIELD_TYPE);<br>
- mpstream_encode_str(stream, type);<br>
+ vstream_encode_map(stream, 2);<br>
+<br>
+ vstream_encode_enum(stream, IPROTO_FIELD_NAME, "name");<br>
+ vstream_encode_str(stream, name);<br>
+ vstream_encode_map_commit(stream);<br>
+<br>
+ vstream_encode_enum(stream, IPROTO_FIELD_TYPE, "type");<br>
+ vstream_encode_str(stream, type);<br>
+ vstream_encode_map_commit(stream);<br>
+<br>
+ vstream_encode_array_commit(stream, i);<br>
}<br>
+ vstream_encode_map_commit(stream);<br>
return 0;<br>
}<br>
<br>
@@ -611,7 +618,7 @@ sql_prepare_and_execute(const struct
sql_request *request,<br>
<br>
int<br>
sql_response_dump(struct sql_response *response, int *keys,<br>
- struct mpstream *stream)<br>
+ struct vstream *stream)<br>
{<br>
sqlite3 *db = sql_get();<br>
struct sqlite3_stmt *stmt = (struct sqlite3_stmt *)
response->prep_stmt;<br>
@@ -623,42 +630,48 @@ err:<br>
goto finish;<br>
}<br>
*keys = 2;<br>
- mpstream_encode_uint(stream, IPROTO_DATA);<br>
- mpstream_flush(stream);<br>
- if (port_dump_msgpack(&response->port,
stream->ctx) < 0) {<br>
+ vstream_encode_enum(stream, IPROTO_DATA, "rows");<br>
+ if (vstream_encode_port(stream, &response->port)
< 0) {<br>
/* Failed port dump destroyes the port. */<br>
goto err;<br>
}<br>
- mpstream_reset(stream);<br>
+ vstream_encode_map_commit(stream);<br>
} else {<br>
*keys = 1;<br>
struct stailq *autoinc_id_list =<br>
vdbe_autoinc_id_list((struct Vdbe *)stmt);<br>
uint32_t map_size = stailq_empty(autoinc_id_list) ? 1 :
2;<br>
- mpstream_encode_uint(stream, IPROTO_SQL_INFO);<br>
- mpstream_encode_map(stream, map_size);<br>
uint64_t id_count = 0;<br>
if (!stailq_empty(autoinc_id_list)) {<br>
struct autoinc_id_entry *id_entry;<br>
stailq_foreach_entry(id_entry, autoinc_id_list, link)<br>
id_count++;<br>
}<br>
-<br>
- mpstream_encode_uint(stream, SQL_INFO_ROW_COUNT);<br>
- mpstream_encode_uint(stream, db->nChange);<br>
+ if (!response->is_info_flattened) {<br>
+ vstream_encode_enum(stream, IPROTO_SQL_INFO, "info");<br>
+ vstream_encode_map(stream, map_size);<br>
+ }<br>
+ vstream_encode_enum(stream, SQL_INFO_ROW_COUNT,
"rowcount");<br>
+ vstream_encode_uint(stream, db->nChange);<br>
+ vstream_encode_map_commit(stream);<br>
if (!stailq_empty(autoinc_id_list)) {<br>
- mpstream_encode_uint(stream,<br>
- SQL_INFO_AUTOINCREMENT_IDS);<br>
- mpstream_encode_array(stream, id_count);<br>
+ vstream_encode_enum(stream,
SQL_INFO_AUTOINCREMENT_IDS,<br>
+ "autoincrement_ids");<br>
+ vstream_encode_array(stream, id_count);<br>
struct autoinc_id_entry *id_entry;<br>
+ int i = 0;<br>
stailq_foreach_entry(id_entry, autoinc_id_list, link)
{<br>
int64_t value = id_entry->id;<br>
if (id_entry->id >= 0)<br>
- mpstream_encode_uint(stream, value);<br>
+ vstream_encode_uint(stream, value);<br>
else<br>
- mpstream_encode_int(stream, value);<br>
+ vstream_encode_int(stream, value);<br>
+ vstream_encode_array_commit(stream, i++);<br>
}<br>
+ vstream_encode_map_commit(stream);<br>
}<br>
+ if (!response->is_info_flattened)<br>
+ vstream_encode_map_commit(stream);<br>
}<br>
finish:<br>
port_destroy(&response->port);<br>
diff --git a/src/box/execute.h b/src/box/execute.h<br>
index 65ac81c..56b7339 100644<br>
--- a/src/box/execute.h<br>
+++ b/src/box/execute.h<br>
@@ -51,7 +51,7 @@ extern const char *sql_info_key_strs[];<br>
struct region;<br>
struct sql_bind;<br>
struct xrow_header;<br>
-struct mpstream;<br>
+struct vstream;<br>
<br>
/** EXECUTE request. */<br>
struct sql_request {<br>
@@ -74,6 +74,20 @@ struct sql_response {<br>
struct port port;<br>
/** Prepared SQL statement with metadata. */<br>
void *prep_stmt;<br>
+ /**<br>
+ * SQL response can be dumped into msgpack to be sent via<br>
+ * iproto or onto Lua stack to be returned into an<br>
+ * application. In the first case response body has<br>
+ * explicit field IPROTO_SQL_INFO: {rowcount = ...,<br>
+ * autoids = ...}. But in case of Lua this field is<br>
+ * flattened. A result never has 'info' field, it has<br>
+ * inlined 'rowcount' and 'autoids'. In iproto<br>
+ * IPROTO_SQL_INFO field is sent mostly to explicitly<br>
+ * distinguish two response types: DML/DDL vs DQL,<br>
+ * IPROTO_SQL_INFO vs IPROTO_METADATA. So this flag is set<br>
+ * by Lua and allows to flatten SQL_INFO fields.<br>
+ */<br>
+ bool is_info_flattened;<br>
};<br>
<br>
/**<br>
@@ -112,7 +126,7 @@ struct sql_response {<br>
*/<br>
int<br>
sql_response_dump(struct sql_response *response, int *keys,<br>
- struct mpstream *stream);<br>
+ struct vstream *stream);<br>
<br>
/**<br>
* Parse the EXECUTE request.<br>
diff --git a/src/box/iproto.cc b/src/box/iproto.cc<br>
index b110900..1c4c651 100644<br>
--- a/src/box/iproto.cc<br>
+++ b/src/box/iproto.cc<br>
@@ -62,6 +62,7 @@<br>
#include "execute.h"<br>
#include "errinj.h"<br>
#include "mpstream.h"<br>
+#include "vstream.h"<br>
<br>
enum {<br>
IPROTO_SALT_SIZE = 32,<br>
@@ -1587,6 +1588,7 @@ tx_process_sql(struct cmsg *m)<br>
struct iproto_msg *msg = tx_accept_msg(m);<br>
struct obuf *out;<br>
struct sql_response response;<br>
+ memset(&response, 0, sizeof(response));<br>
bool is_error = false;<br>
<br>
tx_fiber_init(msg->connection->session,
msg->header.sync);<br>
@@ -1607,16 +1609,18 @@ tx_process_sql(struct cmsg *m)<br>
/* Prepare memory for the iproto header. */<br>
if (iproto_prepare_header(out, &header_svp,
IPROTO_SQL_HEADER_LEN) != 0)<br>
goto error;<br>
- struct mpstream stream;<br>
- mpstream_init(&stream, out, obuf_reserve_cb,
obuf_alloc_cb,<br>
- set_encode_error, &is_error);<br>
+<br>
+ struct vstream stream;<br>
+ mpstream_init((struct mpstream *)&stream, out,
obuf_reserve_cb,<br>
+ obuf_alloc_cb, set_encode_error, &is_error);<br>
if (is_error)<br>
goto error;<br>
+ mp_vstream_init_vtab(&stream);<br>
if (sql_response_dump(&response, &keys, &stream)
!= 0 || is_error) {<br>
obuf_rollback_to_svp(out, &header_svp);<br>
goto error;<br>
}<br>
- mpstream_flush(&stream);<br>
+ mpstream_flush((struct mpstream *)&stream);<br>
iproto_reply_sql(out, &header_svp, response.sync,
schema_version, keys);<br>
iproto_wpos_create(&msg->wpos, out);<br>
return;<br>
diff --git a/src/box/vstream.h b/src/box/vstream.h<br>
new file mode 100644<br>
index 0000000..01a5212<br>
--- /dev/null<br>
+++ b/src/box/vstream.h<br>
@@ -0,0 +1,171 @@<br>
+#ifndef TARANTOOL_VSTREAM_H_INCLUDED<br>
+#define TARANTOOL_VSTREAM_H_INCLUDED<br>
+/*<br>
+ * Copyright 2010-2018, Tarantool AUTHORS, please see AUTHORS
file.<br>
+ *<br>
+ * Redistribution and use in source and binary forms, with or<br>
+ * without modification, are permitted provided that the
following<br>
+ * conditions are met:<br>
+ *<br>
+ * 1. Redistributions of source code must retain the above<br>
+ * copyright notice, this list of conditions and the<br>
+ * following disclaimer.<br>
+ *<br>
+ * 2. Redistributions in binary form must reproduce the above<br>
+ * copyright notice, this list of conditions and the following<br>
+ * disclaimer in the documentation and/or other materials<br>
+ * provided with the distribution.<br>
+ *<br>
+ * THIS SOFTWARE IS PROVIDED BY AUTHORS ``AS IS'' AND<br>
+ * ANY EXPRESS OR IMPLIED WARRANTIES, INCLUDING, BUT NOT LIMITED<br>
+ * TO, THE IMPLIED WARRANTIES OF MERCHANTABILITY AND FITNESS FOR<br>
+ * A PARTICULAR PURPOSE ARE DISCLAIMED. IN NO EVENT SHALL<br>
+ * AUTHORS OR CONTRIBUTORS BE LIABLE FOR ANY DIRECT,<br>
+ * INDIRECT, INCIDENTAL, SPECIAL, EXEMPLARY, OR CONSEQUENTIAL<br>
+ * DAMAGES (INCLUDING, BUT NOT LIMITED TO, PROCUREMENT OF<br>
+ * SUBSTITUTE GOODS OR SERVICES; LOSS OF USE, DATA, OR PROFITS;
OR<br>
+ * BUSINESS INTERRUPTION) HOWEVER CAUSED AND ON ANY THEORY OF<br>
+ * LIABILITY, WHETHER IN CONTRACT, STRICT LIABILITY, OR TORT<br>
+ * (INCLUDING NEGLIGENCE OR OTHERWISE) ARISING IN ANY WAY OUT OF<br>
+ * THE USE OF THIS SOFTWARE, EVEN IF ADVISED OF THE POSSIBILITY
OF<br>
+ * SUCH DAMAGE.<br>
+ */<br>
+#if defined(__cplusplus)<br>
+extern "C" {<br>
+#endif /* defined(__cplusplus) */<br>
+<br>
+struct vstream;<br>
+struct lua_State;<br>
+struct port;<br>
+<br>
+typedef void (*encode_array_f)(struct vstream *stream, uint32_t
size);<br>
+typedef void (*encode_map_f)(struct vstream *stream, uint32_t
size);<br>
+typedef void (*encode_uint_f)(struct vstream *stream, uint64_t
num);<br>
+typedef void (*encode_int_f)(struct vstream *stream, int64_t
num);<br>
+typedef void (*encode_float_f)(struct vstream *stream, float
num);<br>
+typedef void (*encode_double_f)(struct vstream *stream, double
num);<br>
+typedef void (*encode_strn_f)(struct vstream *stream, const char
*str,<br>
+ uint32_t len);<br>
+typedef void (*encode_nil_f)(struct vstream *stream);<br>
+typedef void (*encode_bool_f)(struct vstream *stream, bool val);<br>
+typedef void (*encode_enum_f)(struct vstream *stream, int64_t
num,<br>
+ const char *str);<br>
+typedef int (*encode_port_f)(struct vstream *stream, struct port
*port);<br>
+typedef void (*encode_array_commit_f)(struct vstream *stream,
uint32_t id);<br>
+typedef void (*encode_map_commit_f)(struct vstream *stream);<br>
+<br>
+struct vstream_vtab {<br>
+ encode_array_f encode_array;<br>
+ encode_map_f encode_map;<br>
+ encode_uint_f encode_uint;<br>
+ encode_int_f encode_int;<br>
+ encode_float_f encode_float;<br>
+ encode_double_f encode_double;<br>
+ encode_strn_f encode_strn;<br>
+ encode_nil_f encode_nil;<br>
+ encode_bool_f encode_bool;<br>
+ encode_enum_f encode_enum;<br>
+ encode_port_f encode_port;<br>
+ encode_array_commit_f encode_array_commit;<br>
+ encode_map_commit_f encode_map_commit;<br>
+};<br>
+<br>
+struct vstream {<br>
+ /** Here struct mpstream lives under the hood. */<br>
+ char inheritance_padding[64];<br>
+ /** Virtual function table. */<br>
+ const struct vstream_vtab *vtab;<br>
+};<br>
+<br>
+void<br>
+mp_vstream_init_vtab(struct vstream *vstream);<br>
+<br>
+static inline void<br>
+vstream_encode_array(struct vstream *stream, uint32_t size)<br>
+{<br>
+ return stream->vtab->encode_array(stream, size);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_map(struct vstream *stream, uint32_t size)<br>
+{<br>
+ return stream->vtab->encode_map(stream, size);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_uint(struct vstream *stream, uint64_t num)<br>
+{<br>
+ return stream->vtab->encode_uint(stream, num);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_int(struct vstream *stream, int64_t num)<br>
+{<br>
+ return stream->vtab->encode_int(stream, num);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_float(struct vstream *stream, float num)<br>
+{<br>
+ return stream->vtab->encode_float(stream, num);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_double(struct vstream *stream, double num)<br>
+{<br>
+ return stream->vtab->encode_double(stream, num);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_strn(struct vstream *stream, const char *str,
uint32_t len)<br>
+{<br>
+ return stream->vtab->encode_strn(stream, str, len);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_str(struct vstream *stream, const char *str)<br>
+{<br>
+ return stream->vtab->encode_strn(stream, str,
strlen(str));<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_nil(struct vstream *stream)<br>
+{<br>
+ return stream->vtab->encode_nil(stream);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_bool(struct vstream *stream, bool val)<br>
+{<br>
+ return stream->vtab->encode_bool(stream, val);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_enum(struct vstream *stream, int64_t num, const
char *str)<br>
+{<br>
+ return stream->vtab->encode_enum(stream, num, str);<br>
+}<br>
+<br>
+static inline int<br>
+vstream_encode_port(struct vstream *stream, struct port *port)<br>
+{<br>
+ return stream->vtab->encode_port(stream, port);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_map_commit(struct vstream *stream)<br>
+{<br>
+ return stream->vtab->encode_map_commit(stream);<br>
+}<br>
+<br>
+static inline void<br>
+vstream_encode_array_commit(struct vstream *stream, uint32_t id)<br>
+{<br>
+ return stream->vtab->encode_array_commit(stream, id);<br>
+}<br>
+<br>
+#if defined(__cplusplus)<br>
+} /* extern "C" */<br>
+#endif /* defined(__cplusplus) */<br>
+<br>
+#endif /* TARANTOOL_VSTREAM_H_INCLUDED */<br>
diff --git a/src/mpstream.c b/src/mpstream.c<br>
index e4f7950..4091ead 100644<br>
--- a/src/mpstream.c<br>
+++ b/src/mpstream.c<br>
@@ -33,6 +33,8 @@<br>
#include <assert.h><br>
#include <stdint.h><br>
#include "msgpuck.h"<br>
+#include "box/vstream.h"<br>
+#include "box/port.h"<br>
<br>
void<br>
mpstream_reserve_slow(struct mpstream *stream, size_t size)<br>
@@ -175,3 +177,54 @@ mpstream_encode_bool(struct mpstream *stream,
bool val)<br>
char *pos = mp_encode_bool(data, val);<br>
mpstream_advance(stream, pos - data);<br>
}<br>
+<br>
+int<br>
+mp_vstream_encode_port(struct vstream *stream, struct port *port)<br>
+{<br>
+ struct mpstream *mpstream = (struct mpstream *)stream;<br>
+ mpstream_flush(mpstream);<br>
+ if (port_dump_msgpack(port, mpstream->ctx) < 0) {<br>
+ /* Failed port dump destroyes the port. */<br>
+ return -1;<br>
+ }<br>
+ mpstream_reset(mpstream);<br>
+ return 0;<br>
+}<br>
+<br>
+void<br>
+mp_vstream_encode_enum(struct vstream *stream, int64_t num, const
char *str)<br>
+{<br>
+ (void)str;<br>
+ if (num < 0)<br>
+ mpstream_encode_int((struct mpstream *)stream, num);<br>
+ else<br>
+ mpstream_encode_uint((struct mpstream *)stream, num);<br>
+}<br>
+<br>
+void<br>
+mp_vstream_noop(struct vstream *stream, ...)<br>
+{<br>
+ (void) stream;<br>
+}<br>
+<br>
+const struct vstream_vtab mp_vstream_vtab = {<br>
+ /** encode_array = */ (encode_array_f)mpstream_encode_array,<br>
+ /** encode_map = */ (encode_map_f)mpstream_encode_map,<br>
+ /** encode_uint = */ (encode_uint_f)mpstream_encode_uint,<br>
+ /** encode_int = */ (encode_int_f)mpstream_encode_int,<br>
+ /** encode_float = */ (encode_float_f)mpstream_encode_float,<br>
+ /** encode_double = */
(encode_double_f)mpstream_encode_double,<br>
+ /** encode_strn = */ (encode_strn_f)mpstream_encode_strn,<br>
+ /** encode_nil = */ (encode_nil_f)mpstream_encode_nil,<br>
+ /** encode_bool = */ (encode_bool_f)mpstream_encode_bool,<br>
+ /** encode_enum = */ mp_vstream_encode_enum,<br>
+ /** encode_port = */ mp_vstream_encode_port,<br>
+ /** encode_array_commit = */
(encode_array_commit_f)mp_vstream_noop,<br>
+ /** encode_map_commit = */
(encode_map_commit_f)mp_vstream_noop,<br>
+};<br>
+<br>
+void<br>
+mp_vstream_init_vtab(struct vstream *vstream)<br>
+{<br>
+ vstream->vtab = &mp_vstream_vtab;<br>
+}<br>
<br>
</p>
</body>
</html>