[tarantool-patches] [PATCH v5 2/5] iproto: create port_sql

imeevma at tarantool.org imeevma at tarantool.org
Sat Dec 22 14:31:52 MSK 2018


This patch creates port_sql implementation for the port. This will
allow us to dump sql responses to obuf or to Lua. Also this patch
defines methods dump_msgpack() and destroy() of port_sql.

Part of #3505
---
 src/box/execute.c | 90 ++++++++++++++++++++++++++++++++++++++++++-------------
 src/box/execute.h | 67 +++++++++++++++--------------------------
 src/box/iproto.cc |  6 ++--
 src/box/port.h    |  1 -
 4 files changed, 96 insertions(+), 68 deletions(-)

diff --git a/src/box/execute.c b/src/box/execute.c
index 38b6cbc..b07de28 100644
--- a/src/box/execute.c
+++ b/src/box/execute.c
@@ -530,7 +530,7 @@ sql_execute(sqlite3 *db, struct sqlite3_stmt *stmt, struct port *port,
 
 int
 sql_prepare_and_execute(const char *sql, int len, const struct sql_bind *bind,
-			uint32_t bind_count, struct sql_response *response,
+			uint32_t bind_count, struct port *port,
 			struct region *region)
 {
 	struct sqlite3_stmt *stmt;
@@ -544,22 +544,56 @@ sql_prepare_and_execute(const char *sql, int len, const struct sql_bind *bind,
 		return -1;
 	}
 	assert(stmt != NULL);
-	port_tuple_create(&response->port);
-	response->prep_stmt = stmt;
+	port_tuple_create(port);
 	if (sql_bind(stmt, bind, bind_count) == 0 &&
-	    sql_execute(db, stmt, &response->port, region) == 0)
+	    sql_execute(db, stmt, port, region) == 0) {
+		port_tuple_to_port_sql(port, stmt);
 		return 0;
-	port_destroy(&response->port);
+	}
+	port_destroy(port);
 	sqlite3_finalize(stmt);
 	return -1;
 }
 
-int
-sql_response_dump(struct sql_response *response, struct obuf *out)
+/**
+ * Dump a built response into @an out buffer. The response is
+ * destroyed.
+ * Response structure:
+ * +----------------------------------------------+
+ * | IPROTO_OK, sync, schema_version   ...        | iproto_header
+ * +----------------------------------------------+---------------
+ * | Body - a map with one or two keys.           |
+ * |                                              |
+ * | IPROTO_BODY: {                               |
+ * |     IPROTO_METADATA: [                       |
+ * |         {IPROTO_FIELD_NAME: column name1},   |
+ * |         {IPROTO_FIELD_NAME: column name2},   | iproto_body
+ * |         ...                                  |
+ * |     ],                                       |
+ * |                                              |
+ * |     IPROTO_DATA: [                           |
+ * |         tuple, tuple, tuple, ...             |
+ * |     ]                                        |
+ * | }                                            |
+ * +-------------------- OR ----------------------+
+ * | IPROTO_BODY: {                               |
+ * |     IPROTO_SQL_INFO: {                       |
+ * |         SQL_INFO_ROW_COUNT: number           |
+ * |     }                                        |
+ * | }                                            |
+ * +----------------------------------------------+
+ * @param port port with EXECUTE response.
+ * @param out Output buffer.
+ *
+ * @retval  0 Success.
+ * @retval -1 Memory error.
+ */
+static int
+port_sql_dump_msgpack(struct port *port, struct obuf *out)
 {
+	assert(port->vtab == &port_sql_vtab);
 	sqlite3 *db = sql_get();
-	struct sqlite3_stmt *stmt = (struct sqlite3_stmt *) response->prep_stmt;
-	struct port_tuple *port_tuple = (struct port_tuple *) &response->port;
+	struct sqlite3_stmt *stmt = ((struct port_sql *)port)->stmt;
 	int rc = 0, column_count = sqlite3_column_count(stmt);
 	if (column_count > 0) {
 		int keys = 2;
@@ -575,26 +609,18 @@ err:
 			rc = -1;
 			goto finish;
 		}
-		size = mp_sizeof_uint(IPROTO_DATA) +
-		       mp_sizeof_array(port_tuple->size);
+		size = mp_sizeof_uint(IPROTO_DATA);
 		pos = (char *) obuf_alloc(out, size);
 		if (pos == NULL) {
 			diag_set(OutOfMemory, size, "obuf_alloc", "pos");
 			goto err;
 		}
 		pos = mp_encode_uint(pos, IPROTO_DATA);
-		pos = mp_encode_array(pos, port_tuple->size);
-		/*
-		 * Just like SELECT, SQL uses output format compatible
-		 * with Tarantool 1.6
-		 */
-		if (port_dump_msgpack_16(&response->port, out) < 0) {
-			/* Failed port dump destroyes the port. */
+		if (port_tuple_vtab.dump_msgpack(port, out) < 0)
 			goto err;
-		}
 	} else {
 		int keys = 1;
-		assert(port_tuple->size == 0);
+		assert(((struct port_tuple *)port)->size == 0);
 		struct stailq *autoinc_id_list =
 			vdbe_autoinc_id_list((struct Vdbe *)stmt);
 		uint32_t map_size = stailq_empty(autoinc_id_list) ? 1 : 2;
@@ -643,7 +669,29 @@ err:
 		}
 	}
 finish:
-	port_destroy(&response->port);
+	port_destroy(port);
 	sqlite3_finalize(stmt);
 	return rc;
 }
+
+static void
+port_sql_destroy(struct port *base)
+{
+	port_tuple_vtab.destroy(base);
+}
+
+void
+port_tuple_to_port_sql(struct port *port, struct sqlite3_stmt *stmt)
+{
+	assert(port->vtab == &port_tuple_vtab);
+	((struct port_sql *)port)->stmt = stmt;
+	port->vtab = &port_sql_vtab;
+}
+
+const struct port_vtab port_sql_vtab = {
+	.dump_msgpack = port_sql_dump_msgpack,
+	.dump_msgpack_16 = NULL,
+	.dump_lua = NULL,
+	.dump_plain = NULL,
+	.destroy = port_sql_destroy,
+};
diff --git a/src/box/execute.h b/src/box/execute.h
index 60b8f31..5aef546 100644
--- a/src/box/execute.h
+++ b/src/box/execute.h
@@ -51,14 +51,31 @@ extern const char *sql_info_key_strs[];
 struct obuf;
 struct region;
 struct sql_bind;
+struct sqlite3_stmt;
 
-/** Response on EXECUTE request. */
-struct sql_response {
-	/** Port with response data if any. */
-	struct port port;
-	/** Prepared SQL statement with metadata. */
-	void *prep_stmt;
+/**
+ * Port implementation used for dump tuples, stored in port_tuple,
+ * to obuf or Lua.
+ */
+struct port_sql {
+	/* port_tuple to inherit from. */
+	struct port_tuple port_tuple;
+	/* Prepared SQL statement. */
+	struct sqlite3_stmt *stmt;
 };
+static_assert(sizeof(struct port_sql) <= sizeof(struct port),
+	      "sizeof(struct port_sql) must be <= sizeof(struct port)");
+
+extern const struct port_vtab port_sql_vtab;
+
+/**
+ * Transform port_tuple with already stored tuples to port_sql
+ * that will dump these tuples into obut or Lua.
+ *
+ * @param port port_tuple to transform into port_sql.
+ */
+void
+port_tuple_to_port_sql(struct port *port, struct sqlite3_stmt *stmt);
 
 /**
  * Parse MessagePack array of SQL parameters.
@@ -78,42 +95,6 @@ int
 sql_bind_list_decode(const char *data, struct sql_bind **out_bind);
 
 /**
- * Dump a built response into @an out buffer. The response is
- * destroyed.
- * Response structure:
- * +----------------------------------------------+
- * | IPROTO_OK, sync, schema_version   ...        | iproto_header
- * +----------------------------------------------+---------------
- * | Body - a map with one or two keys.           |
- * |                                              |
- * | IPROTO_BODY: {                               |
- * |     IPROTO_METADATA: [                       |
- * |         {IPROTO_FIELD_NAME: column name1},   |
- * |         {IPROTO_FIELD_NAME: column name2},   | iproto_body
- * |         ...                                  |
- * |     ],                                       |
- * |                                              |
- * |     IPROTO_DATA: [                           |
- * |         tuple, tuple, tuple, ...             |
- * |     ]                                        |
- * | }                                            |
- * +-------------------- OR ----------------------+
- * | IPROTO_BODY: {                               |
- * |     IPROTO_SQL_INFO: {                       |
- * |         SQL_INFO_ROW_COUNT: number           |
- * |     }                                        |
- * | }                                            |
- * +----------------------------------------------+
- * @param response EXECUTE response.
- * @param out Output buffer.
- *
- * @retval  0 Success.
- * @retval -1 Memory error.
- */
-int
-sql_response_dump(struct sql_response *response, struct obuf *out);
-
-/**
  * Prepare and execute an SQL statement.
  * @param sql SQL statement.
  * @param len Length of @a sql.
@@ -128,7 +109,7 @@ sql_response_dump(struct sql_response *response, struct obuf *out);
  */
 int
 sql_prepare_and_execute(const char *sql, int len, const struct sql_bind *bind,
-			uint32_t bind_count, struct sql_response *response,
+			uint32_t bind_count, struct port *port,
 			struct region *region);
 
 #if defined(__cplusplus)
diff --git a/src/box/iproto.cc b/src/box/iproto.cc
index e179de3..ee704e0 100644
--- a/src/box/iproto.cc
+++ b/src/box/iproto.cc
@@ -1613,7 +1613,7 @@ tx_process_sql(struct cmsg *m)
 {
 	struct iproto_msg *msg = tx_accept_msg(m);
 	struct obuf *out;
-	struct sql_response response;
+	struct port port;
 	struct sql_bind *bind;
 	int bind_count;
 	const char *sql;
@@ -1630,7 +1630,7 @@ tx_process_sql(struct cmsg *m)
 		goto error;
 	sql = msg->sql.sql_text;
 	sql = mp_decode_str(&sql, &len);
-	if (sql_prepare_and_execute(sql, len, bind, bind_count, &response,
+	if (sql_prepare_and_execute(sql, len, bind, bind_count, &port,
 				    &fiber()->gc) != 0)
 		goto error;
 	/*
@@ -1642,7 +1642,7 @@ tx_process_sql(struct cmsg *m)
 	/* Prepare memory for the iproto header. */
 	if (iproto_prepare_header(out, &header_svp, IPROTO_HEADER_LEN) != 0)
 		goto error;
-	if (sql_response_dump(&response, out) != 0) {
+	if (port_dump_msgpack(&port, out) != 0) {
 		obuf_rollback_to_svp(out, &header_svp);
 		goto error;
 	}
diff --git a/src/box/port.h b/src/box/port.h
index ad1b349..f188036 100644
--- a/src/box/port.h
+++ b/src/box/port.h
@@ -65,7 +65,6 @@ extern const struct port_vtab port_tuple_vtab;
 static inline struct port_tuple *
 port_tuple(struct port *port)
 {
-	assert(port->vtab == &port_tuple_vtab);
 	return (struct port_tuple *)port;
 }
 
-- 
2.7.4





More information about the Tarantool-patches mailing list