From de560f3161495f2287a6673b61a074b798585720 Mon Sep 17 00:00:00 2001 From: Andrey Hristov Date: Wed, 16 Apr 2008 12:57:38 +0000 Subject: [PATCH] MFB: Update CVS from the development tree --- ext/mysql/php_mysql.c | 6 +- ext/mysqli/mysqli_api.c | 13 +- ext/mysqlnd/mysqlnd.c | 15 +- ext/mysqlnd/mysqlnd.h | 10 +- ext/mysqlnd/mysqlnd_debug.h | 2 - ext/mysqlnd/mysqlnd_libmysql_compat.h | 3 + ext/mysqlnd/mysqlnd_loaddata.c | 4 +- ext/mysqlnd/mysqlnd_ps.c | 260 +++++++++++++++++++------- ext/mysqlnd/mysqlnd_ps_codec.c | 114 ++--------- ext/mysqlnd/mysqlnd_result.c | 35 +++- ext/mysqlnd/mysqlnd_result_meta.c | 18 +- ext/mysqlnd/mysqlnd_structs.h | 80 ++++---- ext/mysqlnd/mysqlnd_wireprotocol.c | 10 +- ext/mysqlnd/php_mysqlnd.c | 2 + 14 files changed, 329 insertions(+), 243 deletions(-) diff --git a/ext/mysql/php_mysql.c b/ext/mysql/php_mysql.c index 16da0115c7..140d945003 100644 --- a/ext/mysql/php_mysql.c +++ b/ext/mysql/php_mysql.c @@ -1871,7 +1871,7 @@ PHP_FUNCTION(mysql_result) switch(Z_TYPE_PP(field)) { case IS_STRING: { int i=0; - MYSQL_FIELD *tmp_field; + const MYSQL_FIELD *tmp_field; char *table_name, *field_name, *tmp; if ((tmp=strchr(Z_STRVAL_PP(field), '.'))) { @@ -2375,7 +2375,7 @@ PHP_FUNCTION(mysql_fetch_field) { zval **result, **field=NULL; MYSQL_RES *mysql_result; - MYSQL_FIELD *mysql_field; + const MYSQL_FIELD *mysql_field; switch (ZEND_NUM_ARGS()) { case 1: @@ -2460,7 +2460,7 @@ static void php_mysql_field_info(INTERNAL_FUNCTION_PARAMETERS, int entry_type) { zval **result, **field; MYSQL_RES *mysql_result; - MYSQL_FIELD *mysql_field = {0}; + const MYSQL_FIELD *mysql_field = {0}; char buf[512]; int len; diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index 84daabf40b..6e1ff659a5 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -166,7 +166,7 @@ int mysqli_stmt_bind_param_do_bind(MY_STMT *stmt, unsigned int argc, unsigned in if (argc == start) { return PASS; } - params = emalloc((argc - start) * sizeof(MYSQLND_PARAM_BIND)); + params = safe_emalloc(argc - start, sizeof(MYSQLND_PARAM_BIND), 0); for (i = 0; i < (argc - start); i++) { zend_uchar type; switch (types[i]) { @@ -445,7 +445,7 @@ mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval ***args, unsigned int argc, unsigned int i; MYSQLND_RESULT_BIND *params; - params = emalloc((argc - start) * sizeof(MYSQLND_RESULT_BIND)); + params = safe_emalloc(argc - start, sizeof(MYSQLND_RESULT_BIND), 0); for (i = 0; i < (argc - start); i++) { params[i].zv = *(args[i + start]); } @@ -984,7 +984,7 @@ PHP_FUNCTION(mysqli_stmt_fetch) /* }}} */ /* {{{ php_add_field_properties */ -static void php_add_field_properties(zval *value, MYSQL_FIELD *field TSRMLS_DC) +static void php_add_field_properties(zval *value, const MYSQL_FIELD *field TSRMLS_DC) { add_property_string(value, "name",(field->name ? field->name : ""), 1); add_property_string(value, "orgname",(field->org_name ? field->org_name : ""), 1); @@ -1007,7 +1007,7 @@ PHP_FUNCTION(mysqli_fetch_field) { MYSQL_RES *result; zval *mysql_result; - MYSQL_FIELD *field; + const MYSQL_FIELD *field; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) { return; @@ -1030,7 +1030,6 @@ PHP_FUNCTION(mysqli_fetch_fields) { MYSQL_RES *result; zval *mysql_result; - MYSQL_FIELD *field; zval *obj; unsigned int i; @@ -1044,7 +1043,7 @@ PHP_FUNCTION(mysqli_fetch_fields) array_init(return_value); for (i = 0; i < mysql_num_fields(result); i++) { - field = mysql_fetch_field_direct(result, i); + const MYSQL_FIELD *field = mysql_fetch_field_direct(result, i); MAKE_STD_ZVAL(obj); object_init(obj); @@ -1061,7 +1060,7 @@ PHP_FUNCTION(mysqli_fetch_field_direct) { MYSQL_RES *result; zval *mysql_result; - MYSQL_FIELD *field; + const MYSQL_FIELD *field; long offset; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) { diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index 82702254bc..d7d6b95d68 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -171,7 +171,7 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND *conn TSRMLS_DC) } if (conn->options.num_commands) { unsigned int i; - for (i=0; i < conn->options.num_commands; i++) { + for (i = 0; i < conn->options.num_commands; i++) { mnd_pefree(conn->options.init_commands[i], pers); } mnd_pefree(conn->options.init_commands, pers); @@ -477,7 +477,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn, { char *transport = NULL, *errstr = NULL; char *hashed_details = NULL; - int transport_len, hashed_details_len, errcode = 0; + int transport_len, hashed_details_len, errcode = 0, host_len; unsigned int streams_options = ENFORCE_SAFE_MODE; unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT; zend_bool self_alloced = FALSE; @@ -530,8 +530,9 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn, if (!port && !socket) { port = 3306; } + host_len = strlen(host); #ifndef PHP_WIN32 - if (!strncasecmp(host, "localhost", sizeof("localhost") - 1)) { + if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) { if (!socket) { socket = "/tmp/mysql.sock"; } @@ -555,14 +556,6 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn, } if (conn->persistent) { -#if 0 - struct timeval tv; - gettimeofday(&tv, NULL); - /* We should generate something unique */ - hashed_details_len = spprintf(&hashed_details, 0, "%s@%s@%s@%ld@%ld@%0.8F", - transport, user, db, tv.tv_sec, (long int)tv.tv_usec, - php_combined_lcg(TSRMLS_C) * 10); -#endif hashed_details_len = spprintf(&hashed_details, 0, "%p", conn); DBG_INF_FMT("hashed_details=%s", hashed_details); } diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index 71dee8faf9..9fa7dcb1b6 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -147,6 +147,7 @@ void _mysqlnd_debug(const char *mode TSRMLS_DC); #define mysqlnd_field_tell(result) (result)->meta? (result)->meta->current_field:0) #define mysqlnd_fetch_field(result) (result)->m.fetch_field((result) TSRMLS_CC) #define mysqlnd_fetch_field_direct(result,fnr) ((result)->meta? &((result)->meta->fields[(fnr)]):NULL) +#define mysqlnd_fetch_fields(result) ((result)->meta? (result)->meta->fields: NULL) /* mysqlnd metadata */ #define mysqlnd_get_client_info() MYSQLND_VERSION @@ -197,6 +198,7 @@ PHPAPI unsigned long * mysqlnd_fetch_lengths(MYSQLND_RES * const result); #define mysqlnd_field_tell(result) (result)->m.field_tell((result)) #define mysqlnd_fetch_field(result) (result)->m.fetch_field((result) TSRMLS_CC) #define mysqlnd_fetch_field_direct(result,fnr) (result)->m.fetch_field_direct((result), (fnr) TSRMLS_CC) +#define mysqlnd_fetch_fields(result) (result)->m.fetch_fields((result) TSRMLS_CC) /* mysqlnd metadata */ PHPAPI const char * mysqlnd_get_client_info(); @@ -216,6 +218,9 @@ PHPAPI unsigned int mysqlnd_get_client_version(); /*****************************************************************************************************/ +PHPAPI void mysqlnd_efree_param_bind_dtor(MYSQLND_PARAM_BIND * param_bind); +PHPAPI void mysqlnd_efree_result_bind_dtor(MYSQLND_RESULT_BIND * result_bind); + PHPAPI const char * mysqlnd_field_type_name(enum mysqlnd_field_types field_type); @@ -261,9 +266,12 @@ PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size #define mysqlnd_stmt_prepare(stmt, q, qlen) (stmt)->m->prepare((stmt), (q), (qlen) TSRMLS_CC) #define mysqlnd_stmt_execute(stmt) (stmt)->m->execute((stmt) TSRMLS_CC) #define mysqlnd_stmt_send_long_data(s,p,d,l) (s)->m->send_long_data((s), (p), (d), (l) TSRMLS_CC) -#define mysqlnd_stmt_bind_param(stmt,bind) (stmt)->m->bind_param((stmt), (bind) TSRMLS_CC) +#define mysqlnd_stmt_bind_param(stmt,bind) (stmt)->m->bind_parameters((stmt), (bind) TSRMLS_CC) +#define mysqlnd_stmt_bind_one_param(s,n,z,t) (s)->m->bind_one_parameter((s), (n), (z), (t) TSRMLS_CC) #define mysqlnd_stmt_refresh_bind_param(s) (s)->m->refresh_bind_param((s) TSRMLS_CC) +#define mysqlnd_stmt_set_param_bind_dtor(s,d) (s)->m->set_param_bind_dtor((s), (d) TSRMLS_CC) #define mysqlnd_stmt_bind_result(stmt,bind) (stmt)->m->bind_result((stmt), (bind) TSRMLS_CC) +#define mysqlnd_stmt_set_result_bind_dtor(s,d) (s)->m->set_result_bind_dtor((s), (d) TSRMLS_CC) #define mysqlnd_stmt_param_metadata(stmt) (stmt)->m->get_parameter_metadata((stmt)) #define mysqlnd_stmt_result_metadata(stmt) (stmt)->m->get_result_metadata((stmt) TSRMLS_CC) diff --git a/ext/mysqlnd/mysqlnd_debug.h b/ext/mysqlnd/mysqlnd_debug.h index 151dbfd1d3..7b1ba88ae7 100644 --- a/ext/mysqlnd/mysqlnd_debug.h +++ b/ext/mysqlnd/mysqlnd_debug.h @@ -89,8 +89,6 @@ char * mysqlnd_get_backtrace(TSRMLS_D); #define DBG_RETURN(value) do { if (MYSQLND_G(dbg)) MYSQLND_G(dbg)->m->func_leave(MYSQLND_G(dbg), __LINE__, __FILE__); return (value); } while (0) #define DBG_VOID_RETURN do { if (MYSQLND_G(dbg)) MYSQLND_G(dbg)->m->func_leave(MYSQLND_G(dbg), __LINE__, __FILE__); return; } while (0) - - #elif MYSQLND_DBG_ENABLED == 0 diff --git a/ext/mysqlnd/mysqlnd_libmysql_compat.h b/ext/mysqlnd/mysqlnd_libmysql_compat.h index 533a3bcd65..52477e4b6b 100644 --- a/ext/mysqlnd/mysqlnd_libmysql_compat.h +++ b/ext/mysqlnd/mysqlnd_libmysql_compat.h @@ -57,6 +57,7 @@ #define mysql_escape_string(a,b,c) mysqlnd_escape_string((a), (b), (c)) #define mysql_fetch_field(r) mysqlnd_fetch_field((r)) #define mysql_fetch_field_direct(r,o) mysqlnd_fetch_field_direct((r), (o)) +#define mysql_fetch_fields(r) mysqlnd_fetch_fields((r)) #define mysql_fetch_lengths(r) mysqlnd_fetch_lengths((r)) #define mysql_fetch_row(r) mysqlnd_fetch_row_c((r)) #define mysql_field_count(r) mysqlnd_field_count((r)) @@ -87,6 +88,8 @@ #define mysql_stmt_num_rows(s) mysqlnd_stmt_num_rows((s)) #define mysql_stmt_insert_id(s) mysqlnd_stmt_insert_id((s)) #define mysql_stmt_close(s) mysqlnd_stmt_close((s)) +#define mysql_stmt_bind_param(s,b) mysqlnd_stmt_bind_param((s), (b)) +#define mysql_stmt_bind_result(s,b) mysqlnd_stmt_bind_result((s), (b)) #define mysql_stmt_errno(s) mysqlnd_stmt_errno((s)) #define mysql_stmt_error(s) mysqlnd_stmt_error((s)) #define mysql_stmt_sqlstate(s) mysqlnd_stmt_sqlstate((s)) diff --git a/ext/mysqlnd/mysqlnd_loaddata.c b/ext/mysqlnd/mysqlnd_loaddata.c index 2064aa39b1..3298c10380 100644 --- a/ext/mysqlnd/mysqlnd_loaddata.c +++ b/ext/mysqlnd/mysqlnd_loaddata.c @@ -58,7 +58,7 @@ int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS DBG_ENTER("mysqlnd_local_infile_init"); - *ptr= info= ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO))); + *ptr = info = ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO))); /* check open_basedir */ if (PG(open_basedir)) { @@ -88,7 +88,7 @@ static int mysqlnd_local_infile_read(void *ptr, char *buf, uint buf_len TSRMLS_DC) { MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr; - int count; + int count; DBG_ENTER("mysqlnd_local_infile_read"); diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index 7679b72169..59e9a96f63 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -56,7 +56,7 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC); -void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC); +static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC); /* {{{ mysqlnd_stmt::store_result */ @@ -78,8 +78,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC) if (stmt->cursor_exists) { /* Silently convert buffered to unbuffered, for now */ - MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC); - DBG_RETURN(res); + DBG_RETURN(stmt->m->use_result(stmt TSRMLS_CC)); } /* Nothing to store for UPSERT/LOAD DATA*/ @@ -135,7 +134,7 @@ MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt MYSQLND_RES *result; zend_bool to_cache = FALSE; - DBG_ENTER("mysqlnd_stmt::store_result"); + DBG_ENTER("mysqlnd_stmt::background_store_result"); DBG_INF_FMT("stmt=%lu", stmt->stmt_id); /* be compliant with libmysql - NULL will turn */ @@ -198,6 +197,7 @@ MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt } /* }}} */ + /* {{{ mysqlnd_stmt::get_result */ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC) @@ -215,8 +215,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC) if (stmt->cursor_exists) { /* Silently convert buffered to unbuffered, for now */ - MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC); - DBG_RETURN(res); + DBG_RETURN(stmt->m->use_result(stmt TSRMLS_CC)); } /* Nothing to store for UPSERT/LOAD DATA*/ @@ -255,6 +254,7 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC) { /* Follows parameter metadata, we have just to skip it, as libmysql does */ unsigned int i = 0; + enum_func_status ret = PASS; php_mysql_packet_res_field field_packet; DBG_ENTER("mysqlnd_stmt_skip_metadata"); @@ -264,13 +264,13 @@ mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC) field_packet.skip_parsing = TRUE; for (;i < stmt->param_count; i++) { if (FAIL == PACKET_READ_ALLOCA(field_packet, stmt->conn)) { - PACKET_FREE_ALLOCA(field_packet); - DBG_RETURN(FAIL); + ret = FAIL; + break; } } PACKET_FREE_ALLOCA(field_packet); - DBG_RETURN(PASS); + DBG_RETURN(ret); } /* }}} */ @@ -280,19 +280,21 @@ static enum_func_status mysqlnd_stmt_read_prepare_response(MYSQLND_STMT *stmt TSRMLS_DC) { php_mysql_packet_prepare_response prepare_resp; + enum_func_status ret = PASS; DBG_ENTER("mysqlnd_stmt_read_prepare_response"); DBG_INF_FMT("stmt=%lu", stmt->stmt_id); PACKET_INIT_ALLOCA(prepare_resp, PROT_PREPARE_RESP_PACKET); if (FAIL == PACKET_READ_ALLOCA(prepare_resp, stmt->conn)) { - PACKET_FREE_ALLOCA(prepare_resp); - return FAIL; + ret = FAIL; + goto done; } if (0xFF == prepare_resp.error_code) { stmt->error_info = stmt->conn->error_info = prepare_resp.error_info; - return FAIL; + ret = FAIL; + goto done; } stmt->stmt_id = prepare_resp.stmt_id; @@ -301,7 +303,8 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT *stmt TSRMLS_DC) stmt->param_count = prepare_resp.param_count; PACKET_FREE_ALLOCA(prepare_resp); - DBG_RETURN(PASS); +done: + DBG_RETURN(ret); } /* }}} */ @@ -487,13 +490,31 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC) DBG_RETURN(FAIL); } - if (stmt->param_count && !stmt->param_bind) { - SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, - "No data supplied for parameters in prepared statement"); - DBG_INF("FAIL"); - DBG_RETURN(FAIL); + if (stmt->param_count) { + uint i, not_bound = 0; + if (!stmt->param_bind) { + SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, + "No data supplied for parameters in prepared statement"); + DBG_INF("FAIL"); + DBG_RETURN(FAIL); + } + for (i = 0; i < stmt->param_count; i++) { + if (stmt->param_bind[i].zv == NULL) { + not_bound++; + } + } + if (not_bound) { + char * msg; + spprintf(&msg, 0, "No data supplied for %d parameter%s in prepared statement", + not_bound, not_bound>1 ?"s":""); + SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, msg); + if (msg) { + efree(msg); + } + DBG_INF("FAIL"); + DBG_RETURN(FAIL); + } } - request = mysqlnd_stmt_execute_generate_request(stmt, &request_len, &free_request TSRMLS_CC); /* support for buffer types should be added here ! */ @@ -553,7 +574,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC) use_result() or store_result() and we should be able to scrap the data on the line, if he just decides to close the statement. */ - DBG_INF_FMT("server_status=%d cursor=%d\n", stmt->upsert_status.server_status, + DBG_INF_FMT("server_status=%d cursor=%d", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) { @@ -595,10 +616,9 @@ enum_func_status mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC) { - unsigned int i; MYSQLND_STMT *stmt = (MYSQLND_STMT *) param; - uint field_count = result->meta->field_count; MYSQLND_RES_BUFFERED *set = result->stored_data; + uint field_count = result->meta->field_count; DBG_ENTER("mysqlnd_fetch_stmt_row_buffered"); DBG_INF_FMT("stmt=%lu", stmt->stmt_id); @@ -609,6 +629,8 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f { /* The user could have skipped binding - don't crash*/ if (stmt->result_bind) { + unsigned int i; + MYSQLND_RES_METADATA * meta = result->meta; zval **current_row = set->data_cursor; if (NULL == current_row[0]) { @@ -616,8 +638,8 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f set->initialized_rows++; result->m.row_decoder(set->row_buffers[row_num], current_row, - result->meta->field_count, - result->meta->fields, + meta->field_count, + meta->fields, result->conn TSRMLS_CC); if (stmt->update_max_length) { for (i = 0; i < result->field_count; i++) { @@ -628,8 +650,8 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f */ if (Z_TYPE_P(current_row[i]) >= IS_STRING) { unsigned long len = Z_STRLEN_P(current_row[i]); - if (result->meta->fields[i].max_length < len) { - result->meta->fields[i].max_length = len; + if (meta->fields[i].max_length < len) { + meta->fields[i].max_length = len; } } } @@ -687,7 +709,6 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int { enum_func_status ret; MYSQLND_STMT *stmt = (MYSQLND_STMT *) param; - unsigned int i, field_count = result->field_count; php_mysql_packet_row *row_packet = result->row_packet; DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered"); @@ -712,6 +733,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int mysqlnd_unbuffered_free_last_data() before it. The function returns always true. */ if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) { + unsigned int i, field_count = result->field_count; result->unbuf->row_count++; *fetched_anything = TRUE; @@ -966,7 +988,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla /* {{{ mysqlnd_stmt::fetch */ -PHPAPI enum_func_status +static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything TSRMLS_DC) { @@ -1021,7 +1043,6 @@ static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC) { enum_func_status ret = PASS; - MYSQLND * conn = stmt->conn; zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */]; DBG_ENTER("mysqlnd_stmt::reset"); @@ -1031,6 +1052,7 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC) SET_EMPTY_ERROR(stmt->conn->error_info); if (stmt->stmt_id) { + MYSQLND * conn = stmt->conn; if (stmt->param_bind) { unsigned int i; DBG_INF("resetting long data"); @@ -1084,7 +1106,6 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned enum_func_status ret = FAIL; MYSQLND * conn = stmt->conn; zend_uchar *cmd_buf; - size_t packet_len; enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA; DBG_ENTER("mysqlnd_stmt::send_long_data"); @@ -1126,6 +1147,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned */ if (CONN_GET_STATE(conn) == CONN_READY) { + size_t packet_len; stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED; cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length); @@ -1178,19 +1200,20 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned /* }}} */ -/* {{{ _mysqlnd_stmt_bind_param */ +/* {{{ mysqlnd_stmt::bind_parameters */ static enum_func_status -MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt, - MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const stmt, + MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC) { - unsigned int i = 0; - DBG_ENTER("mysqlnd_stmt::bind_param"); DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count); if (stmt->state < MYSQLND_STMT_PREPARED) { SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared); DBG_ERR("not prepared"); + if (param_bind && stmt->param_bind_dtor) { + stmt->param_bind_dtor(param_bind); + } DBG_RETURN(FAIL); } @@ -1198,6 +1221,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt, SET_EMPTY_ERROR(stmt->conn->error_info); if (stmt->param_count) { + unsigned int i = 0; + if (!param_bind) { SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported"); @@ -1210,29 +1235,28 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt, Forbid for now re-binding!! */ for (i = 0; i < stmt->param_count; i++) { - /* For BLOBS zv is NULL */ + /* + We may have the last reference, then call zval_ptr_dtor() + or we may leak memory. + Switching from bind_one_parameter to bind_parameters may result in zv being NULL + */ if (stmt->param_bind[i].zv) { - /* - We may have the last reference, then call zval_ptr_dtor() - or we may leak memory. - */ zval_ptr_dtor(&stmt->param_bind[i].zv); - stmt->param_bind[i].zv = NULL; } } - mnd_efree(stmt->param_bind); + if (stmt->param_bind != param_bind && stmt->param_bind_dtor) { + stmt->param_bind_dtor(stmt->param_bind); + } } stmt->param_bind = param_bind; for (i = 0; i < stmt->param_count; i++) { /* The client will use stmt_send_long_data */ DBG_INF_FMT("%d is of type %d", i, stmt->param_bind[i].type); - if (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB) { - /* Prevent from freeing */ - Z_ADDREF_P(stmt->param_bind[i].zv); - /* Don't update is_ref, or we will leak during conversion */ - } else { - stmt->param_bind[i].zv = NULL; + /* Prevent from freeing */ + /* Don't update is_ref, or we will leak during conversion */ + Z_ADDREF_P(stmt->param_bind[i].zv); + if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) { stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED; } } @@ -1244,7 +1268,58 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt, /* }}} */ -/* {{{ _mysqlnd_stmt_refresh_bind_param */ +/* {{{ mysqlnd_stmt::bind_one_parameter */ +static enum_func_status +MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const stmt, unsigned int param_no, + zval * const zv, zend_uchar type TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_stmt::bind_one_parameter"); + DBG_INF_FMT("stmt=%lu param_no=%d param_count=%u type=%d", + stmt->stmt_id, param_no, stmt->param_count, type); + + if (stmt->state < MYSQLND_STMT_PREPARED) { + SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared); + DBG_ERR("not prepared"); + DBG_RETURN(FAIL); + } + + if (param_no < 0 || param_no >= stmt->param_count) { + SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number"); + DBG_ERR("invalid param_no"); + DBG_RETURN(FAIL); + } + SET_EMPTY_ERROR(stmt->error_info); + SET_EMPTY_ERROR(stmt->conn->error_info); + + if (stmt->param_count) { + if (!stmt->param_bind) { + stmt->param_bind = ecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND)); + } + + /* Prevent from freeing */ + /* Don't update is_ref, or we will leak during conversion */ + Z_ADDREF_P(zv); + DBG_INF("Binding"); + /* Release what we had, if we had */ + if (stmt->param_bind[param_no].zv) { + zval_ptr_dtor(&stmt->param_bind[param_no].zv); + } + if (type == MYSQL_TYPE_LONG_BLOB) { + /* The client will use stmt_send_long_data */ + stmt->param_bind[param_no].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED; + } + stmt->param_bind[param_no].zv = zv; + stmt->param_bind[param_no].type = type; + + stmt->send_types_to_server = 1; + } + DBG_INF("PASS"); + DBG_RETURN(PASS); +} +/* }}} */ + + +/* {{{ mysqlnd_stmt::refresh_bind_param */ static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const stmt TSRMLS_DC) { @@ -1269,13 +1344,24 @@ MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const stmt TSRML /* }}} */ +/* {{{ mysqlnd_stmt::set_bind_param_dtor */ +static void +MYSQLND_METHOD(mysqlnd_stmt, set_param_bind_dtor)(MYSQLND_STMT * const stmt, + void (*param_bind_dtor)(MYSQLND_PARAM_BIND *dtor) TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_stmt::set_bind_param_dtor"); + DBG_INF_FMT("stmt=%p", param_bind_dtor); + stmt->param_bind_dtor = param_bind_dtor; + DBG_VOID_RETURN; +} +/* }}} */ + + /* {{{ mysqlnd_stmt::bind_result */ static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC) { - uint i = 0; - DBG_ENTER("mysqlnd_stmt::bind_result"); DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count); @@ -1284,14 +1370,16 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt, if (stmt->state < MYSQLND_STMT_PREPARED) { SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared); - if (result_bind) { - mnd_efree(result_bind); + if (result_bind && stmt->result_bind_dtor) { + stmt->result_bind_dtor(result_bind); } DBG_ERR("not prepared"); DBG_RETURN(FAIL); } if (stmt->field_count) { + uint i = 0; + if (!result_bind) { DBG_ERR("no result bind passed"); DBG_RETURN(FAIL); @@ -1310,8 +1398,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt, */ stmt->result_bind[i].bound = TRUE; } - } else if (result_bind) { - mnd_efree(result_bind); + } else if (result_bind && stmt->result_bind_dtor) { + stmt->result_bind_dtor(result_bind); } DBG_INF("PASS"); DBG_RETURN(PASS); @@ -1319,6 +1407,19 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt, /* }}} */ +/* {{{ mysqlnd_stmt::set_bind_result_dtor */ +static void +MYSQLND_METHOD(mysqlnd_stmt, set_result_bind_dtor)(MYSQLND_STMT * const stmt, + void (*result_bind_dtor)(MYSQLND_RESULT_BIND *dtor) TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_stmt::set_bind_param_dtor"); + DBG_INF_FMT("stmt=%p", result_bind_dtor); + stmt->result_bind_dtor = result_bind_dtor; + DBG_VOID_RETURN; +} +/* }}} */ + + /* {{{ mysqlnd_stmt::insert_id */ static uint64 MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const stmt) @@ -1483,7 +1584,8 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt, case STMT_ATTR_CURSOR_TYPE: { if (val > (unsigned long) CURSOR_TYPE_READ_ONLY) { SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented"); - return FAIL; + DBG_INF("FAIL"); + DBG_RETURN(FAIL); } stmt->flags = val; break; @@ -1493,7 +1595,8 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt, val = MYSQLND_DEFAULT_PREFETCH_ROWS; } else if (val > 1) { SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented"); - return FAIL; + DBG_INF("FAIL"); + DBG_RETURN(FAIL); } stmt->prefetch_rows = val; break; @@ -1508,7 +1611,7 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt, /* }}} */ -/* {{{ _mysqlnd_stmt_attr_get */ +/* {{{ mysqlnd_stmt::attr_get */ static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, attr_get)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, @@ -1624,7 +1727,9 @@ void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC) } } } - mnd_efree(stmt->result_bind); + if (stmt->result_bind_dtor) { + stmt->result_bind_dtor(stmt->result_bind); + } stmt->result_bind = NULL; DBG_VOID_RETURN; @@ -1649,13 +1754,17 @@ void mysqlnd_internal_free_stmt_content(MYSQLND_STMT *stmt TSRMLS_DC) lost reference. */ for (i = 0; i < stmt->param_count; i++) { - /* For BLOBs zv is NULL */ + /* + If bind_one_parameter was used, but not everything was + bound and nothing was fetched, then some `zv` could be NULL + */ if (stmt->param_bind[i].zv) { zval_ptr_dtor(&stmt->param_bind[i].zv); } } - - mnd_efree(stmt->param_bind); + if (stmt->param_bind_dtor) { + stmt->param_bind_dtor(stmt->param_bind); + } stmt->param_bind = NULL; } @@ -1790,9 +1899,12 @@ struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = { MYSQLND_METHOD(mysqlnd_stmt, fetch), - MYSQLND_METHOD(mysqlnd_stmt, bind_param), + MYSQLND_METHOD(mysqlnd_stmt, bind_parameters), + MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter), MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param), + MYSQLND_METHOD(mysqlnd_stmt, set_param_bind_dtor), MYSQLND_METHOD(mysqlnd_stmt, bind_result), + MYSQLND_METHOD(mysqlnd_stmt, set_result_bind_dtor), MYSQLND_METHOD(mysqlnd_stmt, send_long_data), MYSQLND_METHOD(mysqlnd_stmt, param_metadata), MYSQLND_METHOD(mysqlnd_stmt, result_metadata), @@ -1835,10 +1947,32 @@ MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC) */ stmt->conn = conn->m->get_reference(conn); + stmt->m->set_param_bind_dtor(stmt, mysqlnd_efree_param_bind_dtor TSRMLS_CC); + stmt->m->set_result_bind_dtor(stmt, mysqlnd_efree_result_bind_dtor TSRMLS_CC); + DBG_RETURN(stmt); } /* }}} */ + +/* {{{ mysqlnd_efree_param_bind_dtor */ +PHPAPI void +mysqlnd_efree_param_bind_dtor(MYSQLND_PARAM_BIND * param_bind) +{ + efree(param_bind); +} +/* }}} */ + + +/* {{{ mysqlnd_efree_result_bind_dtor */ +PHPAPI void +mysqlnd_efree_result_bind_dtor(MYSQLND_RESULT_BIND * result_bind) +{ + efree(result_bind); +} +/* }}} */ + + /* * Local variables: * tab-width: 4 diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index f393e42a54..c832c6b463 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -156,14 +156,6 @@ void ps_fetch_int8(zval *zv, const MYSQLND_FIELD * const field, zend_bool as_unicode TSRMLS_DC) { ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 1 TSRMLS_CC); -#if 0 - if (field->flags & UNSIGNED_FLAG) { - ZVAL_LONG(zv, *(my_uint8*)*row); - } else { - ZVAL_LONG(zv, *(my_int8*)*row); - } - (*row)++; -#endif } /* }}} */ @@ -175,14 +167,6 @@ void ps_fetch_int16(zval *zv, const MYSQLND_FIELD * const field, zend_bool as_unicode TSRMLS_DC) { ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 2 TSRMLS_CC); -#if 0 - if (field->flags & UNSIGNED_FLAG) { - ZVAL_LONG(zv, (my_uint16) sint2korr(*row)); - } else { - ZVAL_LONG(zv, (my_int16) sint2korr(*row)); - } - (*row)+= 2; -#endif } /* }}} */ @@ -194,44 +178,6 @@ void ps_fetch_int32(zval *zv, const MYSQLND_FIELD * const field, zend_bool as_unicode TSRMLS_DC) { ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 4 TSRMLS_CC); -#if 0 - - if (field->flags & UNSIGNED_FLAG) { - my_uint32 uval; - - /* unsigned int (11) */ - uval= (my_uint32) sint4korr(*row); -#if SIZEOF_LONG==4 - if (uval > INT_MAX) { - char *tmp, *p; - int j=10; - tmp= mnd_emalloc(11); - p= &tmp[9]; - do { - *p-- = (uval % 10) + 48; - uval = uval / 10; - } while (--j > 0); - tmp[10]= '\0'; - /* unsigned int > INT_MAX is 10 digits - ALWAYS */ -#if PHP_MAJOR_VERSION >= 6 - if (!as_unicode) { -#endif - ZVAL_STRING(zv, tmp, 0); -#if PHP_MAJOR_VERSION >= 6 - } else { - ZVAL_UTF8_STRINGL(zv, tmp, 10, ZSTR_AUTOFREE); - } -#endif /* PHP_MAJOR_VERSION >= 6 */ - } else -#endif /* #if SIZEOF_LONG==4 */ - { - ZVAL_LONG(zv, uval); - } - } else { - ZVAL_LONG(zv, (my_int32) sint4korr(*row)); - } - (*row)+= 4; -#endif /* 0 */ } /* }}} */ @@ -243,40 +189,6 @@ void ps_fetch_int64(zval *zv, const MYSQLND_FIELD * const field, zend_bool as_unicode TSRMLS_DC) { ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 8 TSRMLS_CC); -#if 0 - - uint64 llval = (uint64) sint8korr(*row); - zend_bool uns = field->flags & UNSIGNED_FLAG? TRUE:FALSE; - -#if SIZEOF_LONG==8 - if (uns == TRUE && llval > 9223372036854775807L) { -#elif SIZEOF_LONG==4 - if ((uns == TRUE && llval > L64(2147483647)) || - (uns == FALSE && ((L64( 2147483647) < (int64) llval) || - (L64(-2147483648) > (int64) llval)))) - { -#endif - char tmp[22]; - /* even though lval is declared as unsigned, the value - * may be negative. Therefor we cannot use MYSQLND_LLU_SPEC and must - * use MYSQLND_LL_SPEC. - */ - sprintf((char *)&tmp, uns == TRUE? MYSQLND_LLU_SPEC : MYSQLND_LL_SPEC, llval); -#if PHP_MAJOR_VERSION >= 6 - if (!as_unicode) { -#endif - ZVAL_STRING(zv, tmp, 1); -#if PHP_MAJOR_VERSION >= 6 - } else { - ZVAL_UTF8_STRING(zv, tmp, ZSTR_DUPLICATE); - } -#endif - } else { - /* This cast is safe, as we have checked the values above */ - ZVAL_LONG(zv, (long) llval); - } - (*row)+= 8; -#endif /* 0 */ } /* }}} */ @@ -707,14 +619,15 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uch for (i = 0; i < stmt->param_count; i++) { unsigned int j; zval *the_var = stmt->param_bind[i].zv; - if (stmt->param_bind[i].zv && - Z_TYPE_P(stmt->param_bind[i].zv) == IS_NULL) { + + if (!the_var || (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB && + Z_TYPE_P(the_var) == IS_NULL)) { continue; } for (j = i + 1; j < stmt->param_count; j++) { - if (stmt->param_bind[j].zv == stmt->param_bind[i].zv) { + if (stmt->param_bind[j].zv == the_var) { /* Double binding of the same zval, make a copy */ - mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i); + mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i); break; } } @@ -722,9 +635,9 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uch switch (stmt->param_bind[i].type) { case MYSQL_TYPE_DOUBLE: data_size += 8; - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_DOUBLE) { + if (Z_TYPE_P(the_var) != IS_DOUBLE) { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i); + mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i); } } break; @@ -737,9 +650,9 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uch #else #error "Should not happen" #endif - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { + if (Z_TYPE_P(the_var) != IS_LONG) { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i); + mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i); } } break; @@ -748,7 +661,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uch /* User hasn't sent anything, we will send empty string. Empty string has length of 0, encoded in 1 byte. No real - data will follow after it. + data will follows after it. */ data_size++; } @@ -756,14 +669,13 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uch case MYSQL_TYPE_VAR_STRING: data_size += 8; /* max 8 bytes for size */ #if PHP_MAJOR_VERSION < 6 - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_STRING) + if (Z_TYPE_P(the_var) != IS_STRING) #elif PHP_MAJOR_VERSION >= 6 - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_STRING || - (UG(unicode) && Z_TYPE_P(stmt->param_bind[i].zv) == IS_UNICODE)) + if (Z_TYPE_P(the_var) != IS_STRING || (UG(unicode) && Z_TYPE_P(the_var) == IS_UNICODE)) #endif { if (!copies || !copies[i]) { - mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i); + mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i); } the_var = copies[i]; #if PHP_MAJOR_VERSION >= 6 diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index f987ffba65..fac01c1047 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -194,7 +194,7 @@ void mysqlnd_free_buffered_data(MYSQLND_RES *result TSRMLS_DC) MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row]; int col; - for (col = field_count - 1; col >=0 ; col--) { + for (col = field_count - 1; col >= 0; --col) { zend_bool copy_ctor_called; if (current_row[0] == NULL) { break;/* row that was never initialized */ @@ -817,10 +817,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flag { enum_func_status ret; zval *row = (zval *) param; - unsigned int i, - field_count = result->field_count; php_mysql_packet_row *row_packet = result->row_packet; - unsigned long *lengths = result->lengths; DBG_ENTER("mysqlnd_fetch_row_unbuffered"); DBG_INF_FMT("flags=%d", flags); @@ -860,10 +857,12 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flag HashTable *row_ht = Z_ARRVAL_P(row); MYSQLND_FIELD *field = result->meta->fields; struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys; + unsigned int i, field_count = result->field_count; + unsigned long *lengths = result->lengths; result->m.row_decoder(result->unbuf->last_row_buffer, result->unbuf->last_row_data, - row_packet->field_count, + field_count, row_packet->fields_metadata, result->conn TSRMLS_CC); @@ -1200,7 +1199,6 @@ mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result, row_packet->skip_extraction = TRUE; /* let php_mysqlnd_rowp_read() not allocate row_packet->fields, we will do it */ while (FAIL != (ret = PACKET_READ(row_packet, conn)) && !row_packet->eof) { - if (!free_rows) { uint64 total_rows = free_rows = next_extend = next_extend * 5 / 3; /* extend with 33% */ total_rows += set->row_count; @@ -1313,7 +1311,6 @@ static enum_func_status mysqlnd_fetch_row_async_buffered(MYSQLND_RES *result, void *param, unsigned int flags, zend_bool *fetched_anything TSRMLS_DC) { - unsigned int i; zval *row = (zval *) param; MYSQLND_RES_BG_BUFFERED *set = result->bg_stored_data; @@ -1350,6 +1347,7 @@ mysqlnd_fetch_row_async_buffered(MYSQLND_RES *result, void *param, unsigned int /* If there was no decoding in background, we have to decode here */ if (set->decode_in_foreground == TRUE) { MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row_num]; + unsigned int i; result->m.row_decoder(current_buffer, current_row, result->meta->field_count, @@ -1714,7 +1712,7 @@ MYSQLND_METHOD(mysqlnd_res, num_fields)(const MYSQLND_RES * const result) /* {{{ mysqlnd_res::fetch_field */ -static MYSQLND_FIELD * +static const MYSQLND_FIELD * MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC) { DBG_ENTER("mysqlnd_res::fetch_field"); @@ -1731,7 +1729,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC) /* {{{ mysqlnd_res::fetch_field_direct */ -static MYSQLND_FIELD * +static const MYSQLND_FIELD * MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC) { @@ -1749,6 +1747,24 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(MYSQLND_RES * const result, /* }}} */ +/* {{{ mysqlnd_res::fetch_field */ +static const MYSQLND_FIELD * +MYSQLND_METHOD(mysqlnd_res, fetch_fields)(MYSQLND_RES * const result TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_res::fetch_fields"); + if (result->meta) { + if (result->stored_data && (result->stored_data->initialized_rows < result->stored_data->row_count)) { + /* we have to initialize the rest to get the updated max length */ + mysqlnd_res_initialize_result_set_rest(result TSRMLS_CC); + } + DBG_RETURN(result->meta->m->fetch_fields(result->meta TSRMLS_CC)); + } + DBG_RETURN(NULL); +} +/* }}} */ + + + /* {{{ mysqlnd_res::field_seek */ static MYSQLND_FIELD_OFFSET MYSQLND_METHOD(mysqlnd_res, field_seek)(MYSQLND_RES * const result, @@ -1945,6 +1961,7 @@ MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCAC ret->m.field_tell = MYSQLND_METHOD(mysqlnd_res, field_tell); ret->m.fetch_field = MYSQLND_METHOD(mysqlnd_res, fetch_field); ret->m.fetch_field_direct = MYSQLND_METHOD(mysqlnd_res, fetch_field_direct); + ret->m.fetch_fields = MYSQLND_METHOD(mysqlnd_res, fetch_fields); ret->m.skip_result = MYSQLND_METHOD(mysqlnd_res, skip_result); ret->m.free_result_buffers = MYSQLND_METHOD(mysqlnd_res, free_result_buffers); diff --git a/ext/mysqlnd/mysqlnd_result_meta.c b/ext/mysqlnd/mysqlnd_result_meta.c index 56906514af..ee9c4a4202 100644 --- a/ext/mysqlnd/mysqlnd_result_meta.c +++ b/ext/mysqlnd/mysqlnd_result_meta.c @@ -369,7 +369,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * co /* }}} */ /* {{{ mysqlnd_res_meta::fetch_field */ -static MYSQLND_FIELD * +static const MYSQLND_FIELD * MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC) { DBG_ENTER("mysqlnd_res_meta::fetch_field"); @@ -382,7 +382,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta /* {{{ mysqlnd_res_meta::fetch_field_direct */ -static MYSQLND_FIELD * +static const MYSQLND_FIELD * MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC) { @@ -393,6 +393,16 @@ MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA /* }}} */ +/* {{{ mysqlnd_res_meta::fetch_fields */ +static const MYSQLND_FIELD * +MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields)(MYSQLND_RES_METADATA * const meta TSRMLS_DC) +{ + DBG_ENTER("mysqlnd_res_meta::fetch_fields"); + DBG_RETURN(meta->fields); +} +/* }}} */ + + /* {{{ mysqlnd_res_meta::field_tell */ static MYSQLND_FIELD_OFFSET MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const meta) @@ -405,6 +415,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const MYSQLND_CLASS_METHODS_START(mysqlnd_res_meta) MYSQLND_METHOD(mysqlnd_res_meta, fetch_field), MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct), + MYSQLND_METHOD(mysqlnd_res_meta, fetch_fields), MYSQLND_METHOD(mysqlnd_res_meta, field_tell), MYSQLND_METHOD(mysqlnd_res_meta, read_metadata), MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata), @@ -413,7 +424,8 @@ MYSQLND_CLASS_METHODS_END; /* {{{ mysqlnd_result_meta_init */ -MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count TSRMLS_DC) +MYSQLND_RES_METADATA * +mysqlnd_result_meta_init(unsigned int field_count TSRMLS_DC) { MYSQLND_RES_METADATA *ret; DBG_ENTER("mysqlnd_result_meta_init"); diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index 334eef8061..d9cc7351f1 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -92,10 +92,10 @@ typedef struct st_mysqlnd_field typedef struct st_mysqlnd_upsert_result { - unsigned int warning_count; - unsigned int server_status; - uint64 affected_rows; - uint64 last_insert_id; + unsigned int warning_count; + unsigned int server_status; + uint64 affected_rows; + uint64 last_insert_id; } mysqlnd_upsert_status; @@ -212,7 +212,7 @@ typedef struct st_mysqlnd_stats { uint64 values[STAT_LAST]; #ifdef ZTS - MUTEX_T LOCK_access; + MUTEX_T LOCK_access; #endif } MYSQLND_STATS; @@ -257,7 +257,7 @@ struct st_mysqlnd_conn_methods unsigned int (*get_error_no)(const MYSQLND * const conn); const char * (*get_error_str)(const MYSQLND * const conn); const char * (*get_sqlstate)(const MYSQLND * const conn); - uint64 (*get_thread_id)(const MYSQLND * const conn); + uint64 (*get_thread_id)(const MYSQLND * const conn); void (*get_statistics)(const MYSQLND * const conn, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC); unsigned long (*get_server_version)(const MYSQLND * const conn); @@ -270,8 +270,8 @@ struct st_mysqlnd_conn_methods MYSQLND_RES * (*list_fields)(MYSQLND *conn, const char *table, const char *achtung_wild TSRMLS_DC); MYSQLND_RES * (*list_method)(MYSQLND *conn, const char *query, const char *achtung_wild, char *par1 TSRMLS_DC); - uint64 (*get_last_insert_id)(const MYSQLND * const conn); - uint64 (*get_affected_rows)(const MYSQLND * const conn); + uint64 (*get_last_insert_id)(const MYSQLND * const conn); + uint64 (*get_affected_rows)(const MYSQLND * const conn); unsigned int (*get_warning_count)(const MYSQLND * const conn); unsigned int (*get_field_count)(const MYSQLND * const conn); @@ -302,14 +302,15 @@ struct st_mysqlnd_res_methods MYSQLND_ROW_C (*fetch_row_c)(MYSQLND_RES *result TSRMLS_DC); void (*fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC); void (*fetch_field_data)(MYSQLND_RES *result, unsigned int offset, zval *return_value TSRMLS_DC); - uint64 (*num_rows)(const MYSQLND_RES * const result); + uint64 (*num_rows)(const MYSQLND_RES * const result); unsigned int (*num_fields)(const MYSQLND_RES * const result); enum_func_status (*skip_result)(MYSQLND_RES * const result TSRMLS_DC); enum_func_status (*seek_data)(MYSQLND_RES * result, uint64 row TSRMLS_DC); MYSQLND_FIELD_OFFSET (*seek_field)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET field_offset); MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES * const result); - MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES * const result TSRMLS_DC); - MYSQLND_FIELD * (*fetch_field_direct)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC); + const MYSQLND_FIELD *(*fetch_field)(MYSQLND_RES * const result TSRMLS_DC); + const MYSQLND_FIELD *(*fetch_field_direct)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC); + const MYSQLND_FIELD *(*fetch_fields)(MYSQLND_RES * const result TSRMLS_DC); enum_func_status (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC); unsigned long * (*fetch_lengths)(MYSQLND_RES * const result); @@ -325,8 +326,9 @@ struct st_mysqlnd_res_methods struct st_mysqlnd_res_meta_methods { - MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC); - MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC); + const MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC); + const MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC); + const MYSQLND_FIELD * (*fetch_fields)(MYSQLND_RES_METADATA * const meta TSRMLS_DC); MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES_METADATA * const meta); enum_func_status (*read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND *conn TSRMLS_DC); MYSQLND_RES_METADATA * (*clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent TSRMLS_DC); @@ -350,17 +352,20 @@ struct st_mysqlnd_stmt_methods enum_func_status (*fetch)(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything TSRMLS_DC); - enum_func_status (*bind_param)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC); + enum_func_status (*bind_parameters)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC); + enum_func_status (*bind_one_parameter)(MYSQLND_STMT * const stmt, unsigned int param_no, zval * const zv, zend_uchar type TSRMLS_DC); enum_func_status (*refresh_bind_param)(MYSQLND_STMT * const stmt TSRMLS_DC); + void (*set_param_bind_dtor)(MYSQLND_STMT * const stmt, void (*param_bind_dtor)(MYSQLND_PARAM_BIND *) TSRMLS_DC); enum_func_status (*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC); + void (*set_result_bind_dtor)(MYSQLND_STMT * const stmt, void (*result_bind_dtor)(MYSQLND_RESULT_BIND *) TSRMLS_DC); enum_func_status (*send_long_data)(MYSQLND_STMT * const stmt, unsigned int param_num, const char * const data, unsigned long length TSRMLS_DC); - MYSQLND_RES * (*get_parameter_metadata)(MYSQLND_STMT * const stmt); - MYSQLND_RES * (*get_result_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC); + MYSQLND_RES * (*get_parameter_metadata)(MYSQLND_STMT * const stmt); + MYSQLND_RES * (*get_result_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC); - uint64 (*get_last_insert_id)(const MYSQLND_STMT * const stmt); - uint64 (*get_affected_rows)(const MYSQLND_STMT * const stmt); - uint64 (*get_num_rows)(const MYSQLND_STMT * const stmt); + uint64 (*get_last_insert_id)(const MYSQLND_STMT * const stmt); + uint64 (*get_affected_rows)(const MYSQLND_STMT * const stmt); + uint64 (*get_num_rows)(const MYSQLND_STMT * const stmt); unsigned int (*get_param_count)(const MYSQLND_STMT * const stmt); unsigned int (*get_field_count)(const MYSQLND_STMT * const stmt); @@ -387,7 +392,7 @@ struct st_mysqlnd_connection char *passwd; unsigned int *passwd_len; char *scheme; - uint64 thread_id; + uint64 thread_id; char *server_version; char *host_info; unsigned char *scramble; @@ -493,22 +498,22 @@ struct st_mysqlnd_result_metadata struct st_mysqlnd_background_buffered_result { - zval ***data; - uint64 data_size; - zval ***data_cursor; + zval ***data; + uint64 data_size; + zval ***data_cursor; MYSQLND_MEMORY_POOL_CHUNK **row_buffers; - uint64 row_count; - uint64 initialized_rows; - zend_bool persistent; + uint64 row_count; + uint64 initialized_rows; + zend_bool persistent; - MYSQLND_QCACHE *qcache; - unsigned int references; + MYSQLND_QCACHE *qcache; + unsigned int references; - zend_bool decode_in_foreground; + zend_bool decode_in_foreground; #ifdef ZTS - zend_bool bg_fetch_finished; - MUTEX_T LOCK; + zend_bool bg_fetch_finished; + MUTEX_T LOCK; #endif mysqlnd_error_info error_info; @@ -521,8 +526,8 @@ struct st_mysqlnd_buffered_result zval **data; zval **data_cursor; MYSQLND_MEMORY_POOL_CHUNK **row_buffers; - uint64 row_count; - uint64 initialized_rows; + uint64 row_count; + uint64 initialized_rows; zend_bool persistent; MYSQLND_QCACHE *qcache; @@ -538,7 +543,7 @@ struct st_mysqlnd_unbuffered_result zval **last_row_data; MYSQLND_MEMORY_POOL_CHUNK *last_row_buffer; - uint64 row_count; + uint64 row_count; zend_bool eof_reached; }; @@ -565,10 +570,10 @@ struct st_mysqlnd_res */ unsigned long *lengths; - php_mysql_packet_row *row_packet; /* Unused for PS */ + php_mysql_packet_row *row_packet; /* zval cache */ - MYSQLND_THD_ZVAL_PCACHE *zval_cache; + MYSQLND_THD_ZVAL_PCACHE *zval_cache; }; @@ -615,6 +620,9 @@ struct st_mysqlnd_stmt MYSQLND_CMD_BUFFER cmd_buffer; unsigned int execute_count;/* count how many times the stmt was executed */ + void (*param_bind_dtor)(MYSQLND_PARAM_BIND *); + void (*result_bind_dtor)(MYSQLND_RESULT_BIND *); + struct st_mysqlnd_stmt_methods *m; }; diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index 6566bfee07..f4eaeefd22 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -529,7 +529,7 @@ static enum_func_status php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC) { zend_uchar buf[512]; - zend_uchar *p= buf; + zend_uchar *p = buf; zend_uchar *begin = buf; php_mysql_packet_greet *packet= (php_mysql_packet_greet *) _packet; @@ -623,7 +623,7 @@ void php_mysqlnd_greet_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) static void php_mysqlnd_crypt(zend_uchar *buffer, const zend_uchar *s1, const zend_uchar *s2, size_t len) { - const unsigned char *s1_end= s1 + len; + const unsigned char *s1_end = s1 + len; while (s1 < s1_end) { *buffer++= *s1++ ^ *s2++; } @@ -754,7 +754,7 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC) PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "OK"); /* Should be always 0x0 or 0xFF for error */ - packet->field_count= uint1korr(p); + packet->field_count = uint1korr(p); p++; if (0xFF == packet->field_count) { @@ -825,7 +825,7 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC) */ php_mysql_packet_eof *packet= (php_mysql_packet_eof *) _packet; zend_uchar buf[5 + 10 + sizeof(packet->sqlstate) + sizeof(packet->error)]; - zend_uchar *p= buf; + zend_uchar *p = buf; zend_uchar *begin = buf; DBG_ENTER("php_mysqlnd_eof_read"); @@ -833,7 +833,7 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC) PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "EOF"); /* Should be always 0xFE */ - packet->field_count= uint1korr(p); + packet->field_count = uint1korr(p); p++; if (0xFF == packet->field_count) { diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c index 21e9d5a58e..e232d48ac9 100644 --- a/ext/mysqlnd/php_mysqlnd.c +++ b/ext/mysqlnd/php_mysqlnd.c @@ -199,8 +199,10 @@ static PHP_RINIT_FUNCTION(mysqlnd) return SUCCESS; } /* }}} */ +#endif +#if defined(PHP_DEBUG) /* {{{ PHP_RSHUTDOWN_FUNCTION */ static PHP_RSHUTDOWN_FUNCTION(mysqlnd) -- 2.40.0