mirror of
https://github.com/php/php-src.git
synced 2024-09-22 10:27:25 +00:00
Merge branch 'PHP-5.5' into PHP-5.6
* PHP-5.5: fixed test And here is the real fix for #66124 Fix for Bug #66124 (mysqli under mysqlnd loses precision when bind_param with 'i')
This commit is contained in:
commit
696d286911
101
ext/mysqli/tests/bug66124.phpt
Normal file
101
ext/mysqli/tests/bug66124.phpt
Normal file
@ -0,0 +1,101 @@
|
||||
--TEST--
|
||||
Bug #66124 (mysqli under mysqlnd loses precision when bind_param with 'i')
|
||||
--SKIPIF--
|
||||
<?php
|
||||
require_once('skipif.inc');
|
||||
require_once('connect.inc');
|
||||
require_once('skipifconnectfailure.inc');
|
||||
?>
|
||||
--FILE--
|
||||
<?php
|
||||
$table_drop = "DROP TABLE IF EXISTS `bug66124`";
|
||||
$table_create = "CREATE TABLE `bug66124` (
|
||||
`id` bigint(20) unsigned NOT NULL AUTO_INCREMENT,
|
||||
PRIMARY KEY (`id`)
|
||||
) ENGINE=InnoDB DEFAULT CHARSET=utf8";
|
||||
|
||||
$table_insert = "INSERT INTO `bug66124` SET `id`=?";
|
||||
$table_select = "SELECT * FROM `bug66124`";
|
||||
$table_delete = "DELETE FROM `bug66124`";
|
||||
$id = '1311200011005001566';
|
||||
|
||||
|
||||
require_once('connect.inc');
|
||||
|
||||
if (!$link = my_mysqli_connect($host, $user, $passwd, $db, $port, $socket)) {
|
||||
printf("Cannot connect to the server using host=%s, user=%s, passwd=***, dbname=%s, port=%s, socket=%s\n",
|
||||
$host, $user, $db, $port, $socket);
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$link->query($table_drop);
|
||||
$link->query($table_create);
|
||||
|
||||
$stmt = $link->prepare($table_insert);
|
||||
if (!$stmt) {
|
||||
printf("Can't prepare\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
echo "Using 'i':\n";
|
||||
$stmt->bind_param('i', $id);
|
||||
|
||||
if ($stmt->execute()){
|
||||
echo "insert id:{$id}=>{$stmt->insert_id}\n";
|
||||
} else {
|
||||
printf("Can't execute\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
|
||||
$result = $link->query($table_select);
|
||||
|
||||
if ($result){
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
echo "fetch id:{$row['id']}\n";
|
||||
}
|
||||
} else {
|
||||
printf("Can't select\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$stmt->close();
|
||||
|
||||
$link->query($table_drop);
|
||||
$link->query($table_create);
|
||||
|
||||
|
||||
$stmt = $link->prepare($table_insert);
|
||||
$stmt->bind_param('s', $id);
|
||||
|
||||
echo "Using 's':\n";
|
||||
|
||||
if ($stmt->execute()){
|
||||
echo "insert id:{$id}\n";
|
||||
} else{
|
||||
printf("Can't execute\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$result = $link->query($table_select);
|
||||
|
||||
if ($result){
|
||||
while ($row = $result->fetch_assoc()) {
|
||||
echo "fetch id:{$row['id']}\n";
|
||||
}
|
||||
} else {
|
||||
printf("Can't select\n");
|
||||
exit(1);
|
||||
}
|
||||
|
||||
$link->close();
|
||||
?>
|
||||
done
|
||||
--EXPECTF--
|
||||
Using 'i':
|
||||
insert id:1311200011005001566=>1311200011005001566
|
||||
fetch id:1311200011005001566
|
||||
Using 's':
|
||||
insert id:1311200011005001566
|
||||
fetch id:1311200011005001566
|
||||
done
|
@ -569,9 +569,8 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||
occur, and force resend for the next execution.
|
||||
*/
|
||||
for (i = 0; i < stmt->param_count; i++) {
|
||||
if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL &&
|
||||
(stmt->param_bind[i].type == MYSQL_TYPE_LONG || stmt->param_bind[i].type == MYSQL_TYPE_LONGLONG))
|
||||
{
|
||||
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)) {
|
||||
/* 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))
|
||||
@ -585,10 +584,31 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||
*/
|
||||
if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
|
||||
zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
|
||||
convert_to_double_ex(&tmp_data);
|
||||
if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) {
|
||||
/*
|
||||
Because converting to double and back to long can lead
|
||||
to losing precision we need second variable. Conversion to double is to see if
|
||||
value is too big for a long. As said, precision could be lost.
|
||||
*/
|
||||
zval *tmp_data_copy;
|
||||
MAKE_STD_ZVAL(tmp_data_copy);
|
||||
*tmp_data_copy = *tmp_data;
|
||||
Z_SET_REFCOUNT_P(tmp_data_copy, 1);
|
||||
zval_copy_ctor(tmp_data_copy);
|
||||
convert_to_double_ex(&tmp_data_copy);
|
||||
|
||||
/*
|
||||
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
|
||||
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;
|
||||
convert_to_string_ex(&tmp_data);
|
||||
} else {
|
||||
convert_to_long_ex(&tmp_data);
|
||||
}
|
||||
|
||||
zval_ptr_dtor(&tmp_data_copy);
|
||||
}
|
||||
}
|
||||
}
|
||||
@ -631,10 +651,11 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||
*/
|
||||
if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) {
|
||||
zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv;
|
||||
|
||||
convert_to_double_ex(&tmp_data);
|
||||
if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) {
|
||||
convert_to_string_ex(&tmp_data);
|
||||
/*
|
||||
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(tmp_data) == IS_STRING) {
|
||||
current_type = MYSQL_TYPE_VAR_STRING;
|
||||
/*
|
||||
don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING
|
||||
@ -642,8 +663,6 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar
|
||||
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.
|
||||
*/
|
||||
} else {
|
||||
convert_to_long_ex(&tmp_data);
|
||||
}
|
||||
}
|
||||
}
|
||||
|
@ -43,7 +43,7 @@ echo "Done";
|
||||
*** Testing unserialize() error/boolean distinction ***
|
||||
string(4) "b:0;"
|
||||
|
||||
Notice: unserialize(): Error at offset 0 of 27 bytes in %s/serialization_error_002.php on line 20
|
||||
Notice: unserialize(): Error at offset 0 of 27 bytes in %s%eserialization_error_002.php on line 20
|
||||
bool(false)
|
||||
bool(false)
|
||||
unserialize error and deserialized false are identical? 1
|
||||
|
Loading…
Reference in New Issue
Block a user