[tarantool-patches] [PATCH v1 04/10] sql: create interface vstream

imeevma at tarantool.org imeevma at tarantool.org
Sat Nov 17 17:03:57 MSK 2018


If we want to use functions from execute.h not only in IPROTO we
should create special interface. This interface will allow us to
create different implementations for mpstream and lua_State and
use functions from execute.c without changing them. This patch
creates such interface and its implementation for mpstream and
replaces mpstream functions in execute.c by methods of this
interface.

Needed for #3505
---
 src/box/CMakeLists.txt |   1 +
 src/box/execute.c      |  92 +++++++++--------------
 src/box/execute.h      |   4 +-
 src/box/iproto.cc      |  13 +++-
 src/box/vstream.c      | 200 +++++++++++++++++++++++++++++++++++++++++++++++++
 src/box/vstream.h      | 191 ++++++++++++++++++++++++++++++++++++++++++++++
 6 files changed, 439 insertions(+), 62 deletions(-)
 create mode 100644 src/box/vstream.c
 create mode 100644 src/box/vstream.h

diff --git a/src/box/CMakeLists.txt b/src/box/CMakeLists.txt
index d127647..09cb245 100644
--- a/src/box/CMakeLists.txt
+++ b/src/box/CMakeLists.txt
@@ -56,6 +56,7 @@ add_library(xlog STATIC xlog.c)
 target_link_libraries(xlog core box_error crc32 ${ZSTD_LIBRARIES})
 
 add_library(box STATIC
+    vstream.c
     iproto.cc
     error.cc
     xrow_io.cc
diff --git a/src/box/execute.c b/src/box/execute.c
index 5c2ec19..80ad655 100644
--- a/src/box/execute.c
+++ b/src/box/execute.c
@@ -37,11 +37,11 @@
 #include "small/region.h"
 #include "diag.h"
 #include "sql.h"
-#include "xrow.h"
 #include "schema.h"
 #include "port.h"
 #include "tuple.h"
 #include "sql/vdbe.h"
+#include "vstream.h"
 
 const char *sql_type_strs[] = {
 	NULL,
@@ -453,20 +453,12 @@ sql_bind(const struct sql_request *request, struct sqlite3_stmt *stmt)
  * @retval -1 Client or memory error.
  */
 static inline int
-sql_get_description(struct sqlite3_stmt *stmt, struct mpstream *stream,
+sql_get_description(struct sqlite3_stmt *stmt, struct vstream *stream,
 		    int column_count)
 {
 	assert(column_count > 0);
-	char *pos = mpstream_reserve(stream, IPROTO_KEY_HEADER_LEN);
-	if (pos == NULL) {
-		diag_set(OutOfMemory, IPROTO_KEY_HEADER_LEN, "mpstream_reserve",
-			 "pos");
-		return -1;
-	}
-	pos = mp_store_u8(pos, IPROTO_METADATA);
-	pos = mp_store_u8(pos, 0xdd);
-	pos = mp_store_u32(pos, column_count);
-	mpstream_advance(stream, IPROTO_KEY_HEADER_LEN);
+	vstream_encode_reply_array(stream, column_count, IPROTO_METADATA,
+				   "metadata");
 	for (int i = 0; i < column_count; ++i) {
 		const char *name = sqlite3_column_name(stmt, i);
 		const char *type = sqlite3_column_datatype(stmt, i);
@@ -476,12 +468,19 @@ sql_get_description(struct sqlite3_stmt *stmt, struct mpstream *stream,
 		 * column_name simply returns them.
 		 */
 		assert(name != NULL);
-		mpstream_encode_map(stream, 2);
-		mpstream_encode_uint(stream, IPROTO_FIELD_NAME);
-		mpstream_encode_str(stream, name);
-		mpstream_encode_uint(stream, IPROTO_FIELD_TYPE);
-		mpstream_encode_str(stream, type);
+		vstream_encode_map(stream, 2);
+
+		vstream_encode_enum(stream, IPROTO_FIELD_NAME, "name");
+		vstream_encode_str(stream, name);
+		vstream_encode_map_commit(stream);
+
+		vstream_encode_enum(stream, IPROTO_FIELD_TYPE, "type");
+		vstream_encode_str(stream, type);
+		vstream_encode_map_commit(stream);
+
+		vstream_encode_array_commit(stream, i);
 	}
+	vstream_encode_reply_commit(stream);
 	return 0;
 }
 
@@ -540,7 +539,7 @@ sql_prepare_and_execute(const struct sql_request *request,
 
 int
 sql_response_dump(struct sql_response *response, int *keys,
-		  struct mpstream *stream)
+		  struct vstream *stream)
 {
 	sqlite3 *db = sql_get();
 	struct sqlite3_stmt *stmt = (struct sqlite3_stmt *) response->prep_stmt;
@@ -553,27 +552,11 @@ err:
 			goto finish;
 		}
 		*keys = 2;
-		char *pos = mpstream_reserve(stream, IPROTO_KEY_HEADER_LEN);
-		if (pos == NULL) {
-			diag_set(OutOfMemory, IPROTO_KEY_HEADER_LEN,
-				 "mpstream_reserve", "pos");
+		vstream_encode_reply_array(stream, port_tuple->size,
+					   IPROTO_DATA, "rows");
+		if (vstream_encode_port(stream, &response->port) < 0)
 			goto err;
-		}
-		pos = mp_store_u8(pos, IPROTO_DATA);
-		pos = mp_store_u8(pos, 0xdd);
-		pos = mp_store_u32(pos, port_tuple->size);
-		mpstream_advance(stream, IPROTO_KEY_HEADER_LEN);
-
-		mpstream_flush(stream);
-		/*
-		 * Just like SELECT, SQL uses output format compatible
-		 * with Tarantool 1.6
-		 */
-		if (port_dump_msgpack_16(&response->port, stream->ctx) < 0) {
-			/* Failed port dump destroyes the port. */
-			goto err;
-		}
-		mpstream_reset(stream);
+		vstream_encode_reply_commit(stream);
 	} else {
 		*keys = 1;
 		assert(port_tuple->size == 0);
@@ -586,32 +569,29 @@ err:
 			stailq_foreach_entry(id_entry, autoinc_id_list, link)
 				id_count++;
 		}
-		char *pos = mpstream_reserve(stream, IPROTO_KEY_HEADER_LEN);
-		if (pos == NULL) {
-			diag_set(OutOfMemory, IPROTO_KEY_HEADER_LEN,
-				 "mpstream_reserve", "pos");
-			goto err;
-		}
-		pos = mp_store_u8(pos, IPROTO_SQL_INFO);
-		pos = mp_store_u8(pos, 0xdf);
-		pos = mp_store_u32(pos, map_size);
-		mpstream_advance(stream, IPROTO_KEY_HEADER_LEN);
-
-		mpstream_encode_uint(stream, SQL_INFO_ROW_COUNT);
-		mpstream_encode_uint(stream, db->nChange);
+		stream->is_flatten = true;
+		vstream_encode_reply_map(stream, map_size, IPROTO_SQL_INFO,
+					 "info");
+		vstream_encode_enum(stream, SQL_INFO_ROW_COUNT, "rowcount");
+		vstream_encode_uint(stream, db->nChange);
+		vstream_encode_map_commit(stream);
 		if (!stailq_empty(autoinc_id_list)) {
-			mpstream_encode_uint(stream,
-					     SQL_INFO_AUTOINCREMENT_IDS);
-			mpstream_encode_array(stream, id_count);
+			vstream_encode_enum(stream, SQL_INFO_AUTOINCREMENT_IDS,
+					    "autoincrement_ids");
+			vstream_encode_array(stream, id_count);
 			struct autoinc_id_entry *id_entry;
+			int i = 0;
 			stailq_foreach_entry(id_entry, autoinc_id_list, link) {
 				int64_t value = id_entry->id;
 				if (id_entry->id >= 0)
-					mpstream_encode_uint(stream, value);
+					vstream_encode_uint(stream, value);
 				else
-					mpstream_encode_int(stream, value);
+					vstream_encode_int(stream, value);
+				vstream_encode_array_commit(stream, i);
 			}
+			vstream_encode_map_commit(stream);
 		}
+		vstream_encode_reply_commit(stream);
 	}
 finish:
 	port_destroy(&response->port);
diff --git a/src/box/execute.h b/src/box/execute.h
index 7eb2121..882334f 100644
--- a/src/box/execute.h
+++ b/src/box/execute.h
@@ -34,7 +34,6 @@
 #include <stdint.h>
 #include <stdbool.h>
 #include "port.h"
-#include "mpstream.h"
 
 #if defined(__cplusplus)
 extern "C" {
@@ -53,6 +52,7 @@ struct obuf;
 struct region;
 struct sql_bind;
 struct xrow_header;
+struct vstream;
 
 /** EXECUTE request. */
 struct sql_request {
@@ -113,7 +113,7 @@ struct sql_response {
  */
 int
 sql_response_dump(struct sql_response *response, int *keys,
-		  struct mpstream *stream);
+		  struct vstream *stream);
 
 /**
  * Parse MessagePack array of SQL parameters and store a result
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index 83b268b..f823c2d 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -61,6 +61,8 @@
 #include "rmean.h"
 #include "execute.h"
 #include "errinj.h"
+#include "vstream.h"
+#include "mpstream.h"
 
 enum {
 	IPROTO_SALT_SIZE = 32,
@@ -1667,16 +1669,19 @@ tx_process_sql(struct cmsg *m)
 	/* Prepare memory for the iproto header. */
 	if (iproto_prepare_header(out, &header_svp, IPROTO_SQL_HEADER_LEN) != 0)
 		goto error;
-	struct mpstream stream;
-	mpstream_init(&stream, out, obuf_reserve_cb, obuf_alloc_cb,
+
+	struct mpstream mpstream;
+	mpstream_init(&mpstream, out, obuf_reserve_cb, obuf_alloc_cb,
 		      set_encode_error, &is_error);
 	if (is_error)
 		goto error;
-	if (sql_response_dump(&response, &keys, &stream) != 0) {
+	struct vstream vstream;
+	mp_vstream_init(&vstream, &mpstream);
+	if (sql_response_dump(&response, &keys, &vstream) != 0) {
 		obuf_rollback_to_svp(out, &header_svp);
 		goto error;
 	}
-	mpstream_flush(&stream);
+	mpstream_flush(&mpstream);
 	iproto_reply_sql(out, &header_svp, response.sync, schema_version, keys);
 	iproto_wpos_create(&msg->wpos, out);
 	return;
diff --git a/src/box/vstream.c b/src/box/vstream.c
new file mode 100644
index 0000000..d43c352
--- /dev/null
+++ b/src/box/vstream.c
@@ -0,0 +1,200 @@
+/*
+ * 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 AUTHORS ``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
+ * AUTHORS 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 "vstream.h"
+#include "mpstream.h"
+#include "iproto_constants.h"
+#include "port.h"
+#include "xrow.h"
+
+void
+mp_vstream_encode_array(struct vstream *stream, uint32_t size)
+{
+	mpstream_encode_array(stream->mpstream, size);
+}
+
+void
+mp_vstream_encode_map(struct vstream *stream, uint32_t size)
+{
+	mpstream_encode_map(stream->mpstream, size);
+}
+
+void
+mp_vstream_encode_uint(struct vstream *stream, uint64_t num)
+{
+	mpstream_encode_uint(stream->mpstream, num);
+}
+
+void
+mp_vstream_encode_int(struct vstream *stream, int64_t num)
+{
+	mpstream_encode_int(stream->mpstream, num);
+}
+
+void
+mp_vstream_encode_float(struct vstream *stream, float num)
+{
+	mpstream_encode_float(stream->mpstream, num);
+}
+
+void
+mp_vstream_encode_double(struct vstream *stream, double num)
+{
+	mpstream_encode_double(stream->mpstream, num);
+}
+
+void
+mp_vstream_encode_strn(struct vstream *stream, const char *str, uint32_t len)
+{
+	mpstream_encode_strn(stream->mpstream, str, len);
+}
+
+void
+mp_vstream_encode_nil(struct vstream *stream)
+{
+	mpstream_encode_nil(stream->mpstream);
+}
+
+void
+mp_vstream_encode_bool(struct vstream *stream, bool val)
+{
+	mpstream_encode_bool(stream->mpstream, val);
+}
+
+int
+mp_vstream_encode_port(struct vstream *stream, struct port *port)
+{
+	mpstream_flush(stream->mpstream);
+	/*
+	 * Just like SELECT, SQL uses output format compatible
+	 * with Tarantool 1.6
+	 */
+	if (port_dump_msgpack_16(port, stream->mpstream->ctx) < 0) {
+		/* Failed port dump destroyes the port. */
+		return -1;
+	}
+	mpstream_reset(stream->mpstream);
+	return 0;
+}
+
+int
+mp_vstream_encode_reply_array(struct vstream *stream, uint32_t size,
+			      uint8_t key, const char *str)
+{
+	(void)str;
+	uint8_t type = 0xdd;
+	char *pos = mpstream_reserve(stream->mpstream, IPROTO_KEY_HEADER_LEN);
+	if (pos == NULL) {
+		diag_set(OutOfMemory, IPROTO_KEY_HEADER_LEN,
+			 "mpstream_reserve", "pos");
+		return -1;
+	}
+	pos = mp_store_u8(pos, key);
+	pos = mp_store_u8(pos, type);
+	pos = mp_store_u32(pos, size);
+	mpstream_advance(stream->mpstream, IPROTO_KEY_HEADER_LEN);
+	return 0;
+}
+
+int
+mp_vstream_encode_reply_map(struct vstream *stream, uint32_t size, uint8_t key,
+			    const char *str)
+{
+	(void)str;
+	uint8_t type = 0xdf;
+	char *pos = mpstream_reserve(stream->mpstream, IPROTO_KEY_HEADER_LEN);
+	if (pos == NULL) {
+		diag_set(OutOfMemory, IPROTO_KEY_HEADER_LEN,
+			 "mpstream_reserve", "pos");
+		return -1;
+	}
+	pos = mp_store_u8(pos, key);
+	pos = mp_store_u8(pos, type);
+	pos = mp_store_u32(pos, size);
+	mpstream_advance(stream->mpstream, IPROTO_KEY_HEADER_LEN);
+	return 0;
+}
+
+void
+mp_vstream_encode_enum(struct vstream *stream, int64_t num, const char *str)
+{
+	(void)str;
+	if (num < 0)
+		mpstream_encode_int(stream->mpstream, num);
+	else
+		mpstream_encode_uint(stream->mpstream, num);
+}
+
+void
+mp_vstream_encode_reply_commit(struct vstream *stream)
+{
+	(void)stream;
+}
+
+void
+mp_vstream_encode_map_commit(struct vstream *stream)
+{
+	(void)stream;
+}
+
+void
+mp_vstream_encode_array_commit(struct vstream *stream, uint32_t id)
+{
+	(void)stream;
+	(void)id;
+}
+
+const struct vstream_vtab mp_vstream_vtab = {
+	/** encode_array = */ mp_vstream_encode_array,
+	/** encode_map = */ mp_vstream_encode_map,
+	/** encode_uint = */ mp_vstream_encode_uint,
+	/** encode_int = */ mp_vstream_encode_int,
+	/** encode_float = */ mp_vstream_encode_float,
+	/** encode_double = */ mp_vstream_encode_double,
+	/** encode_strn = */ mp_vstream_encode_strn,
+	/** encode_nil = */ mp_vstream_encode_nil,
+	/** encode_bool = */ mp_vstream_encode_bool,
+	/** encode_enum = */ mp_vstream_encode_enum,
+	/** encode_port = */ mp_vstream_encode_port,
+	/** encode_reply_array = */ mp_vstream_encode_reply_array,
+	/** encode_reply_map = */ mp_vstream_encode_reply_map,
+	/** encode_array_commit = */ mp_vstream_encode_array_commit,
+	/** encode_reply_commit = */ mp_vstream_encode_reply_commit,
+	/** encode_map_commit = */ mp_vstream_encode_map_commit,
+};
+
+void
+mp_vstream_init(struct vstream *vstream, struct mpstream *mpstream)
+{
+	vstream->vtab = &mp_vstream_vtab;
+	vstream->mpstream = mpstream;
+	vstream->is_flatten = false;
+}
diff --git a/src/box/vstream.h b/src/box/vstream.h
new file mode 100644
index 0000000..42f9813
--- /dev/null
+++ b/src/box/vstream.h
@@ -0,0 +1,191 @@
+#ifndef TARANTOOL_VSTREAM_H_INCLUDED
+#define TARANTOOL_VSTREAM_H_INCLUDED
+/*
+ * 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 AUTHORS ``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
+ * AUTHORS 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) */
+
+struct vstream;
+struct mpstream;
+struct lua_State;
+struct port;
+
+struct vstream_vtab {
+	void (*encode_array)(struct vstream *stream, uint32_t size);
+	void (*encode_map)(struct vstream *stream, uint32_t size);
+	void (*encode_uint)(struct vstream *stream, uint64_t num);
+	void (*encode_int)(struct vstream *stream, int64_t num);
+	void (*encode_float)(struct vstream *stream, float num);
+	void (*encode_double)(struct vstream *stream, double num);
+	void (*encode_strn)(struct vstream *stream, const char *str,
+			    uint32_t len);
+	void (*encode_nil)(struct vstream *stream);
+	void (*encode_bool)(struct vstream *stream, bool val);
+	void (*encode_enum)(struct vstream *stream, int64_t num,
+			    const char *str);
+	int (*encode_port)(struct vstream *stream, struct port *port);
+	int (*encode_reply_array)(struct vstream *stream, uint32_t size,
+				  uint8_t key, const char *str);
+	int (*encode_reply_map)(struct vstream *stream, uint32_t size,
+				uint8_t key, const char *str);
+	void (*encode_array_commit)(struct vstream *stream, uint32_t id);
+	void (*encode_reply_commit)(struct vstream *stream);
+	void (*encode_map_commit)(struct vstream *stream);
+};
+
+struct vstream {
+	/** Virtual function table. */
+	const struct vstream_vtab *vtab;
+	/** TODO: Write comment. */
+	union {
+		struct mpstream *mpstream;
+		struct lua_State *L;
+	};
+	/** TODO: Write comment. */
+	bool is_flatten;
+};
+
+void
+mp_vstream_init(struct vstream *vstream, struct mpstream *mpstream);
+
+static inline void
+vstream_encode_array(struct vstream *stream, uint32_t size)
+{
+	return stream->vtab->encode_array(stream, size);
+}
+
+static inline void
+vstream_encode_map(struct vstream *stream, uint32_t size)
+{
+	return stream->vtab->encode_map(stream, size);
+}
+
+static inline void
+vstream_encode_uint(struct vstream *stream, uint64_t num)
+{
+	return stream->vtab->encode_uint(stream, num);
+}
+
+static inline void
+vstream_encode_int(struct vstream *stream, int64_t num)
+{
+	return stream->vtab->encode_int(stream, num);
+}
+
+static inline void
+vstream_encode_float(struct vstream *stream, float num)
+{
+	return stream->vtab->encode_float(stream, num);
+}
+
+static inline void
+vstream_encode_double(struct vstream *stream, double num)
+{
+	return stream->vtab->encode_double(stream, num);
+}
+
+static inline void
+vstream_encode_strn(struct vstream *stream, const char *str, uint32_t len)
+{
+	return stream->vtab->encode_strn(stream, str, len);
+}
+
+static inline void
+vstream_encode_str(struct vstream *stream, const char *str)
+{
+	return stream->vtab->encode_strn(stream, str, strlen(str));
+}
+
+static inline void
+vstream_encode_nil(struct vstream *stream)
+{
+	return stream->vtab->encode_nil(stream);
+}
+
+static inline void
+vstream_encode_bool(struct vstream *stream, bool val)
+{
+	return stream->vtab->encode_bool(stream, val);
+}
+
+static inline void
+vstream_encode_enum(struct vstream *stream, int64_t num, const char *str)
+{
+	return stream->vtab->encode_enum(stream, num, str);
+}
+
+static inline int
+vstream_encode_port(struct vstream *stream, struct port *port)
+{
+	return stream->vtab->encode_port(stream, port);
+}
+
+static inline int
+vstream_encode_reply_array(struct vstream *stream, uint32_t size, uint8_t key,
+			   const char *str)
+{
+	return stream->vtab->encode_reply_array(stream, size, key, str);
+}
+
+static inline int
+vstream_encode_reply_map(struct vstream *stream, uint32_t size, uint8_t key,
+			 const char *str)
+{
+	return stream->vtab->encode_reply_map(stream, size, key, str);
+}
+
+static inline void
+vstream_encode_reply_commit(struct vstream *stream)
+{
+	return stream->vtab->encode_reply_commit(stream);
+}
+
+static inline void
+vstream_encode_map_commit(struct vstream *stream)
+{
+	return stream->vtab->encode_map_commit(stream);
+}
+
+static inline void
+vstream_encode_array_commit(struct vstream *stream, uint32_t id)
+{
+	return stream->vtab->encode_array_commit(stream, id);
+}
+
+#if defined(__cplusplus)
+} /* extern "C" */
+#endif /* defined(__cplusplus) */
+
+#endif /* TARANTOOL_VSTREAM_H_INCLUDED */
-- 
2.7.4





More information about the Tarantool-patches mailing list