From mboxrd@z Thu Jan 1 00:00:00 1970 Return-Path: Received: from localhost (localhost [127.0.0.1]) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTP id 8125F1FD27 for ; Sat, 22 Dec 2018 06:31:55 -0500 (EST) Received: from turing.freelists.org ([127.0.0.1]) by localhost (turing.freelists.org [127.0.0.1]) (amavisd-new, port 10024) with ESMTP id JdhPs_0_F4Pa for ; Sat, 22 Dec 2018 06:31:55 -0500 (EST) Received: from smtpng2.m.smailru.net (smtpng2.m.smailru.net [94.100.179.3]) (using TLSv1.2 with cipher ECDHE-RSA-AES256-GCM-SHA384 (256/256 bits)) (No client certificate requested) by turing.freelists.org (Avenir Technologies Mail Multiplex) with ESMTPS id 1EA8921CE1 for ; Sat, 22 Dec 2018 06:31:55 -0500 (EST) From: imeevma@tarantool.org Subject: [tarantool-patches] [PATCH v5 2/5] iproto: create port_sql Date: Sat, 22 Dec 2018 14:31:52 +0300 Message-Id: <9c825dd4f7e2c18c829553caeeca4f525916866c.1545477494.git.imeevma@gmail.com> In-Reply-To: References: Sender: tarantool-patches-bounce@freelists.org Errors-to: tarantool-patches-bounce@freelists.org Reply-To: tarantool-patches@freelists.org List-help: List-unsubscribe: List-software: Ecartis version 1.0.0 List-Id: tarantool-patches List-subscribe: List-owner: List-post: List-archive: To: v.shpilevoy@tarantool.org, tarantool-patches@freelists.org 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