diff options
Diffstat (limited to 'ext/mysqlnd')
-rw-r--r-- | ext/mysqlnd/config9.m4 | 12 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_enum_n_def.h | 2 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_portability.h | 107 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_ps_codec.c | 350 | ||||
-rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.h | 1 |
5 files changed, 197 insertions, 275 deletions
diff --git a/ext/mysqlnd/config9.m4 b/ext/mysqlnd/config9.m4 index 09aca5af8a..0e08b977af 100644 --- a/ext/mysqlnd/config9.m4 +++ b/ext/mysqlnd/config9.m4 @@ -48,16 +48,4 @@ fi if test "$PHP_MYSQLND" != "no" || test "$PHP_MYSQLND_ENABLED" = "yes" || test "$PHP_MYSQLI" != "no"; then PHP_ADD_BUILD_DIR([ext/mysqlnd], 1) - - dnl This creates a file so it has to be after above macros - PHP_CHECK_TYPES([int8 uint8 int16 uint16 int32 uint32 uchar ulong int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t], [ - ext/mysqlnd/php_mysqlnd_config.h - ],[ -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif - ]) fi diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index 13e8c20a15..3d65001382 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -104,7 +104,7 @@ #define MYSQLND_CAPABILITIES (CLIENT_LONG_PASSWORD | CLIENT_LONG_FLAG | CLIENT_TRANSACTIONS | \ CLIENT_PROTOCOL_41 | CLIENT_SECURE_CONNECTION | \ - CLIENT_MULTI_RESULTS | CLIENT_PS_MULTI_RESULTS | CLIENT_LOCAL_FILES | CLIENT_PLUGIN_AUTH) + CLIENT_MULTI_RESULTS | CLIENT_LOCAL_FILES | CLIENT_PLUGIN_AUTH) #define MYSQLND_NET_FLAG_USE_COMPRESSION 1 diff --git a/ext/mysqlnd/mysqlnd_portability.h b/ext/mysqlnd/mysqlnd_portability.h index b9479150ae..72a156a795 100644 --- a/ext/mysqlnd/mysqlnd_portability.h +++ b/ext/mysqlnd/mysqlnd_portability.h @@ -36,8 +36,6 @@ This file is public domain and comes with NO WARRANTY of any kind */ #if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32) # include "ext/mysqlnd/config-win.h" -#else -# include <ext/mysqlnd/php_mysqlnd_config.h> #endif /* _WIN32... */ #if __STDC_VERSION__ < 199901L && !defined(atoll) @@ -45,14 +43,7 @@ This file is public domain and comes with NO WARRANTY of any kind */ #define atoll atol #endif - -#ifdef HAVE_SYS_TYPES_H -#include <sys/types.h> -#endif - -#ifdef HAVE_STDINT_H -#include <stdint.h> -#endif +#include "php_stdint.h" #if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG) #define _LONG_LONG 1 /* For AIX string library */ @@ -70,102 +61,6 @@ This file is public domain and comes with NO WARRANTY of any kind */ #define HAVE_LONG_LONG 1 #endif - -/* Typdefs for easyier portability */ -#ifndef HAVE_INT8_T -#ifndef HAVE_INT8 -typedef signed char int8_t; /* Signed integer >= 8 bits */ -#else -typedef int8 int8_t; /* Signed integer >= 8 bits */ -#endif -#endif - -#ifndef HAVE_UINT8_T -#ifndef HAVE_UINT8 -typedef unsigned char uint8_t; /* Unsigned integer >= 8 bits */ -#else -typedef uint8 uint8_t; /* Signed integer >= 8 bits */ -#endif -#endif - -#ifndef HAVE_INT16_T -#ifndef HAVE_INT16 -typedef signed short int16_t; /* Signed integer >= 16 bits */ -#else -typedef int16 int16_t; /* Signed integer >= 16 bits */ -#endif -#endif - -#ifndef HAVE_UINT16_T -#ifndef HAVE_UINT16 -typedef unsigned short uint16_t; /* Signed integer >= 16 bits */ -#else -typedef uint16 uint16_t; /* Signed integer >= 16 bits */ -#endif -#endif - - -#ifndef HAVE_INT32_T -#ifdef HAVE_INT32 -typedef int32 int32_t; -#elif SIZEOF_INT == 4 -typedef signed int int32_t; -#elif SIZEOF_LONG == 4 -typedef signed long int32_t; -#else -error "Neither int nor long is of 4 bytes width" -#endif -#endif /* HAVE_INT32_T */ - -#ifndef HAVE_UINT32_T -#ifdef HAVE_UINT32 -typedef uint32 uint32_t; -#elif SIZEOF_INT == 4 -typedef unsigned int uint32_t; -#elif SIZEOF_LONG == 4 -typedef unsigned long uint32_t; -#else -#error "Neither int nor long is of 4 bytes width" -#endif -#endif /* HAVE_UINT32_T */ - -#ifndef HAVE_INT64_T -#ifdef HAVE_INT64 -typedef int64 int64_t; -#elif SIZEOF_INT == 8 -typedef signed int int64_t; -#elif SIZEOF_LONG == 8 -typedef signed long int64_t; -#elif SIZEOF_LONG_LONG == 8 -#ifdef PHP_WIN32 -typedef __int64 int64_t; -#else -typedef signed long long int64_t; -#endif -#else -#error "Neither int nor long nor long long is of 8 bytes width" -#endif -#endif /* HAVE_INT64_T */ - -#ifndef HAVE_UINT64_T -#ifdef HAVE_UINT64 -typedef uint64 uint64_t; -#elif SIZEOF_INT == 8 -typedef unsigned int uint64_t; -#elif SIZEOF_LONG == 8 -typedef unsigned long uint64_t; -#elif SIZEOF_LONG_LONG == 8 -#ifdef PHP_WIN32 -typedef unsigned __int64 uint64_t; -#else -typedef unsigned long long uint64_t; -#endif -#else -#error "Neither int nor long nor long long is of 8 bytes width" -#endif -#endif /* HAVE_INT64_T */ - - #ifdef PHP_WIN32 #define MYSQLND_LLU_SPEC "%I64u" #define MYSQLND_LL_SPEC "%I64d" diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index d0e44fa275..d96a57721c 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -516,68 +516,70 @@ mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count, /* }}} */ -/* {{{ mysqlnd_stmt_execute_store_params */ -static enum_func_status -mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC) +/* {{{ mysqlnd_stmt_free_copies */ +static void +mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval ** copies TSRMLS_DC) { - MYSQLND_STMT_DATA * stmt = s->data; - unsigned int i = 0; - zend_uchar * provided_buffer = *buf; - size_t left = (*buf_len - (*p - *buf)); - size_t data_size = 0; - zval **copies = NULL;/* if there are different types */ - enum_func_status ret = FAIL; - int resend_types_next_time = 0; - size_t null_byte_offset; + if (copies) { + unsigned int i; + for (i = 0; i < stmt->param_count; i++) { + if (copies[i]) { + zval_ptr_dtor(&copies[i]); + } + } + mnd_efree(copies); + } +} +/* }}} */ - DBG_ENTER("mysqlnd_stmt_execute_store_params"); - { - unsigned int null_count = (stmt->param_count + 7) / 8; - /* give it some reserved space - 20 bytes */ - if (left < (null_count + 20)) { - unsigned int offset = *p - *buf; - zend_uchar *tmp_buf; - *buf_len = offset + null_count + 20; - tmp_buf = mnd_emalloc(*buf_len); - if (!tmp_buf) { - SET_OOM_ERROR(*stmt->error_info); - goto end; - } - memcpy(tmp_buf, *buf, offset); - if (*buf != provided_buffer) { - mnd_efree(*buf); - } - *buf = tmp_buf; +/* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */ +static enum_func_status +mysqlnd_stmt_execute_check_n_enlarge_buffer(zend_uchar **buf, zend_uchar **p, size_t * buf_len, zend_uchar * const provided_buffer, size_t needed_bytes TSRMLS_DC) +{ + const size_t overalloc = 5; + size_t left = (*buf_len - (*p - *buf)); - /* Update our pos pointer */ - *p = *buf + offset; + if (left < (needed_bytes + overalloc)) { + size_t offset = *p - *buf; + zend_uchar *tmp_buf; + *buf_len = offset + needed_bytes + overalloc; + tmp_buf = mnd_emalloc(*buf_len); + if (!tmp_buf) { + return FAIL; } - /* put `null` bytes */ - null_byte_offset = *p - *buf; - memset(*p, 0, null_count); - *p += null_count; + memcpy(tmp_buf, *buf, offset); + if (*buf != provided_buffer) { + mnd_efree(*buf); + } + *buf = tmp_buf; + /* Update our pos pointer */ + *p = *buf + offset; } + return PASS; +} +/* }}} */ - left = (*buf_len - (*p - *buf)); -/* 1. Store type information */ - /* - check if need to send the types even if stmt->send_types_to_server is 0. This is because - if we send "i" (42) then the type will be int and the server will expect int. However, if next - time we try to send > LONG_MAX, the conversion to string will send a string and the server - won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values - occur, and force resend for the next execution. - */ + +/* {{{ mysqlnd_stmt_execute_prepare_param_types */ +static enum_func_status +mysqlnd_stmt_execute_prepare_param_types(MYSQLND_STMT_DATA * stmt, zval *** copies_param, int * resend_types_next_time TSRMLS_DC) +{ + unsigned int i; + DBG_ENTER("mysqlnd_stmt_execute_prepare_param_types"); for (i = 0; i < stmt->param_count; i++) { short current_type = stmt->param_bind[i].type; + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + zval ** copies; /* always copy the var, because we do many conversions */ if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG && - PASS != mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC)) + PASS != mysqlnd_stmt_copy_it(copies_param, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } + copies = *copies_param; /* if it doesn't fit in a long send it as a string. Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX @@ -602,7 +604,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar We do transformation here, which will be used later when sending types. The code later relies on this. */ if (Z_DVAL_P(tmp_data_copy) > LONG_MAX || Z_DVAL_P(tmp_data_copy) < LONG_MIN) { - stmt->send_types_to_server = resend_types_next_time = 1; + stmt->send_types_to_server = *resend_types_next_time = 1; convert_to_string_ex(&tmp_data); } else { convert_to_long_ex(&tmp_data); @@ -612,69 +614,63 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } } } + DBG_RETURN(PASS); +end: + DBG_RETURN(FAIL); +} +/* }}} */ - int1store(*p, stmt->send_types_to_server); - (*p)++; - - if (stmt->send_types_to_server) { - /* 2 bytes per type, and leave 20 bytes for future use */ - if (left < ((stmt->param_count * 2) + 20)) { - unsigned int offset = *p - *buf; - zend_uchar *tmp_buf; - *buf_len = offset + stmt->param_count * 2 + 20; - tmp_buf = mnd_emalloc(*buf_len); - if (!tmp_buf) { - SET_OOM_ERROR(*stmt->error_info); - goto end; - } - memcpy(tmp_buf, *buf, offset); - if (*buf != provided_buffer) { - mnd_efree(*buf); - } - *buf = tmp_buf; - /* Update our pos pointer */ - *p = *buf + offset; - } - for (i = 0; i < stmt->param_count; i++) { - short current_type = stmt->param_bind[i].type; - /* our types are not unsigned */ +/* {{{ mysqlnd_stmt_execute_store_types */ +static void +mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar ** p) +{ + unsigned int i; + for (i = 0; i < stmt->param_count; i++) { + short current_type = stmt->param_bind[i].type; + /* our types are not unsigned */ #if SIZEOF_LONG==8 - if (current_type == MYSQL_TYPE_LONG) { - current_type = MYSQL_TYPE_LONGLONG; - } + if (current_type == MYSQL_TYPE_LONG) { + current_type = MYSQL_TYPE_LONGLONG; + } #endif - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + /* + if it doesn't fit in a long send it as a string. + Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX + */ + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { + const zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; /* - if it doesn't fit in a long send it as a string. - Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX + In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type. + The actual transformation has been performed several dozens line above. */ - if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { - zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + if (Z_TYPE_P(tmp_data) == IS_STRING) { + current_type = MYSQL_TYPE_VAR_STRING; /* - In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type. - The actual transformation has been performed several dozens line above. + don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING + we force convert_to_long_ex in all cases, thus the type will be right in the next switch. + if the type is however not long, then we will do a goto in the next switch. + We want to preserve the original bind type given by the user. Thus, we do these hacks. */ - if (Z_TYPE_P(tmp_data) == IS_STRING) { - current_type = MYSQL_TYPE_VAR_STRING; - /* - don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING - we force convert_to_long_ex in all cases, thus the type will be right in the next switch. - if the type is however not long, then we will do a goto in the next switch. - We want to preserve the original bind type given by the user. Thus, we do these hacks. - */ - } } } - int2store(*p, current_type); - *p+= 2; } + int2store(*p, current_type); + *p+= 2; } - stmt->send_types_to_server = resend_types_next_time; +} +/* }}} */ -/* 2. Store data */ - /* 2.1 Calculate how much space we need */ + +/* {{{ mysqlnd_stmt_execute_calculate_param_values_size */ +static enum_func_status +mysqlnd_stmt_execute_calculate_param_values_size(MYSQLND_STMT_DATA * stmt, zval *** copies_param, size_t * data_size TSRMLS_DC) +{ + unsigned int i; + DBG_ENTER("mysqlnd_stmt_execute_calculate_param_values_size"); for (i = 0; i < stmt->param_count; i++) { + unsigned short is_longlong = 0; unsigned int j; zval *the_var = stmt->param_bind[i].zv; @@ -684,22 +680,22 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar for (j = i + 1; j < stmt->param_count; j++) { if (stmt->param_bind[j].zv == the_var) { /* Double binding of the same zval, make a copy */ - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + if (!*copies_param || !(*copies_param)[i]) { + if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } } - break; + break; } } switch (stmt->param_bind[i].type) { case MYSQL_TYPE_DOUBLE: - data_size += 8; + *data_size += 8; if (Z_TYPE_P(the_var) != IS_DOUBLE) { - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + if (!*copies_param || !(*copies_param)[i]) { + if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } @@ -707,24 +703,17 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } break; case MYSQL_TYPE_LONGLONG: - { - zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; - if (Z_TYPE_P(tmp_data) == IS_STRING) { - goto use_string; - } - convert_to_long_ex(&tmp_data); - } - data_size += 8; - break; + is_longlong = 4; + /* fall-through */ case MYSQL_TYPE_LONG: { - zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + zval *tmp_data = (*copies_param && (*copies_param)[i])? (*copies_param)[i]: stmt->param_bind[i].zv; if (Z_TYPE_P(tmp_data) == IS_STRING) { goto use_string; } convert_to_long_ex(&tmp_data); } - data_size += 4; + *data_size += 4 + is_longlong; break; case MYSQL_TYPE_LONG_BLOB: if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) { @@ -733,58 +722,43 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar Empty string has length of 0, encoded in 1 byte. No real data will follows after it. */ - data_size++; + (*data_size)++; } break; case MYSQL_TYPE_VAR_STRING: use_string: - data_size += 8; /* max 8 bytes for size */ + *data_size += 8; /* max 8 bytes for size */ if (Z_TYPE_P(the_var) != IS_STRING) { - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + if (!*copies_param || !(*copies_param)[i]) { + if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) { SET_OOM_ERROR(*stmt->error_info); goto end; } } - the_var = copies[i]; + the_var = (*copies_param)[i]; } convert_to_string_ex(&the_var); - data_size += Z_STRLEN_P(the_var); + *data_size += Z_STRLEN_P(the_var); break; } } + DBG_RETURN(PASS); +end: + DBG_RETURN(FAIL); +} +/* }}} */ - /* 2.2 Enlarge the buffer, if needed */ - left = (*buf_len - (*p - *buf)); - if (left < data_size) { - unsigned int offset = *p - *buf; - zend_uchar *tmp_buf; - *buf_len = offset + data_size + 10; /* Allocate + 10 for safety */ - tmp_buf = mnd_emalloc(*buf_len); - if (!tmp_buf) { - SET_OOM_ERROR(*stmt->error_info); - goto end; - } - memcpy(tmp_buf, *buf, offset); - /* - When too many columns the buffer provided to the function might not be sufficient. - In this case new buffer has been allocated above. When we allocate a buffer and then - allocate a bigger one here, we should free the first one. - */ - if (*buf != provided_buffer) { - mnd_efree(*buf); - } - *buf = tmp_buf; - /* Update our pos pointer */ - *p = *buf + offset; - } - /* 2.3 Store the actual data */ +/* {{{ mysqlnd_stmt_execute_store_param_values */ +static void +mysqlnd_stmt_execute_store_param_values(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar * buf, zend_uchar ** p, size_t null_byte_offset) +{ + unsigned int i; for (i = 0; i < stmt->param_count; i++) { - zval *data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + zval * data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; /* Handle long data */ if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) { - (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); + (buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); } else { switch (stmt->param_bind[i].type) { case MYSQL_TYPE_DOUBLE: @@ -819,7 +793,7 @@ use_string: case MYSQL_TYPE_VAR_STRING: send_string: { - unsigned int len = Z_STRLEN_P(data); + size_t len = Z_STRLEN_P(data); /* to is after p. The latter hasn't been moved */ *p = php_mysqlnd_net_store_length(*p, len); memcpy(*p, Z_STRVAL_P(data), len); @@ -828,22 +802,86 @@ send_string: break; default: /* Won't happen, but set to NULL */ - (*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); + (buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7)); break; } } } - ret = PASS; -end: - if (copies) { - for (i = 0; i < stmt->param_count; i++) { - if (copies[i]) { - zval_ptr_dtor(&copies[i]); - } +} +/* }}} */ + + +/* {{{ mysqlnd_stmt_execute_store_params */ +static enum_func_status +mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC) +{ + MYSQLND_STMT_DATA * stmt = s->data; + unsigned int i = 0; + zend_uchar * provided_buffer = *buf; + size_t data_size = 0; + zval **copies = NULL;/* if there are different types */ + enum_func_status ret = FAIL; + int resend_types_next_time = 0; + size_t null_byte_offset; + + DBG_ENTER("mysqlnd_stmt_execute_store_params"); + + { + unsigned int null_count = (stmt->param_count + 7) / 8; + if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, null_count TSRMLS_CC)) { + SET_OOM_ERROR(*stmt->error_info); + goto end; } - mnd_efree(copies); + /* put `null` bytes */ + null_byte_offset = *p - *buf; + memset(*p, 0, null_count); + *p += null_count; + } + +/* 1. Store type information */ + /* + check if need to send the types even if stmt->send_types_to_server is 0. This is because + if we send "i" (42) then the type will be int and the server will expect int. However, if next + time we try to send > LONG_MAX, the conversion to string will send a string and the server + won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values + occur, and force resend for the next execution. + */ + if (FAIL == mysqlnd_stmt_execute_prepare_param_types(stmt, &copies, &resend_types_next_time TSRMLS_CC)) { + goto end; + } + + int1store(*p, stmt->send_types_to_server); + (*p)++; + + if (stmt->send_types_to_server) { + if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, stmt->param_count * 2 TSRMLS_CC)) { + SET_OOM_ERROR(*stmt->error_info); + goto end; + } + mysqlnd_stmt_execute_store_types(stmt, copies, p); + } + + stmt->send_types_to_server = resend_types_next_time; + +/* 2. Store data */ + /* 2.1 Calculate how much space we need */ + if (FAIL == mysqlnd_stmt_execute_calculate_param_values_size(stmt, &copies, &data_size TSRMLS_CC)) { + goto end; + } + + /* 2.2 Enlarge the buffer, if needed */ + if (FAIL == mysqlnd_stmt_execute_check_n_enlarge_buffer(buf, p, buf_len, provided_buffer, data_size TSRMLS_CC)) { + SET_OOM_ERROR(*stmt->error_info); + goto end; } + /* 2.3 Store the actual data */ + mysqlnd_stmt_execute_store_param_values(stmt, copies, *buf, p, null_byte_offset); + + ret = PASS; +end: + mysqlnd_stmt_free_copies(stmt, copies TSRMLS_CC); + DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL"); DBG_RETURN(ret); } diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index 4bd33592bf..be71d06508 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -302,6 +302,7 @@ PHPAPI void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * c unsigned long php_mysqlnd_net_field_length(zend_uchar **packet); zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length); +size_t php_mysqlnd_net_store_length_size(uint64_t length); PHPAPI const extern char * const mysqlnd_empty_string; |