switch (stmt->stmt->params[i].buffer_type) {
case MYSQL_TYPE_VAR_STRING:
if (UG(unicode) && Z_TYPE_P(the_var) == IS_UNICODE) {
- php_mysqli_stmt_copy_it(&copies, stmt->param.vars[i], stmt->param.var_cnt, i);
- the_var = copies[i];
+ if (the_var == stmt->param.vars[i]) {
+ php_mysqli_stmt_copy_it(&copies, stmt->param.vars[i], stmt->param.var_cnt, i);
+ the_var = copies[i];
+ }
zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC);
} else {
if (the_var == stmt->param.vars[i] && Z_TYPE_P(stmt->param.vars[i]) != IS_STRING) {
--- /dev/null
+--TEST--
+mysqli_stmt_bind_param() - checking whether the parameters are modified (bug#44390)
+--SKIPIF--
+<?php
+require_once('skipif.inc');
+require_once('skipifemb.inc');
+require_once('skipifconnectfailure.inc');
+?>
+--FILE--
+<?php
+ include "connect.inc";
+ require('table.inc');
+
+ class foo {
+ // @var $bar string
+ public $bar;
+ }
+
+ $foo = new foo;
+ $foo->bar = "фубар";
+
+ echo "Test 1: \n";
+ $stmt = $link->prepare("SELECT ? FOO");
+ var_dump($foo); // here you can see the bar member var beeing a string
+ $stmt->bind_param("s", $foo->bar);
+ var_dump($foo); // this will show $foo->bar beeing a reference string
+ $stmt->bind_result($one);
+ $stmt->execute();
+ $stmt->fetch();
+ $stmt->free_result();
+ echo("$one\n\n");
+
+ // it is getting worse. Binding the same var twice with different
+ // types you can get unexpected results (e.g. binary trash for the
+ // string and misc data for the integer. See next 2 tests.
+
+ echo "Test 2: \n";
+ $stmt = $link->prepare("SELECT ? FOO, ? BAR");
+ var_dump($foo);
+ $stmt->bind_param("si", $foo->bar, $foo->bar);
+ echo "---\n";
+ var_dump($foo);
+ echo "---\n";
+ $stmt->execute();
+ var_dump($foo);
+ echo "---\n";
+ $stmt->bind_result($one, $two);
+ $stmt->fetch();
+ $stmt->free_result();
+ echo("$one - $two\n\n");
+
+
+ echo "Test 3: \n";
+ $stmt = $link->prepare("SELECT ? FOO, ? BAR");
+ var_dump($foo);
+ $stmt->bind_param("is", $foo->bar, $foo->bar);
+ var_dump($foo);
+ $stmt->bind_result($one, $two);
+ $stmt->execute();
+ $stmt->fetch();
+ $stmt->free_result();
+ echo("$one - $two\n\n");
+ echo "done!\n";
+?>
+--EXPECTF--
+Test 1:
+object(foo)#3 (1) {
+ ["bar"]=>
+ string(10) "фубар"
+}
+object(foo)#3 (1) {
+ ["bar"]=>
+ &string(10) "фубар"
+}
+фубар
+
+Test 2:
+object(foo)#3 (1) {
+ ["bar"]=>
+ string(10) "фубар"
+}
+---
+object(foo)#3 (1) {
+ ["bar"]=>
+ &string(10) "фубар"
+}
+---
+object(foo)#3 (1) {
+ ["bar"]=>
+ &string(10) "фубар"
+}
+---
+фубар - 0
+
+Test 3:
+object(foo)#3 (1) {
+ ["bar"]=>
+ string(10) "фубар"
+}
+object(foo)#3 (1) {
+ ["bar"]=>
+ &string(10) "фубар"
+}
+0 - фубар
+
+done!
+--UEXPECTF--
+Test 1:
+object(foo)#3 (1) {
+ [u"bar"]=>
+ unicode(5) "фубар"
+}
+object(foo)#3 (1) {
+ [u"bar"]=>
+ &unicode(5) "фубар"
+}
+фубар
+
+Test 2:
+object(foo)#3 (1) {
+ [u"bar"]=>
+ unicode(5) "фубар"
+}
+---
+object(foo)#3 (1) {
+ [u"bar"]=>
+ &unicode(5) "фубар"
+}
+---
+object(foo)#3 (1) {
+ [u"bar"]=>
+ &unicode(5) "фубар"
+}
+---
+фубар - 0
+
+Test 3:
+object(foo)#3 (1) {
+ [u"bar"]=>
+ unicode(5) "фубар"
+}
+object(foo)#3 (1) {
+ [u"bar"]=>
+ &unicode(5) "фубар"
+}
+0 - фубар
+
+done!
*p = php_mysqlnd_net_store_length(*p, 0);
}
break;
- case MYSQL_TYPE_VAR_STRING:
- /*
- If the user uses refs, it could be that the type has
- has changed and we need to convert, again. Which is noop,
- if the type hasn't changed.
- */
- convert_to_string_ex(&stmt->param_bind[i].zv);
- {
+ case MYSQL_TYPE_VAR_STRING:{
unsigned int len = Z_STRLEN_P(data);
/* to is after p. The latter hasn't been moved */
*p = php_mysqlnd_net_store_length(*p, len);