From b8b840fe3099841a14684c1b38cc1c1819061340 Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Fri, 28 May 2021 13:03:16 +0200 Subject: [PATCH 1/2] More verbosity when proxysql detects a broken connection Added function MySQL_Session::detected_broken_connection() that unifies the way broken connections are logged. It also logs username, and last time used. Added also a new macro proxy_error_inline() --- include/MySQL_Session.h | 1 + include/proxysql_debug.h | 11 ++++ lib/MySQL_Session.cpp | 137 +++++++++------------------------------ 3 files changed, 43 insertions(+), 106 deletions(-) diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index 021629c83..c41dff766 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -276,6 +276,7 @@ class MySQL_Session bool known_query_for_locked_on_hostgroup(uint64_t); void unable_to_parse_set_statement(bool *); bool has_any_backend(); + void detected_broken_connection(const char *file, unsigned int line, const char *func, const char *action, MySQL_Connection *myconn, int myerr, const char *message, bool verbose=false); }; #define KILL_QUERY 1 diff --git a/include/proxysql_debug.h b/include/proxysql_debug.h index 56ed7188d..9c67ec4ce 100644 --- a/include/proxysql_debug.h +++ b/include/proxysql_debug.h @@ -40,6 +40,17 @@ extern int gdbg; strftime(__buffer, 25, "%Y-%m-%d %H:%M:%S", &__tm_info); \ proxy_error_func("%s %s:%d:%s(): [ERROR] " fmt, __buffer, __FILE__, __LINE__, __func__ , ## __VA_ARGS__); \ } while(0) + +#define proxy_error_inline(fi, li, fu, fmt, ...) \ + do { \ + time_t __timer; \ + char __buffer[30]; \ + struct tm __tm_info; \ + time(&__timer); \ + localtime_r(&__timer, &__tm_info); \ + strftime(__buffer, 25, "%Y-%m-%d %H:%M:%S", &__tm_info); \ + proxy_error_func("%s %s:%d:%s(): [ERROR] " fmt, __buffer, fi, li, fu , ## __VA_ARGS__); \ + } while(0) /* #else #define proxy_error(fmt, ...) \ diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index d8d9594c8..c90f2f9a4 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -1478,7 +1478,7 @@ int MySQL_Session::handler_again___status_PINGING_SERVER() { MyHGM->p_update_mysql_error_counter(p_mysql_error_type::proxysql, myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, ER_PROXYSQL_PING_TIMEOUT); } else { // rc==-1 int myerr=mysql_errno(myconn->mysql); - proxy_error("Detected a broken connection during ping on (%d,%s,%d) , FD (Conn:%d , MyDS:%d) : %d, %s\n", myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, myds->fd, myds->myconn->fd, myerr, mysql_error(myconn->mysql)); + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "during ping", myconn, myerr, mysql_error(myconn->mysql) , true); MyHGM->p_update_mysql_error_counter(p_mysql_error_type::mysql, myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, myerr); } myds->destroy_MySQL_Connection_From_Pool(false); @@ -1962,18 +1962,7 @@ bool MySQL_Session::handler_again___status_SETTING_INIT_CONNECT(int *_rc) { if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection while setting INIT CONNECT on %s:%d hg %d : %d, %s\n", myconn->parent->address, myconn->parent->port, current_hostgroup, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection while setting INIT CONNECT on %s:%d hg %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - current_hostgroup, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "while setting INIT CONNECT", myconn, myerr, mysql_error(myconn->mysql)); //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) { if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; @@ -2070,18 +2059,7 @@ bool MySQL_Session::handler_again___status_SETTING_LDAP_USER_VARIABLE(int *_rc) if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection while setting LDAP USER VARIABLE on %s:%d hg %d : %d, %s\n", myconn->parent->address, myconn->parent->port, current_hostgroup, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection while setting LDAP USER VARIABLE on %s:%d hg %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - current_hostgroup, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "while setting LDAP USER VARIABLE", myconn, myerr, mysql_error(myconn->mysql)); if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; } @@ -2164,18 +2142,7 @@ bool MySQL_Session::handler_again___status_SETTING_SQL_LOG_BIN(int *_rc) { if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection while setting SQL_LOG_BIN on %s:%d hg %d : %d, %s\n", myconn->parent->address, myconn->parent->port, current_hostgroup, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection while setting SQL_LOG_BIN on %s:%d hg %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - current_hostgroup, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "while setting SQL_LOG_BIN", myconn, myerr, mysql_error(myconn->mysql)); if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; } @@ -2249,17 +2216,7 @@ bool MySQL_Session::handler_again___status_CHANGING_CHARSET(int *_rc) { } bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection during SET NAMES on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection during SET NAMES on %s , %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "during SET NAMES", myconn, myerr, mysql_error(myconn->mysql)); if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; } @@ -2369,19 +2326,9 @@ bool MySQL_Session::handler_again___status_SETTING_GENERIC_VARIABLE(int *_rc, co if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection while setting %s on %s:%d hg %d : %d, %s\n", var_name, myconn->parent->address, myconn->parent->port, current_hostgroup, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection while setting %s on %s:%d hg %d : %d, %s\n", - var_name, - myconn->parent->address, - myconn->parent->port, - current_hostgroup, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + std::string action = "while setting "; + action += var_name; + detected_broken_connection(__FILE__ , __LINE__ , __func__ , action.c_str(), myconn, myerr, mysql_error(myconn->mysql)); //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) { if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; @@ -2491,17 +2438,7 @@ bool MySQL_Session::handler_again___status_SETTING_MULTI_STMT(int *_rc) { if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection during setting MYSQL_OPTION_MULTI_STATEMENTS on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection during setting MYSQL_OPTION_MULTI_STATEMENTS on %s , %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "while setting MYSQL_OPTION_MULTI_STATEMENTS", myconn, myerr, mysql_error(myconn->mysql)); //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) { if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; @@ -2573,17 +2510,7 @@ bool MySQL_Session::handler_again___status_CHANGING_SCHEMA(int *_rc) { if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection during INIT_DB on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection during INIT_DB on %s , %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "during INIT_DB", myconn, myerr, mysql_error(myconn->mysql)); //if ((myds->myconn->reusable==true) && ((myds->myprot.prot_status & SERVER_STATUS_IN_TRANS)==0)) { if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; @@ -2821,17 +2748,7 @@ bool MySQL_Session::handler_again___status_CHANGING_USER_SERVER(int *_rc) { if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection during change user on %s, %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection during change user on %s, %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "during CHANGE_USER", myconn, myerr, mysql_error(myconn->mysql)); if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; } @@ -2931,17 +2848,7 @@ bool MySQL_Session::handler_again___status_CHANGING_AUTOCOMMIT(int *_rc) { if (myerr >= 2000 || myerr == 0) { bool retry_conn=false; // client error, serious - if (myerr != 0) { - proxy_error("Detected a broken connection during SET AUTOCOMMIT on %s , %d : %d, %s\n", myconn->parent->address, myconn->parent->port, myerr, mysql_error(myconn->mysql)); - } else { - proxy_error( - "Detected a broken connection during SET AUTOCOMMIT on %s , %d : %d, %s\n", - myconn->parent->address, - myconn->parent->port, - ER_PROXYSQL_OFFLINE_SRV, - "Detected offline server prior to statement execution" - ); - } + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "during SET AUTOCOMMIT", myconn, myerr, mysql_error(myconn->mysql)); if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { retry_conn=true; } @@ -3954,7 +3861,7 @@ bool MySQL_Session::handler_minus1_ClientLibraryError(MySQL_Data_Stream *myds, i MySQL_Connection *myconn = myds->myconn; bool retry_conn=false; // client error, serious - proxy_error("Detected a broken connection during query on (%d,%s,%d,%lu) , FD (Conn:%d , MyDS:%d) : %d, %s\n", myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, myconn->get_mysql_thread_id(), myds->fd, myds->myconn->fd, myerr, ( *errmsg ? *errmsg : mysql_error(myconn->mysql))); + detected_broken_connection(__FILE__ , __LINE__ , __func__ , "running query", myconn, myerr, mysql_error(myconn->mysql) , true); if (myds->query_retries_on_failure > 0) { myds->query_retries_on_failure--; if ((myds->myconn->reusable==true) && myds->myconn->IsActiveTransaction()==false && myds->myconn->MultiplexDisabled()==false) { @@ -7170,3 +7077,21 @@ void MySQL_Session::handler___status_WAITING_CLIENT_DATA___STATE_SLEEP___MYSQL_C status=WAITING_CLIENT_DATA; l_free(pkt.size,pkt.ptr); } + +void MySQL_Session::detected_broken_connection(const char *file, unsigned int line, const char *func, const char *action, MySQL_Connection *myconn, int myerr, const char *message, bool verbose) { + char *msg = (char *)message; + if (msg == NULL) { + msg = (char *)"Detected offline server prior to statement execution"; + } + if (myerr == 0) { + myerr = ER_PROXYSQL_OFFLINE_SRV; + msg = (char *)"Detected offline server prior to statement execution"; + } + unsigned long long last_used = thread->curtime - myconn->last_time_used; + last_used /= 1000; + if (verbose) { + proxy_error_inline(file, line, func, "Detected a broken connection while %s on (%d,%s,%d,%lu) , FD (Conn:%d , MyDS:%d) , user %s , last_used %llums ago : %d, %s\n" , action , myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, myconn->get_mysql_thread_id() , myconn->myds->fd , myconn->fd , myconn->userinfo->username, last_used, myerr, msg); + } else { + proxy_error_inline(file, line, func, "Detected a broken connection while %s on (%d,%s,%d,%lu) , user %s , last_used %llums ago : %d, %s\n", action, myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, myconn->get_mysql_thread_id(), myconn->userinfo->username, last_used, myerr, msg); + } +} From 6c7503f85f45e802f8d877c0681d7d477b8b71ce Mon Sep 17 00:00:00 2001 From: =?UTF-8?q?Ren=C3=A9=20Canna=C3=B2?= Date: Fri, 28 May 2021 14:05:43 +0200 Subject: [PATCH 2/2] Improve debugging when unable to reach hostgroup When we generate an error "Max connect timeout reached while reaching hostgroup" for the client, now the error log is more verbose. --- include/MySQL_HostGroups_Manager.h | 2 +- include/MySQL_Session.h | 1 + lib/MySQL_HostGroups_Manager.cpp | 37 +++++++++++++++++++----------- lib/MySQL_Session.cpp | 23 +++++++++++++++++++ 4 files changed, 49 insertions(+), 14 deletions(-) diff --git a/include/MySQL_HostGroups_Manager.h b/include/MySQL_HostGroups_Manager.h index aca4a8f20..6350cc5a6 100644 --- a/include/MySQL_HostGroups_Manager.h +++ b/include/MySQL_HostGroups_Manager.h @@ -540,7 +540,7 @@ class MySQL_HostGroups_Manager { void drop_all_idle_connections(); int get_multiple_idle_connections(int, unsigned long long, MySQL_Connection **, int); - SQLite3_result * SQL3_Connection_Pool(bool _reset); + SQLite3_result * SQL3_Connection_Pool(bool _reset, int *hid = NULL); SQLite3_result * SQL3_Free_Connections(); void push_MyConn_to_pool(MySQL_Connection *, bool _lock=true); diff --git a/include/MySQL_Session.h b/include/MySQL_Session.h index c41dff766..6bb0bb1e0 100644 --- a/include/MySQL_Session.h +++ b/include/MySQL_Session.h @@ -277,6 +277,7 @@ class MySQL_Session void unable_to_parse_set_statement(bool *); bool has_any_backend(); void detected_broken_connection(const char *file, unsigned int line, const char *func, const char *action, MySQL_Connection *myconn, int myerr, const char *message, bool verbose=false); + void generate_status_one_hostgroup(int hid, std::string& s); }; #define KILL_QUERY 1 diff --git a/lib/MySQL_HostGroups_Manager.cpp b/lib/MySQL_HostGroups_Manager.cpp index 2bfffb2c5..c82ee0a28 100644 --- a/lib/MySQL_HostGroups_Manager.cpp +++ b/lib/MySQL_HostGroups_Manager.cpp @@ -2779,6 +2779,7 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_ MySrvC *mysrvcCandidates_static[32]; MySrvC **mysrvcCandidates = mysrvcCandidates_static; unsigned int num_candidates = 0; + bool max_connections_reached = false; if (l>32) { mysrvcCandidates = (MySrvC **)malloc(sizeof(MySrvC *)*l); } @@ -2814,6 +2815,8 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_ } } } + } else { + max_connections_reached = true; } } else { if (mysrvc->status==MYSQL_SERVER_STATUS_SHUNNED) { @@ -2911,7 +2914,9 @@ MySrvC *MyHGC::get_random_MySrvC(char * gtid_uuid, uint64_t gtid_trxid, int max_ } if (t - last_hg_log > 1) { // log this at most once per second to avoid spamming the logs last_hg_log = time(NULL); - proxy_error("Hostgroup %u has no servers available! Checking servers shunned for more than %u second%s\n", hid, max_wait_sec, max_wait_sec == 1 ? "" : "s"); + proxy_error("Hostgroup %u has no servers available%s! Checking servers shunned for more than %u second%s\n", hid, + (max_connections_reached ? " or max_connections reached for all servers" : ""), + max_wait_sec, max_wait_sec == 1 ? "" : "s"); } for (j=0; jidx(j); @@ -3776,7 +3781,7 @@ void MySQL_HostGroups_Manager::p_update_connection_pool() { wrunlock(); } -SQLite3_result * MySQL_HostGroups_Manager::SQL3_Connection_Pool(bool _reset) { +SQLite3_result * MySQL_HostGroups_Manager::SQL3_Connection_Pool(bool _reset, int *hid) { const int colnum=14; proxy_debug(PROXY_DEBUG_MYSQL_CONNECTION, 4, "Dumping Connection Pool\n"); SQLite3_result *result=new SQLite3_result(colnum); @@ -3800,17 +3805,23 @@ SQLite3_result * MySQL_HostGroups_Manager::SQL3_Connection_Pool(bool _reset) { MyHGC *myhgc=(MyHGC *)MyHostGroups->index(i); for (j=0; j<(int)myhgc->mysrvs->cnt(); j++) { MySrvC *mysrvc=(MySrvC *)myhgc->mysrvs->servers->index(j); - if (mysrvc->status!=MYSQL_SERVER_STATUS_ONLINE) { - proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 5, "Server %s:%d is not online\n", mysrvc->address, mysrvc->port); - //__sync_fetch_and_sub(&status.server_connections_connected, mysrvc->ConnectionsFree->conns->len); - mysrvc->ConnectionsFree->drop_all_connections(); - } - // drop idle connections if beyond max_connection - while (mysrvc->ConnectionsFree->conns_length() && mysrvc->ConnectionsUsed->conns_length()+mysrvc->ConnectionsFree->conns_length() > mysrvc->max_connections) { - //MySQL_Connection *conn=(MySQL_Connection *)mysrvc->ConnectionsFree->conns->remove_index_fast(0); - MySQL_Connection *conn=mysrvc->ConnectionsFree->remove(0); - delete conn; - //__sync_fetch_and_sub(&status.server_connections_connected, 1); + if (hid == NULL) { + if (mysrvc->status!=MYSQL_SERVER_STATUS_ONLINE) { + proxy_debug(PROXY_DEBUG_MYSQL_CONNPOOL, 5, "Server %s:%d is not online\n", mysrvc->address, mysrvc->port); + //__sync_fetch_and_sub(&status.server_connections_connected, mysrvc->ConnectionsFree->conns->len); + mysrvc->ConnectionsFree->drop_all_connections(); + } + // drop idle connections if beyond max_connection + while (mysrvc->ConnectionsFree->conns_length() && mysrvc->ConnectionsUsed->conns_length()+mysrvc->ConnectionsFree->conns_length() > mysrvc->max_connections) { + //MySQL_Connection *conn=(MySQL_Connection *)mysrvc->ConnectionsFree->conns->remove_index_fast(0); + MySQL_Connection *conn=mysrvc->ConnectionsFree->remove(0); + delete conn; + //__sync_fetch_and_sub(&status.server_connections_connected, 1); + } + } else { + if (*hid != (int)myhgc->hid) { + continue; + } } char buf[1024]; char **pta=(char **)malloc(sizeof(char *)*colnum); diff --git a/lib/MySQL_Session.cpp b/lib/MySQL_Session.cpp index c90f2f9a4..5cb49d2f5 100644 --- a/lib/MySQL_Session.cpp +++ b/lib/MySQL_Session.cpp @@ -2564,6 +2564,9 @@ bool MySQL_Session::handler_again___status_CONNECTING_SERVER(int *_rc) { } client_myds->myprot.generate_pkt_ERR(true,NULL,NULL,1,9001,(char *)"HY000",buf, true); RequestEnd(mybe->server_myds); + std::string errmsg; + generate_status_one_hostgroup(current_hostgroup, errmsg); + proxy_error("%s . HG status: %s\n", buf, errmsg.c_str()); //enum session_status st; while (previous_status.size()) { previous_status.top(); @@ -7095,3 +7098,23 @@ void MySQL_Session::detected_broken_connection(const char *file, unsigned int li proxy_error_inline(file, line, func, "Detected a broken connection while %s on (%d,%s,%d,%lu) , user %s , last_used %llums ago : %d, %s\n", action, myconn->parent->myhgc->hid, myconn->parent->address, myconn->parent->port, myconn->get_mysql_thread_id(), myconn->userinfo->username, last_used, myerr, msg); } } + +void MySQL_Session::generate_status_one_hostgroup(int hid, std::string& s) { + SQLite3_result *resultset = MyHGM->SQL3_Connection_Pool(false, &hid); + json j_res; + if (resultset->rows_count) { + for (std::vector::iterator it = resultset->rows.begin() ; it != resultset->rows.end(); ++it) { + SQLite3_row *r=*it; + json j; // one json for each row + for (int i=0; icolumns; i++) { + // using the format j["name"] == "value" + j[resultset->column_definition[i]->name] = ( r->fields[i] ? r->fields[i] : "(null)" ); + } + j_res.push_back(j); // the row json is added to the final json + } + } else { + j_res=json::array(); + } + s = j_res.dump(); + delete resultset; +}