diff options
-rw-r--r-- | ext/mysqlnd/mysqlnd.c | 80 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_auth.c | 2 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_driver.c | 5 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_priv.h | 5 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_ps.c | 25 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_result.c | 21 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_structs.h | 25 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 102 |
8 files changed, 203 insertions, 62 deletions
diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index 8dff5505cd..3d2afe7779 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -44,6 +44,42 @@ PHPAPI const char * const mysqlnd_out_of_memory = "Out of memory"; PHPAPI MYSQLND_STATS *mysqlnd_global_stats = NULL; +/* {{{ mysqlnd_upsert_status::reset */ +void +MYSQLND_METHOD(mysqlnd_upsert_status, reset)(MYSQLND_UPSERT_STATUS * const upsert_status) +{ + upsert_status->warning_count = 0; + upsert_status->server_status = 0; + upsert_status->affected_rows = 0; + upsert_status->last_insert_id = 0; +} +/* }}} */ + + +/* {{{ mysqlnd_upsert_status::set_affected_rows_to_error */ +void +MYSQLND_METHOD(mysqlnd_upsert_status, set_affected_rows_to_error)(MYSQLND_UPSERT_STATUS * upsert_status) +{ + upsert_status->affected_rows = (uint64_t) ~0; +} +/* }}} */ + + +MYSQLND_CLASS_METHODS_START(mysqlnd_upsert_status) + MYSQLND_METHOD(mysqlnd_upsert_status, reset), + MYSQLND_METHOD(mysqlnd_upsert_status, set_affected_rows_to_error), +MYSQLND_CLASS_METHODS_END; + + +/* {{{ mysqlnd_upsert_status_init */ +void +mysqlnd_upsert_status_init(MYSQLND_UPSERT_STATUS * const upsert_status) +{ + upsert_status->m = &MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_upsert_status); +} +/* }}} */ + + /* {{{ mysqlnd_conn_data::free_options */ static void MYSQLND_METHOD(mysqlnd_conn_data, free_options)(MYSQLND_CONN_DATA * conn) @@ -190,9 +226,12 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, dtor)(MYSQLND_CONN_DATA * conn) /* {{{ mysqlnd_conn_data::send_command_handle_response */ static enum_func_status -MYSQLND_METHOD(mysqlnd_conn_data, send_command_handle_response)(MYSQLND_CONN_DATA * conn, enum mysqlnd_packet_type ok_packet, - zend_bool silent, enum php_mysqlnd_server_command command, - zend_bool ignore_upsert_status) +MYSQLND_METHOD(mysqlnd_conn_data, send_command_handle_response)( + MYSQLND_CONN_DATA * const conn, + const enum mysqlnd_packet_type ok_packet, + const zend_bool silent, + const enum php_mysqlnd_server_command command, + const zend_bool ignore_upsert_status) { enum_func_status ret = FAIL; @@ -228,14 +267,14 @@ MYSQLND_METHOD(mysqlnd_conn_data, send_command_handle_response)(MYSQLND_CONN_DAT safe to unconditionally turn off the flag here. */ conn->upsert_status->server_status &= ~SERVER_MORE_RESULTS_EXISTS; - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); } else { SET_NEW_MESSAGE(conn->last_message, conn->last_message_len, ok_response->message, ok_response->message_len, conn->persistent); if (!ignore_upsert_status) { - memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); + UPSERT_STATUS_RESET(conn->upsert_status); conn->upsert_status->warning_count = ok_response->warning_count; conn->upsert_status->server_status = ok_response->server_status; conn->upsert_status->affected_rows = ok_response->affected_rows; @@ -263,7 +302,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, send_command_handle_response)(MYSQLND_CONN_DAT } else if (0xFF == ok_response->field_count) { /* The server signalled error. Set the error */ SET_CLIENT_ERROR(*conn->error_info, ok_response->error_no, ok_response->sqlstate, ok_response->error); - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); } else if (0xFE != ok_response->field_count) { SET_CLIENT_ERROR(*conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, "Malformed packet"); if (!silent) { @@ -288,10 +327,14 @@ MYSQLND_METHOD(mysqlnd_conn_data, send_command_handle_response)(MYSQLND_CONN_DAT /* }}} */ -/* {{{ mysqlnd_conn_data::simple_command_send_request */ +/* {{{ mysqlnd_conn_data::send_command_do_request */ static enum_func_status -MYSQLND_METHOD(mysqlnd_conn_data, send_command_do_request)(MYSQLND_CONN_DATA * conn, enum php_mysqlnd_server_command command, - const zend_uchar * const arg, size_t arg_len, zend_bool silent, zend_bool ignore_upsert_status) +MYSQLND_METHOD(mysqlnd_conn_data, send_command_do_request)( + MYSQLND_CONN_DATA * const conn, + const enum php_mysqlnd_server_command command, + const zend_uchar * const arg, const size_t arg_len, + const zend_bool silent, + const zend_bool ignore_upsert_status) { enum_func_status ret = PASS; MYSQLND_PACKET_COMMAND * cmd_packet; @@ -314,7 +357,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, send_command_do_request)(MYSQLND_CONN_DATA * c DBG_RETURN(FAIL); } - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); SET_EMPTY_ERROR(*conn->error_info); cmd_packet = conn->payload_decoder_factory->m.get_command_packet(conn->payload_decoder_factory, FALSE); @@ -747,7 +790,8 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect_handshake)(MYSQLND_CONN_DATA * conn, { goto err; } - memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); + + UPSERT_STATUS_RESET(conn->upsert_status); conn->upsert_status->warning_count = 0; conn->upsert_status->server_status = greet_packet->server_status; conn->upsert_status->affected_rows = 0; @@ -791,7 +835,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, connect)(MYSQLND_CONN_DATA * conn, local_tx_started = TRUE; SET_EMPTY_ERROR(*conn->error_info); - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); DBG_INF_FMT("host=%s user=%s db=%s port=%u flags=%u persistent=%u state=%u", host?host:"", user?user:"", db?db:"", port, mysql_flags, @@ -1595,7 +1639,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, select_db)(MYSQLND_CONN_DATA * const conn, con The server sends 0 but libmysql doesn't read it and has established a protocol of giving back -1. Thus we have to follow it :( */ - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); if (ret == PASS) { if (conn->connect_or_select_db) { mnd_pefree(conn->connect_or_select_db, conn->persistent); @@ -1635,7 +1679,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, ping)(MYSQLND_CONN_DATA * const conn) The server sends 0 but libmysql doesn't read it and has established a protocol of giving back -1. Thus we have to follow it :( */ - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); conn->m->local_tx_end(conn, this_func, ret); } @@ -1711,7 +1755,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, kill)(MYSQLND_CONN_DATA * conn, unsigned int p The server sends 0 but libmysql doesn't read it and has established a protocol of giving back -1. Thus we have to follow it :( */ - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); } else if (PASS == ret) { CONN_SET_STATE(conn, CONN_QUIT_SENT); conn->m->send_close(conn); @@ -2095,7 +2139,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, next_result)(MYSQLND_CONN_DATA * const conn) } SET_EMPTY_ERROR(*conn->error_info); - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); /* We are sure that there is a result set, since conn->state is set accordingly in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered() @@ -2202,7 +2246,7 @@ MYSQLND_METHOD(mysqlnd_conn_data, change_user)(MYSQLND_CONN_DATA * const conn, } SET_EMPTY_ERROR(*conn->error_info); - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); if (!user) { user = ""; @@ -2961,7 +3005,7 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn_data) MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, get_state), MYSQLND_METHOD_PRIVATE(mysqlnd_conn_data, set_state), - MYSQLND_METHOD(mysqlnd_conn_data, send_command_do_request), +// MYSQLND_METHOD(mysqlnd_conn_data, send_command_do_request), MYSQLND_METHOD(mysqlnd_conn_data, send_command_handle_response), MYSQLND_METHOD(mysqlnd_conn_data, restart_psession), MYSQLND_METHOD(mysqlnd_conn_data, end_psession), diff --git a/ext/mysqlnd/mysqlnd_auth.c b/ext/mysqlnd/mysqlnd_auth.c index 9512e12728..7a8f848f6d 100644 --- a/ext/mysqlnd/mysqlnd_auth.c +++ b/ext/mysqlnd/mysqlnd_auth.c @@ -289,7 +289,7 @@ mysqlnd_auth_change_user(MYSQLND_CONN_DATA * const conn, mnd_pefree(conn->last_message, conn->persistent); conn->last_message = NULL; } - memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); + UPSERT_STATUS_RESET(conn->upsert_status); /* set charset for old servers */ if (conn->m->get_server_version(conn) < 50123) { ret = conn->m->set_charset(conn, old_cs->name); diff --git a/ext/mysqlnd/mysqlnd_driver.c b/ext/mysqlnd/mysqlnd_driver.c index 00e38adde2..8c11093826 100644 --- a/ext/mysqlnd/mysqlnd_driver.c +++ b/ext/mysqlnd/mysqlnd_driver.c @@ -135,7 +135,10 @@ MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(struct st_mysqlnd_object_ data->error_info = &(data->error_info_impl); data->options = &(data->options_impl); + + mysqlnd_upsert_status_init(&data->upsert_status_impl); data->upsert_status = &(data->upsert_status_impl); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(data->upsert_status); data->persistent = persistent; data->m = mysqlnd_conn_data_get_methods(); @@ -151,7 +154,6 @@ MYSQLND_METHOD(mysqlnd_object_factory, get_connection)(struct st_mysqlnd_object_ zend_llist_init(data->error_info->error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t)mysqlnd_error_list_pdtor, persistent); mysqlnd_stats_init(&data->stats, STAT_LAST, persistent); - SET_ERROR_AFF_ROWS(data); data->net = mysqlnd_net_init(persistent, data->stats, data->error_info); data->payload_decoder_factory = mysqlnd_protocol_payload_decoder_factory_init(data, persistent); @@ -219,6 +221,7 @@ MYSQLND_METHOD(mysqlnd_object_factory, get_prepared_statement)(MYSQLND_CONN_DATA } stmt->persistent = persistent; stmt->error_info = &(stmt->error_info_impl); + mysqlnd_upsert_status_init(&stmt->upsert_status_impl); stmt->upsert_status = &(stmt->upsert_status_impl); stmt->state = MYSQLND_STMT_INITTED; stmt->execute_cmd_buffer.length = 4096; diff --git a/ext/mysqlnd/mysqlnd_priv.h b/ext/mysqlnd/mysqlnd_priv.h index fdd663276f..abd475f63a 100644 --- a/ext/mysqlnd/mysqlnd_priv.h +++ b/ext/mysqlnd/mysqlnd_priv.h @@ -76,8 +76,10 @@ #define MAX_CHARSET_LEN 32 +void mysqlnd_upsert_status_init(MYSQLND_UPSERT_STATUS * const upsert_status); -#define SET_ERROR_AFF_ROWS(s) (s)->upsert_status->affected_rows = (uint64_t) ~0 +#define UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(status) (status)->m->set_affected_rows_to_error((status)) +#define UPSERT_STATUS_RESET(status) (status)->m->reset((status)) /* Error handling */ #define SET_NEW_MESSAGE(buf, buf_len, message, len, persistent) \ @@ -181,6 +183,7 @@ PHPAPI extern MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(mysqlnd_result_unbuffered) PHPAPI extern MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(mysqlnd_result_buffered); PHPAPI extern MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(mysqlnd_protocol_payload_decoder_factory); PHPAPI extern MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(mysqlnd_net); +PHPAPI extern MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(mysqlnd_upsert_status); enum_func_status mysqlnd_handle_local_infile(MYSQLND_CONN_DATA * conn, const char * filename, zend_bool * is_warning); diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 8fa22544dc..d7bb50b4a7 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -358,6 +358,11 @@ mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s) if (stmt->result) { stmt->result->m.free_result_contents(stmt->result); mnd_efree(stmt->result); + /* XXX: This will crash, because we will null also the methods. + But seems it happens in extreme cases or doesn't. Should be fixed by exporting a function + (from mysqlnd_driver.c?) to do the reset. + This is done also in mysqlnd_result.c + */ memset(stmt, 0, sizeof(MYSQLND_STMT_DATA)); stmt->state = MYSQLND_STMT_INITTED; } @@ -389,8 +394,8 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const DBG_INF_FMT("stmt=%lu", stmt->stmt_id); DBG_INF_FMT("query=%s", query); - SET_ERROR_AFF_ROWS(stmt); - SET_ERROR_AFF_ROWS(stmt->conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(stmt->upsert_status); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(stmt->conn->upsert_status); SET_EMPTY_ERROR(*stmt->error_info); SET_EMPTY_ERROR(*stmt->conn->error_info); @@ -516,7 +521,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s, enum_mysqlnd_parse_e ret = stmt->conn->m->query_read_result_set_header(stmt->conn, s); if (ret == FAIL) { COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info); - memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status)); + UPSERT_STATUS_RESET(stmt->upsert_status); stmt->upsert_status->affected_rows = conn->upsert_status->affected_rows; if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) { /* close the statement here, the connection has been closed */ @@ -650,8 +655,8 @@ MYSQLND_METHOD(mysqlnd_stmt, send_execute)(MYSQLND_STMT * const s, enum_mysqlnd_ conn = stmt->conn; DBG_INF_FMT("stmt=%lu", stmt->stmt_id); - SET_ERROR_AFF_ROWS(stmt); - SET_ERROR_AFF_ROWS(stmt->conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(stmt->upsert_status); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(stmt->conn->upsert_status); if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) { /* @@ -733,7 +738,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_execute)(MYSQLND_STMT * const s, enum_mysqlnd_ } ret = s->m->generate_execute_request(s, &request, &request_len, &free_request); if (ret == PASS) { - const MYSQLND_CSTRING payload = {request, request_len}; + const MYSQLND_CSTRING payload = {(const char*) request, request_len}; struct st_mysqlnd_protocol_command * command = stmt->conn->command_factory(COM_STMT_EXECUTE, stmt->conn, payload); ret = FAIL; if (command) { @@ -970,7 +975,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned i DBG_INF("EOF"); /* Mark the connection as usable again */ result->unbuf->eof_reached = TRUE; - memset(result->conn->upsert_status, 0, sizeof(*result->conn->upsert_status)); + UPSERT_STATUS_RESET(result->conn->upsert_status); result->conn->upsert_status->warning_count = row_packet->warning_count; result->conn->upsert_status->server_status = row_packet->server_status; /* @@ -1070,7 +1075,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f int4store(buf + MYSQLND_STMT_ID_LENGTH, 1); /* for now fetch only one row */ { - const MYSQLND_CSTRING payload = {buf, sizeof(buf)}; + const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)}; struct st_mysqlnd_protocol_command * command = stmt->conn->command_factory(COM_STMT_FETCH, stmt->conn, payload); ret = FAIL; if (command) { @@ -1096,7 +1101,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int f row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE; - memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status)); + UPSERT_STATUS_RESET(stmt->upsert_status); if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) { const MYSQLND_RES_METADATA * const meta = result->meta; unsigned int i, field_count = result->field_count; @@ -1416,7 +1421,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned in /* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/ { - const MYSQLND_CSTRING payload = {cmd_buf, packet_len}; + const MYSQLND_CSTRING payload = {(const char *) cmd_buf, packet_len}; struct st_mysqlnd_protocol_command * command = stmt->conn->command_factory(COM_STMT_SEND_LONG_DATA, stmt->conn, payload); ret = FAIL; if (command) { diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index bee0a1da88..b06b02f22d 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -418,7 +418,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) break; } - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); if (FAIL == (ret = PACKET_READ(rset_header, conn))) { php_error_docref(NULL, E_WARNING, "Error reading result set's header"); @@ -465,7 +465,7 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) DBG_INF("UPSERT"); conn->last_query_type = QUERY_UPSERT; conn->field_count = rset_header->field_count; - memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); + UPSERT_STATUS_RESET(conn->upsert_status); conn->upsert_status->warning_count = rset_header->warning_count; conn->upsert_status->server_status = rset_header->server_status; conn->upsert_status->affected_rows = rset_header->affected_rows; @@ -490,9 +490,9 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) SET_EMPTY_MESSAGE(conn->last_message, conn->last_message_len, conn->persistent); MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_RSET_QUERY); - memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); + UPSERT_STATUS_RESET(conn->upsert_status); /* restore after zeroing */ - SET_ERROR_AFF_ROWS(conn); + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); conn->last_query_type = QUERY_SELECT; CONN_SET_STATE(conn, CONN_FETCHING_DATA); @@ -556,6 +556,11 @@ mysqlnd_query_read_result_set_header(MYSQLND_CONN_DATA * conn, MYSQLND_STMT * s) conn->current_result = NULL; } else { stmt->result = NULL; + /* XXX: This will crash, because we will null also the methods. + But seems it happens in extreme cases or doesn't. Should be fixed by exporting a function + (from mysqlnd_driver.c?) to do the reset. + This is done also in mysqlnd_ps.c + */ memset(stmt, 0, sizeof(*stmt)); stmt->state = MYSQLND_STMT_INITTED; } @@ -772,7 +777,8 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row_c)(MYSQLND_RES * result, voi /* Mark the connection as usable again */ DBG_INF_FMT("warnings=%u server_status=%u", row_packet->warning_count, row_packet->server_status); result->unbuf->eof_reached = TRUE; - memset(result->conn->upsert_status, 0, sizeof(*result->conn->upsert_status)); + + UPSERT_STATUS_RESET(result->conn->upsert_status); result->conn->upsert_status->warning_count = row_packet->warning_count; result->conn->upsert_status->server_status = row_packet->server_status; /* @@ -898,7 +904,8 @@ MYSQLND_METHOD(mysqlnd_result_unbuffered, fetch_row)(MYSQLND_RES * result, void /* Mark the connection as usable again */ DBG_INF_FMT("warnings=%u server_status=%u", row_packet->warning_count, row_packet->server_status); result->unbuf->eof_reached = TRUE; - memset(result->conn->upsert_status, 0, sizeof(*result->conn->upsert_status)); + + UPSERT_STATUS_RESET(result->conn->upsert_status); result->conn->upsert_status->warning_count = row_packet->warning_count; result->conn->upsert_status->server_status = row_packet->server_status; /* @@ -1354,7 +1361,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND_CONN_DATA * const c /* Finally clean */ if (row_packet->eof) { - memset(conn->upsert_status, 0, sizeof(*conn->upsert_status)); + UPSERT_STATUS_RESET(conn->upsert_status); conn->upsert_status->warning_count = row_packet->warning_count; conn->upsert_status->server_status = row_packet->server_status; } diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 959c9a2cb8..dae967e52c 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -28,7 +28,8 @@ #define MYSQLND_TYPEDEFED_METHODS #define MYSQLND_CLASS_METHOD_TABLE_NAME(class) mysqlnd_##class##_methods -#define MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(class) struct st_##class##_methods MYSQLND_CLASS_METHOD_TABLE_NAME(class) +#define MYSQLND_CLASS_METHOD_TABLE_NAME_DECL(class) struct st_##class##_methods +#define MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(class) MYSQLND_CLASS_METHOD_TABLE_NAME_DECL(class) MYSQLND_CLASS_METHOD_TABLE_NAME(class) #define MYSQLND_CLASS_METHODS_START(class) MYSQLND_CLASS_METHOD_TABLE_NAME_FORWARD(class) = { #define MYSQLND_CLASS_METHODS_END } @@ -98,13 +99,25 @@ typedef struct st_mysqlnd_field } MYSQLND_FIELD; -typedef struct st_mysqlnd_upsert_result +typedef struct st_mysqlnd_upsert_status MYSQLND_UPSERT_STATUS; +typedef void (*func_mysqlnd_upsert_status__reset)(MYSQLND_UPSERT_STATUS * const upsert_status); +typedef void (*func_mysqlnd_upsert_status__set_affected_rows_to_error)(MYSQLND_UPSERT_STATUS * const upsert_status); + +MYSQLND_CLASS_METHOD_TABLE_NAME_DECL(mysqlnd_upsert_status) +{ + func_mysqlnd_upsert_status__reset reset; + func_mysqlnd_upsert_status__set_affected_rows_to_error set_affected_rows_to_error; +}; + +struct st_mysqlnd_upsert_status { unsigned int warning_count; unsigned int server_status; uint64_t affected_rows; uint64_t last_insert_id; -} MYSQLND_UPSERT_STATUS; + + struct st_mysqlnd_upsert_status_methods *m; +}; typedef struct st_mysqlnd_error_info @@ -476,8 +489,8 @@ typedef enum_func_status (*func_mysqlnd_conn_data__free_reference)(MYSQLND_CONN_ typedef enum mysqlnd_connection_state (*func_mysqlnd_conn_data__get_state)(const MYSQLND_CONN_DATA * const conn); typedef void (*func_mysqlnd_conn_data__set_state)(MYSQLND_CONN_DATA * const conn, enum mysqlnd_connection_state new_state); -typedef enum_func_status (*func_mysqlnd_conn_data__send_command_do_request)(MYSQLND_CONN_DATA * conn, enum php_mysqlnd_server_command command, const zend_uchar * const arg, size_t arg_len, zend_bool silent, zend_bool ignore_upsert_status); -typedef enum_func_status (*func_mysqlnd_conn_data__send_command_handle_response)(MYSQLND_CONN_DATA * conn, enum mysqlnd_packet_type ok_packet, zend_bool silent, enum php_mysqlnd_server_command command, zend_bool ignore_upsert_status); +typedef enum_func_status (*func_mysqlnd_conn_data__send_command_do_request)(MYSQLND_CONN_DATA * const conn, const enum php_mysqlnd_server_command command, const zend_uchar * const arg, const size_t arg_len, const zend_bool silent, const zend_bool ignore_upsert_status); +typedef enum_func_status (*func_mysqlnd_conn_data__send_command_handle_response)(MYSQLND_CONN_DATA * const conn, const enum mysqlnd_packet_type ok_packet, const zend_bool silent, const enum php_mysqlnd_server_command command, const zend_bool ignore_upsert_status); typedef enum_func_status (*func_mysqlnd_conn_data__restart_psession)(MYSQLND_CONN_DATA * conn); typedef enum_func_status (*func_mysqlnd_conn_data__end_psession)(MYSQLND_CONN_DATA * conn); @@ -571,7 +584,7 @@ struct st_mysqlnd_conn_data_methods func_mysqlnd_conn_data__get_state get_state; func_mysqlnd_conn_data__set_state set_state; - func_mysqlnd_conn_data__send_command_do_request send_command_do_request; +// func_mysqlnd_conn_data__send_command_do_request send_command_do_request; func_mysqlnd_conn_data__send_command_handle_response send_command_handle_response; func_mysqlnd_conn_data__restart_psession restart_psession; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 25ed39fd4f..da4bde11ce 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -2660,6 +2660,72 @@ mysqlnd_protocol_payload_decoder_factory_free(MYSQLND_PROTOCOL_PAYLOAD_DECODER_F +/* {{{ mysqlnd_conn_data::send_command_do_request */ +static enum_func_status +send_command_do_request( + MYSQLND_CONN_DATA * const conn, + const enum php_mysqlnd_server_command command, + const zend_uchar * const arg, const size_t arg_len, + const zend_bool silent, + const zend_bool ignore_upsert_status) +{ + enum_func_status ret = PASS; + MYSQLND_PACKET_COMMAND * cmd_packet = NULL; + enum mysqlnd_connection_state conn_state = CONN_GET_STATE(conn); + MYSQLND_ERROR_INFO * error_info = conn->error_info; + DBG_ENTER("mysqlnd_conn_data::send_command_do_request"); + DBG_INF_FMT("command=%s silent=%u", mysqlnd_command_to_text[command], silent); + DBG_INF_FMT("conn->server_status=%u", conn->upsert_status->server_status); + DBG_INF_FMT("sending %u bytes", arg_len + 1); /* + 1 is for the command */ + + switch (conn_state) { + case CONN_READY: + break; + case CONN_QUIT_SENT: + SET_CLIENT_ERROR(*error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); + DBG_ERR("Server is gone"); + DBG_RETURN(FAIL); + default: + SET_CLIENT_ERROR(*error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync); + DBG_ERR_FMT("Command out of sync. State=%u", conn_state); + DBG_RETURN(FAIL); + } + + UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(conn->upsert_status); + SET_EMPTY_ERROR(*conn->error_info); + + cmd_packet = conn->payload_decoder_factory->m.get_command_packet(conn->payload_decoder_factory, FALSE); + if (!cmd_packet) { + SET_OOM_ERROR(*conn->error_info); + DBG_RETURN(FAIL); + } + + cmd_packet->command = command; + if (arg && arg_len) { + cmd_packet->argument = arg; + cmd_packet->arg_len = arg_len; + } + + MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_COM_QUIT + command - 1 /* because of COM_SLEEP */ ); + + if (! PACKET_WRITE(cmd_packet, conn)) { + if (!silent) { + DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]); + php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid()); + } + CONN_SET_STATE(conn, CONN_QUIT_SENT); + conn->m->send_close(conn); + DBG_ERR("Server is gone"); + ret = FAIL; + } + PACKET_FREE(cmd_packet); + DBG_RETURN(ret); +} +/* }}} */ + + + + struct st_mysqlnd_protocol_no_params_command { @@ -2706,7 +2772,7 @@ mysqlnd_com_set_option_run(void *cmd) DBG_ENTER("mysqlnd_com_set_option_run"); int2store(buffer, (unsigned int) option); - ret = conn->m->send_command_do_request(conn, COM_SET_OPTION, buffer, sizeof(buffer), FALSE, TRUE); + ret = send_command_do_request(conn, COM_SET_OPTION, buffer, sizeof(buffer), FALSE, TRUE); if (PASS == ret) { ret = conn->m->send_command_handle_response(conn, PROT_EOF_PACKET, FALSE, COM_SET_OPTION, TRUE); } @@ -2747,7 +2813,7 @@ mysqlnd_com_debug_run(void *cmd) DBG_ENTER("mysqlnd_com_debug_run"); - ret = conn->m->send_command_do_request(conn, COM_DEBUG, NULL, 0, FALSE, TRUE); + ret = send_command_do_request(conn, COM_DEBUG, NULL, 0, FALSE, TRUE); if (PASS == ret) { ret = conn->m->send_command_handle_response(conn, PROT_EOF_PACKET, COM_DEBUG, COM_DEBUG, TRUE); } @@ -2798,7 +2864,7 @@ mysqlnd_com_init_db_run(void *cmd) DBG_ENTER("mysqlnd_com_init_db_run"); - ret = conn->m->send_command_do_request(conn, COM_INIT_DB, (zend_uchar*) command->context.db.s, command->context.db.l, FALSE, TRUE); + ret = send_command_do_request(conn, COM_INIT_DB, (zend_uchar*) command->context.db.s, command->context.db.l, FALSE, TRUE); if (PASS == ret) { ret = conn->m->send_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_INIT_DB, TRUE); } @@ -2839,7 +2905,7 @@ mysqlnd_com_ping_run(void *cmd) DBG_ENTER("mysqlnd_com_ping_run"); - ret = conn->m->send_command_do_request(conn, COM_PING, NULL, 0, TRUE, TRUE); + ret = send_command_do_request(conn, COM_PING, NULL, 0, TRUE, TRUE); if (PASS == ret) { ret = conn->m->send_command_handle_response(conn, PROT_OK_PACKET, TRUE, COM_PING, TRUE); } @@ -2906,7 +2972,7 @@ mysqlnd_com_field_list_run(void *cmd) *p++ = '\0'; } - ret = conn->m->send_command_do_request(conn, COM_FIELD_LIST, buff, p - buff, FALSE, TRUE); + ret = send_command_do_request(conn, COM_FIELD_LIST, buff, p - buff, FALSE, TRUE); DBG_RETURN(ret); } @@ -2945,7 +3011,7 @@ mysqlnd_com_statistics_run(void *cmd) DBG_ENTER("mysqlnd_com_statistics_run"); - ret = conn->m->send_command_do_request(conn, COM_STATISTICS, NULL, 0, FALSE, TRUE); + ret = send_command_do_request(conn, COM_STATISTICS, NULL, 0, FALSE, TRUE); DBG_RETURN(ret); } @@ -2995,7 +3061,7 @@ mysqlnd_com_process_kill_run(void *cmd) DBG_ENTER("mysqlnd_com_process_kill_run"); int4store(buff, command->context.process_id); - ret = conn->m->send_command_do_request(conn, COM_PROCESS_KILL, buff, 4, FALSE, TRUE); + ret = send_command_do_request(conn, COM_PROCESS_KILL, buff, 4, FALSE, TRUE); if (PASS == ret && command->context.read_response) { ret = conn->m->send_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_PROCESS_KILL, TRUE); } @@ -3049,7 +3115,7 @@ mysqlnd_com_refresh_run(void *cmd) DBG_ENTER("mysqlnd_com_refresh_run"); int1store(bits, command->context.options); - ret = conn->m->send_command_do_request(conn, COM_REFRESH, bits, 1, FALSE, TRUE); + ret = send_command_do_request(conn, COM_REFRESH, bits, 1, FALSE, TRUE); if (PASS == ret) { ret = conn->m->send_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_REFRESH, TRUE); } @@ -3103,7 +3169,7 @@ mysqlnd_com_shutdown_run(void *cmd) DBG_ENTER("mysqlnd_com_shutdown_run"); int1store(bits, command->context.level); - ret = conn->m->send_command_do_request(conn, COM_SHUTDOWN, bits, 1, FALSE, TRUE); + ret = send_command_do_request(conn, COM_SHUTDOWN, bits, 1, FALSE, TRUE); if (PASS == ret) { ret = conn->m->send_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_SHUTDOWN, TRUE); } @@ -3154,7 +3220,7 @@ mysqlnd_com_quit_run(void *cmd) DBG_ENTER("mysqlnd_com_quit_run"); - ret = conn->m->send_command_do_request(conn, COM_QUIT, NULL, 0, TRUE, TRUE); + ret = send_command_do_request(conn, COM_QUIT, NULL, 0, TRUE, TRUE); DBG_RETURN(ret); } @@ -3201,7 +3267,7 @@ mysqlnd_com_query_run(void *cmd) DBG_ENTER("mysqlnd_com_query_run"); - ret = conn->m->send_command_do_request(conn, COM_QUERY, (zend_uchar*) command->context.query.s, command->context.query.l, FALSE, FALSE); + ret = send_command_do_request(conn, COM_QUERY, (zend_uchar*) command->context.query.s, command->context.query.l, FALSE, FALSE); if (PASS == ret) { CONN_SET_STATE(conn, CONN_QUERY_SENT); @@ -3254,7 +3320,7 @@ mysqlnd_com_change_user_run(void *cmd) DBG_ENTER("mysqlnd_com_change_user_run"); - ret = conn->m->send_command_do_request(conn, COM_CHANGE_USER, (zend_uchar*) command->context.payload.s, command->context.payload.l, command->context.silent, TRUE); + ret = send_command_do_request(conn, COM_CHANGE_USER, (zend_uchar*) command->context.payload.s, command->context.payload.l, command->context.silent, TRUE); DBG_RETURN(ret); } @@ -3356,7 +3422,7 @@ mysqlnd_com_stmt_prepare_run(void *cmd) DBG_ENTER("mysqlnd_com_stmt_prepare_run"); - ret = conn->m->send_command_do_request(conn, COM_STMT_PREPARE, (zend_uchar*) command->context.query.s, command->context.query.l, FALSE, TRUE); + ret = send_command_do_request(conn, COM_STMT_PREPARE, (zend_uchar*) command->context.query.s, command->context.query.l, FALSE, TRUE); DBG_RETURN(ret); } @@ -3405,7 +3471,7 @@ mysqlnd_com_stmt_execute_run(void *cmd) DBG_ENTER("mysqlnd_com_stmt_execute_run"); - ret = conn->m->send_command_do_request(conn, COM_STMT_EXECUTE, (zend_uchar*) command->context.payload.s, command->context.payload.l, FALSE, FALSE); + ret = send_command_do_request(conn, COM_STMT_EXECUTE, (zend_uchar*) command->context.payload.s, command->context.payload.l, FALSE, FALSE); DBG_RETURN(ret); } @@ -3454,7 +3520,7 @@ mysqlnd_com_stmt_fetch_run(void *cmd) DBG_ENTER("mysqlnd_com_stmt_fetch_run"); - ret = conn->m->send_command_do_request(conn, COM_STMT_FETCH, (zend_uchar*) command->context.payload.s, command->context.payload.l, FALSE, TRUE); + ret = send_command_do_request(conn, COM_STMT_FETCH, (zend_uchar*) command->context.payload.s, command->context.payload.l, FALSE, TRUE); DBG_RETURN(ret); } @@ -3505,7 +3571,7 @@ mysqlnd_com_stmt_reset_run(void *cmd) DBG_ENTER("mysqlnd_com_stmt_reset_run"); int4store(cmd_buf, command->context.stmt_id); - ret = conn->m->send_command_do_request(conn, COM_STMT_RESET, cmd_buf, sizeof(cmd_buf), FALSE, TRUE); + ret = send_command_do_request(conn, COM_STMT_RESET, cmd_buf, sizeof(cmd_buf), FALSE, TRUE); DBG_RETURN(ret); } @@ -3554,7 +3620,7 @@ mysqlnd_com_stmt_send_long_data_run(void *cmd) DBG_ENTER("mysqlnd_com_stmt_send_long_data_run"); - ret = conn->m->send_command_do_request(conn, COM_STMT_SEND_LONG_DATA, (zend_uchar*) command->context.payload.s, command->context.payload.l, FALSE, TRUE); + ret = send_command_do_request(conn, COM_STMT_SEND_LONG_DATA, (zend_uchar*) command->context.payload.s, command->context.payload.l, FALSE, TRUE); DBG_RETURN(ret); } @@ -3605,7 +3671,7 @@ mysqlnd_com_stmt_close_run(void *cmd) DBG_ENTER("mysqlnd_com_stmt_close_run"); int4store(cmd_buf, command->context.stmt_id); - ret = conn->m->send_command_do_request(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf), FALSE, TRUE); + ret = send_command_do_request(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf), FALSE, TRUE); DBG_RETURN(ret); } |