From 8ea3eb9c988caef1df037190860ea063ce145bdd Mon Sep 17 00:00:00 2001 From: Aki Tuomi Date: Sat, 12 Sep 2015 20:38:26 +0300 Subject: [PATCH] Implement multi result set support in gMySQL --- modules/gmysqlbackend/smysql.cc | 48 ++++++++++++++++++++++++++++----- 1 file changed, 41 insertions(+), 7 deletions(-) diff --git a/modules/gmysqlbackend/smysql.cc b/modules/gmysqlbackend/smysql.cc index 8d981ef55..6d391a047 100644 --- a/modules/gmysqlbackend/smysql.cc +++ b/modules/gmysqlbackend/smysql.cc @@ -144,18 +144,21 @@ public: throw SSqlException("Could not execute mysql statement: " + d_query + string(": ") + error); } + // MySQL documentation says you can call this safely for all queries + if ((err = mysql_stmt_store_result(d_stmt))) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not store mysql statement: " + d_query + string(": ") + error); + } + if ((d_fnum = static_cast(mysql_stmt_field_count(d_stmt)))>0) { // prepare for result - if ((err = mysql_stmt_store_result(d_stmt))) { - string error(mysql_stmt_error(d_stmt)); - throw SSqlException("Could not store mysql statement: " + d_query + string(": ") + error); - } d_resnum = mysql_stmt_num_rows(d_stmt); if (d_resnum>0 && d_res_bind == NULL) { + MYSQL_RES* meta = mysql_stmt_result_metadata(d_stmt); + d_fnum = static_cast(mysql_num_fields(meta)); // ensure correct number of fields d_res_bind = new MYSQL_BIND[d_fnum]; memset(d_res_bind, 0, sizeof(MYSQL_BIND)*d_fnum); - MYSQL_RES* meta = mysql_stmt_result_metadata(d_stmt); MYSQL_FIELD* fields = mysql_fetch_fields(meta); for(int i = 0; i < d_fnum; i++) { @@ -187,7 +190,7 @@ public: SSqlStatement* nextRow(row_t& row) { int err; row.clear(); - if (d_residx >= d_resnum) return this; + if (!hasNextRow()) return this; if ((err =mysql_stmt_fetch(d_stmt))) { if (err != MYSQL_DATA_TRUNCATED) { @@ -211,6 +214,29 @@ public: } d_residx++; +#if MYSQL_VERSION_ID >= 50500 + if (d_residx >= d_resnum) { + mysql_stmt_free_result(d_stmt); + while(!mysql_stmt_next_result(d_stmt)) { + if ((err = mysql_stmt_store_result(d_stmt))) { + string error(mysql_stmt_error(d_stmt)); + throw PDNSException("Could not store mysql statement: " + d_query + string(": ") + error); + } + d_resnum = mysql_stmt_num_rows(d_stmt); + // XXX: For some reason mysql_stmt_result_metadata returns NULL here, so we cannot + // ensure row field count matches first result set. + if (d_resnum>0) { // ignore empty result set + if ((err = mysql_stmt_bind_result(d_stmt, d_res_bind))) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not bind parameters to mysql statement: " + d_query + string(": ") + error); + } + d_residx = 0; + break; + } + mysql_stmt_free_result(d_stmt); + } + } +#endif return this; } @@ -229,7 +255,15 @@ public: SSqlStatement* reset() { if (!d_stmt) return this; - + int err; + mysql_stmt_free_result(d_stmt); + while((err = mysql_stmt_next_result(d_stmt)) == 0) { + mysql_stmt_free_result(d_stmt); + } + if (err>0) { + string error(mysql_stmt_error(d_stmt)); + throw SSqlException("Could not get next result from mysql statement: " + d_query + string(": ") + error); + } mysql_stmt_reset(d_stmt); if (d_req_bind) { for(int i=0;i