mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
Backport refactoring from php-src
This commit is contained in:
parent
698b04270e
commit
0c90c207a7
2 changed files with 195 additions and 150 deletions
|
@ -516,68 +516,70 @@ mysqlnd_stmt_copy_it(zval *** copies, zval * original, unsigned int param_count,
|
||||||
/* }}} */
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
/* {{{ mysqlnd_stmt_execute_store_params */
|
/* {{{ mysqlnd_stmt_free_copies */
|
||||||
static enum_func_status
|
static void
|
||||||
mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar **p, size_t *buf_len TSRMLS_DC)
|
mysqlnd_stmt_free_copies(MYSQLND_STMT_DATA * stmt, zval ** copies TSRMLS_DC)
|
||||||
{
|
{
|
||||||
MYSQLND_STMT_DATA * stmt = s->data;
|
if (copies) {
|
||||||
unsigned int i = 0;
|
unsigned int i;
|
||||||
zend_uchar * provided_buffer = *buf;
|
for (i = 0; i < stmt->param_count; i++) {
|
||||||
size_t left = (*buf_len - (*p - *buf));
|
if (copies[i]) {
|
||||||
size_t data_size = 0;
|
zval_ptr_dtor(&copies[i]);
|
||||||
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;
|
|
||||||
/* 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;
|
|
||||||
|
|
||||||
/* Update our pos pointer */
|
|
||||||
*p = *buf + offset;
|
|
||||||
}
|
}
|
||||||
/* put `null` bytes */
|
mnd_efree(copies);
|
||||||
null_byte_offset = *p - *buf;
|
|
||||||
memset(*p, 0, null_count);
|
|
||||||
*p += null_count;
|
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
left = (*buf_len - (*p - *buf));
|
|
||||||
/* 1. Store type information */
|
/* {{{ mysqlnd_stmt_execute_check_n_enlarge_buffer */
|
||||||
/*
|
static enum_func_status
|
||||||
check if need to send the types even if stmt->send_types_to_server is 0. This is because
|
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)
|
||||||
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
|
const size_t overalloc = 5;
|
||||||
won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values
|
size_t left = (*buf_len - (*p - *buf));
|
||||||
occur, and force resend for the next execution.
|
|
||||||
*/
|
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;
|
||||||
|
}
|
||||||
|
memcpy(tmp_buf, *buf, offset);
|
||||||
|
if (*buf != provided_buffer) {
|
||||||
|
mnd_efree(*buf);
|
||||||
|
}
|
||||||
|
*buf = tmp_buf;
|
||||||
|
/* Update our pos pointer */
|
||||||
|
*p = *buf + offset;
|
||||||
|
}
|
||||||
|
return PASS;
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
/* {{{ 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++) {
|
for (i = 0; i < stmt->param_count; i++) {
|
||||||
short current_type = stmt->param_bind[i].type;
|
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)) {
|
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 */
|
/* always copy the var, because we do many conversions */
|
||||||
if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG &&
|
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);
|
SET_OOM_ERROR(*stmt->error_info);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
copies = *copies_param;
|
||||||
/*
|
/*
|
||||||
if it doesn't fit in a long send it as a string.
|
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
|
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.
|
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) {
|
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);
|
convert_to_string_ex(&tmp_data);
|
||||||
} else {
|
} else {
|
||||||
convert_to_long_ex(&tmp_data);
|
convert_to_long_ex(&tmp_data);
|
||||||
|
@ -612,68 +614,61 @@ 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) {
|
/* {{{ mysqlnd_stmt_execute_store_types */
|
||||||
/* 2 bytes per type, and leave 20 bytes for future use */
|
static void
|
||||||
if (left < ((stmt->param_count * 2) + 20)) {
|
mysqlnd_stmt_execute_store_types(MYSQLND_STMT_DATA * stmt, zval ** copies, zend_uchar ** p)
|
||||||
unsigned int offset = *p - *buf;
|
{
|
||||||
zend_uchar *tmp_buf;
|
unsigned int i;
|
||||||
*buf_len = offset + stmt->param_count * 2 + 20;
|
for (i = 0; i < stmt->param_count; i++) {
|
||||||
tmp_buf = mnd_emalloc(*buf_len);
|
short current_type = stmt->param_bind[i].type;
|
||||||
if (!tmp_buf) {
|
/* our types are not unsigned */
|
||||||
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 */
|
|
||||||
#if SIZEOF_LONG==8
|
#if SIZEOF_LONG==8
|
||||||
if (current_type == MYSQL_TYPE_LONG) {
|
if (current_type == MYSQL_TYPE_LONG) {
|
||||||
current_type = MYSQL_TYPE_LONGLONG;
|
current_type = MYSQL_TYPE_LONGLONG;
|
||||||
}
|
}
|
||||||
#endif
|
#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.
|
In case of IS_LONG we do nothing, it is ok, in case of string, we just need to set current_type.
|
||||||
Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX
|
The actual transformation has been performed several dozens line above.
|
||||||
*/
|
*/
|
||||||
if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
|
if (Z_TYPE_P(tmp_data) == IS_STRING) {
|
||||||
zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
|
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.
|
don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
|
||||||
The actual transformation has been performed several dozens line above.
|
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++) {
|
for (i = 0; i < stmt->param_count; i++) {
|
||||||
unsigned int j;
|
unsigned int j;
|
||||||
zval *the_var = stmt->param_bind[i].zv;
|
zval *the_var = stmt->param_bind[i].zv;
|
||||||
|
@ -684,8 +679,8 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||||
for (j = i + 1; j < stmt->param_count; j++) {
|
for (j = i + 1; j < stmt->param_count; j++) {
|
||||||
if (stmt->param_bind[j].zv == the_var) {
|
if (stmt->param_bind[j].zv == the_var) {
|
||||||
/* Double binding of the same zval, make a copy */
|
/* Double binding of the same zval, make a copy */
|
||||||
if (!copies || !copies[i]) {
|
if (!*copies_param || !(*copies_param)[i]) {
|
||||||
if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
|
if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) {
|
||||||
SET_OOM_ERROR(*stmt->error_info);
|
SET_OOM_ERROR(*stmt->error_info);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -696,10 +691,10 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||||
|
|
||||||
switch (stmt->param_bind[i].type) {
|
switch (stmt->param_bind[i].type) {
|
||||||
case MYSQL_TYPE_DOUBLE:
|
case MYSQL_TYPE_DOUBLE:
|
||||||
data_size += 8;
|
*data_size += 8;
|
||||||
if (Z_TYPE_P(the_var) != IS_DOUBLE) {
|
if (Z_TYPE_P(the_var) != IS_DOUBLE) {
|
||||||
if (!copies || !copies[i]) {
|
if (!*copies_param || !(*copies_param)[i]) {
|
||||||
if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
|
if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) {
|
||||||
SET_OOM_ERROR(*stmt->error_info);
|
SET_OOM_ERROR(*stmt->error_info);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
|
@ -708,23 +703,23 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_LONGLONG:
|
case MYSQL_TYPE_LONGLONG:
|
||||||
{
|
{
|
||||||
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) {
|
if (Z_TYPE_P(tmp_data) == IS_STRING) {
|
||||||
goto use_string;
|
goto use_string;
|
||||||
}
|
}
|
||||||
convert_to_long_ex(&tmp_data);
|
convert_to_long_ex(&tmp_data);
|
||||||
}
|
}
|
||||||
data_size += 8;
|
*data_size += 8;
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_LONG:
|
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) {
|
if (Z_TYPE_P(tmp_data) == IS_STRING) {
|
||||||
goto use_string;
|
goto use_string;
|
||||||
}
|
}
|
||||||
convert_to_long_ex(&tmp_data);
|
convert_to_long_ex(&tmp_data);
|
||||||
}
|
}
|
||||||
data_size += 4;
|
*data_size += 4;
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_LONG_BLOB:
|
case MYSQL_TYPE_LONG_BLOB:
|
||||||
if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
|
if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
|
||||||
|
@ -733,58 +728,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
|
Empty string has length of 0, encoded in 1 byte. No real
|
||||||
data will follows after it.
|
data will follows after it.
|
||||||
*/
|
*/
|
||||||
data_size++;
|
(*data_size)++;
|
||||||
}
|
}
|
||||||
break;
|
break;
|
||||||
case MYSQL_TYPE_VAR_STRING:
|
case MYSQL_TYPE_VAR_STRING:
|
||||||
use_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 (Z_TYPE_P(the_var) != IS_STRING) {
|
||||||
if (!copies || !copies[i]) {
|
if (!*copies_param || !(*copies_param)[i]) {
|
||||||
if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) {
|
if (PASS != mysqlnd_stmt_copy_it(copies_param, the_var, stmt->param_count, i TSRMLS_CC)) {
|
||||||
SET_OOM_ERROR(*stmt->error_info);
|
SET_OOM_ERROR(*stmt->error_info);
|
||||||
goto end;
|
goto end;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
the_var = copies[i];
|
the_var = (*copies_param)[i];
|
||||||
}
|
}
|
||||||
convert_to_string_ex(&the_var);
|
convert_to_string_ex(&the_var);
|
||||||
data_size += Z_STRLEN_P(the_var);
|
*data_size += Z_STRLEN_P(the_var);
|
||||||
break;
|
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++) {
|
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 */
|
/* Handle long data */
|
||||||
if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) {
|
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 {
|
} else {
|
||||||
switch (stmt->param_bind[i].type) {
|
switch (stmt->param_bind[i].type) {
|
||||||
case MYSQL_TYPE_DOUBLE:
|
case MYSQL_TYPE_DOUBLE:
|
||||||
|
@ -819,7 +799,7 @@ use_string:
|
||||||
case MYSQL_TYPE_VAR_STRING:
|
case MYSQL_TYPE_VAR_STRING:
|
||||||
send_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 */
|
/* to is after p. The latter hasn't been moved */
|
||||||
*p = php_mysqlnd_net_store_length(*p, len);
|
*p = php_mysqlnd_net_store_length(*p, len);
|
||||||
memcpy(*p, Z_STRVAL_P(data), len);
|
memcpy(*p, Z_STRVAL_P(data), len);
|
||||||
|
@ -828,21 +808,85 @@ send_string:
|
||||||
break;
|
break;
|
||||||
default:
|
default:
|
||||||
/* Won't happen, but set to NULL */
|
/* 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;
|
break;
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
}
|
}
|
||||||
|
}
|
||||||
|
/* }}} */
|
||||||
|
|
||||||
|
|
||||||
|
/* {{{ 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;
|
||||||
|
}
|
||||||
|
/* 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;
|
ret = PASS;
|
||||||
end:
|
end:
|
||||||
if (copies) {
|
mysqlnd_stmt_free_copies(stmt, copies TSRMLS_CC);
|
||||||
for (i = 0; i < stmt->param_count; i++) {
|
|
||||||
if (copies[i]) {
|
|
||||||
zval_ptr_dtor(&copies[i]);
|
|
||||||
}
|
|
||||||
}
|
|
||||||
mnd_efree(copies);
|
|
||||||
}
|
|
||||||
|
|
||||||
DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
|
DBG_INF_FMT("ret=%s", ret == PASS? "PASS":"FAIL");
|
||||||
DBG_RETURN(ret);
|
DBG_RETURN(ret);
|
||||||
|
|
|
@ -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);
|
unsigned long php_mysqlnd_net_field_length(zend_uchar **packet);
|
||||||
zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, uint64_t length);
|
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;
|
PHPAPI const extern char * const mysqlnd_empty_string;
|
||||||
|
|
||||||
|
|
Loading…
Add table
Add a link
Reference in a new issue