andrey Thu Mar 20 14:03:30 2008 UTC
Added files: (Branch: PHP_5_3)
/php-src/ext/mysqli/tests mysqli_stmt_datatype_change.phpt
Modified files:
/php-src/ext/mysqli mysqli_api.c
/php-src/ext/mysqlnd mysqlnd.c mysqlnd_ps.c mysqlnd_ps_codec.c
Log:
- Don't modify the variables which are passed for parameter binding.
We need to clone them, if there will be a transformation (convert_to_xxx)
which will change the origin
(bug#44390 bind_param / bind_result and Object member variables)
- Make mysqlnd more compatible to libmysql, in this case if the execute of
a statement fails set the state of the statement back to PREPARED
- A test case to check the case of a failing statement.
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqli/mysqli_api.c?r1=1.118.2.22.2.16.2.14&r2=1.118.2.22.2.16.2.15&diff_format=u
Index: php-src/ext/mysqli/mysqli_api.c
diff -u php-src/ext/mysqli/mysqli_api.c:1.118.2.22.2.16.2.14
php-src/ext/mysqli/mysqli_api.c:1.118.2.22.2.16.2.15
--- php-src/ext/mysqli/mysqli_api.c:1.118.2.22.2.16.2.14 Mon Mar 10
20:15:38 2008
+++ php-src/ext/mysqli/mysqli_api.c Thu Mar 20 14:03:29 2008
@@ -17,7 +17,7 @@
| Ulf Wendel <[EMAIL PROTECTED]>
|
+----------------------------------------------------------------------+
- $Id: mysqli_api.c,v 1.118.2.22.2.16.2.14 2008/03/10 20:15:38 andrey Exp $
+ $Id: mysqli_api.c,v 1.118.2.22.2.16.2.15 2008/03/20 14:03:29 andrey Exp $
*/
#ifdef HAVE_CONFIG_H
@@ -689,6 +689,22 @@
}
/* }}} */
+#ifndef MYSQLI_USE_MYSQLND
+/* {{{ php_mysqli_stmt_copy_it */
+static void
+php_mysqli_stmt_copy_it(zval *** copies, zval *original, uint param_count,
uint current)
+{
+ if (!*copies) {
+ *copies = ecalloc(param_count, sizeof(zval *));
+ }
+ MAKE_STD_ZVAL((*copies)[current]);
+ *(*copies)[current] = *original;
+ Z_SET_REFCOUNT_P((*copies)[current], 1);
+ zval_copy_ctor((*copies)[current]);
+}
+/* }}} */
+#endif
+
/* {{{ proto bool mysqli_stmt_execute(object stmt)
Execute a prepared statement */
PHP_FUNCTION(mysqli_stmt_execute)
@@ -697,6 +713,7 @@
zval *mysql_stmt;
#ifndef MYSQLI_USE_MYSQLND
unsigned int i;
+ zval **copies = NULL;
#endif
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(),
"O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
@@ -705,23 +722,48 @@
MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt",
MYSQLI_STATUS_VALID);
#ifndef MYSQLI_USE_MYSQLND
+ if (stmt->param.var_cnt) {
+ int j;
+ for (i = 0; i < stmt->param.var_cnt; i++) {
+ for (j = i + 1; j < stmt->param.var_cnt; j++) {
+ /* Oops, someone binding the same variable -
clone */
+ if (stmt->param.vars[j] == stmt->param.vars[i])
{
+ php_mysqli_stmt_copy_it(&copies,
stmt->param.vars[i], stmt->param.var_cnt, i);
+ break;
+ }
+ }
+ }
+ }
for (i = 0; i < stmt->param.var_cnt; i++) {
if (stmt->param.vars[i]) {
if ( !(stmt->param.is_null[i] =
(stmt->param.vars[i]->type == IS_NULL)) ) {
+ zval *the_var = copies && copies[i]?
copies[i]:stmt->param.vars[i];
switch (stmt->stmt->params[i].buffer_type) {
case MYSQL_TYPE_VAR_STRING:
-
convert_to_string_ex(&stmt->param.vars[i]);
- stmt->stmt->params[i].buffer =
Z_STRVAL_PP(&stmt->param.vars[i]);
-
stmt->stmt->params[i].buffer_length = Z_STRLEN_PP(&stmt->param.vars[i]);
+ if (the_var ==
stmt->param.vars[i] && Z_TYPE_P(stmt->param.vars[i]) != IS_STRING) {
+
php_mysqli_stmt_copy_it(&copies, stmt->param.vars[i], stmt->param.var_cnt, i);
+ the_var = copies[i];
+ }
+ convert_to_string_ex(&the_var);
+ stmt->stmt->params[i].buffer =
Z_STRVAL_P(the_var);
+
stmt->stmt->params[i].buffer_length = Z_STRLEN_P(the_var);
break;
case MYSQL_TYPE_DOUBLE:
-
convert_to_double_ex(&stmt->param.vars[i]);
- stmt->stmt->params[i].buffer =
&Z_LVAL_PP(&stmt->param.vars[i]);
+ if (the_var ==
stmt->param.vars[i] && Z_TYPE_P(stmt->param.vars[i]) != IS_DOUBLE) {
+
php_mysqli_stmt_copy_it(&copies, stmt->param.vars[i], stmt->param.var_cnt, i);
+ the_var = copies[i];
+ }
+ convert_to_double_ex(&the_var);
+ stmt->stmt->params[i].buffer =
&Z_DVAL_P(the_var);
break;
case MYSQL_TYPE_LONGLONG:
case MYSQL_TYPE_LONG:
-
convert_to_long_ex(&stmt->param.vars[i]);
- stmt->stmt->params[i].buffer =
&Z_LVAL_PP(&stmt->param.vars[i]);
+ if (the_var ==
stmt->param.vars[i] && Z_TYPE_P(stmt->param.vars[i]) != IS_LONG) {
+
php_mysqli_stmt_copy_it(&copies, stmt->param.vars[i], stmt->param.var_cnt, i);
+ the_var = copies[i];
+ }
+ convert_to_long_ex(&the_var);
+ stmt->stmt->params[i].buffer =
&Z_LVAL_P(the_var);
break;
default:
break;
@@ -738,6 +780,17 @@
RETVAL_TRUE;
}
+#ifndef MYSQLI_USE_MYSQLND
+ if (copies) {
+ for (i = 0; i < stmt->param.var_cnt; i++) {
+ if (copies[i]) {
+ zval_ptr_dtor(&copies[i]);
+ }
+ }
+ efree(copies);
+ }
+#endif
+
if (MyG(report_mode) & MYSQLI_REPORT_INDEX) {
php_mysqli_report_index(stmt->query,
mysqli_stmt_server_status(stmt->stmt) TSRMLS_CC);
}
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqlnd/mysqlnd.c?r1=1.5.2.16&r2=1.5.2.17&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd.c
diff -u php-src/ext/mysqlnd/mysqlnd.c:1.5.2.16
php-src/ext/mysqlnd/mysqlnd.c:1.5.2.17
--- php-src/ext/mysqlnd/mysqlnd.c:1.5.2.16 Tue Mar 18 16:57:31 2008
+++ php-src/ext/mysqlnd/mysqlnd.c Thu Mar 20 14:03:30 2008
@@ -18,7 +18,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: mysqlnd.c,v 1.5.2.16 2008/03/18 16:57:31 andrey Exp $ */
+/* $Id: mysqlnd.c,v 1.5.2.17 2008/03/20 14:03:30 andrey Exp $ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
@@ -591,6 +591,7 @@
if (hashed_details) {
mnd_efree(hashed_details);
}
+ errcode = CR_CONNECTION_ERROR;
goto err;
}
@@ -748,7 +749,7 @@
conn->net.cmd_buffer.length = 128L*1024L;
conn->net.cmd_buffer.buffer =
mnd_pemalloc(conn->net.cmd_buffer.length, conn->persistent);
- mysqlnd_local_infile_default(conn);
+ mysqlnd_local_infile_default(conn);
{
uint buf_size;
buf_size = MYSQLND_G(net_read_buffer_size); /* this is
long, cast to uint*/
@@ -807,11 +808,12 @@
DBG_ERR_FMT("[%d] %.64s (trying to connect via %s)", errcode,
errstr, conn->scheme);
SET_CLIENT_ERROR(conn->error_info, errcode?
errcode:CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE, errstr);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] %.64s (trying
to connect via %s)", errcode, errstr, conn->scheme);
-
- mnd_efree(errstr);
+ /* no mnd_ since we don't allocate it */
+ efree(errstr);
}
if (conn->scheme) {
- mnd_pefree(conn->scheme, conn->persistent);
+ /* no mnd_ since we don't allocate it */
+ pefree(conn->scheme, conn->persistent);
conn->scheme = NULL;
}
@@ -1315,7 +1317,7 @@
{
enum mysqlnd_connection_state state;
DBG_ENTER("mysqlnd_conn::get_state");
- tsrm_mutex_lock(conn->LOCK_state);
+ tsrm_mutex_lock(conn->LOCK_state);
state = conn->state;
tsrm_mutex_unlock(conn->LOCK_state);
DBG_RETURN(state);
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqlnd/mysqlnd_ps.c?r1=1.3.2.10&r2=1.3.2.11&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd_ps.c
diff -u php-src/ext/mysqlnd/mysqlnd_ps.c:1.3.2.10
php-src/ext/mysqlnd/mysqlnd_ps.c:1.3.2.11
--- php-src/ext/mysqlnd/mysqlnd_ps.c:1.3.2.10 Thu Feb 14 14:50:21 2008
+++ php-src/ext/mysqlnd/mysqlnd_ps.c Thu Mar 20 14:03:30 2008
@@ -18,7 +18,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: mysqlnd_ps.c,v 1.3.2.10 2008/02/14 14:50:21 andrey Exp $ */
+/* $Id: mysqlnd_ps.c,v 1.3.2.11 2008/03/20 14:03:30 andrey Exp $ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
@@ -522,6 +522,7 @@
if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
/* close the statement here, the connection has been
closed */
}
+ stmt->state = MYSQLND_STMT_PREPARED;
} else {
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqlnd/mysqlnd_ps_codec.c?r1=1.3.2.5&r2=1.3.2.6&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd_ps_codec.c
diff -u php-src/ext/mysqlnd/mysqlnd_ps_codec.c:1.3.2.5
php-src/ext/mysqlnd/mysqlnd_ps_codec.c:1.3.2.6
--- php-src/ext/mysqlnd/mysqlnd_ps_codec.c:1.3.2.5 Wed Jan 23 19:11:28 2008
+++ php-src/ext/mysqlnd/mysqlnd_ps_codec.c Thu Mar 20 14:03:30 2008
@@ -18,7 +18,7 @@
+----------------------------------------------------------------------+
*/
-/* $Id: mysqlnd_ps_codec.c,v 1.3.2.5 2008/01/23 19:11:28 andrey Exp $ */
+/* $Id: mysqlnd_ps_codec.c,v 1.3.2.6 2008/03/20 14:03:30 andrey Exp $ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
@@ -650,14 +650,30 @@
/* }}} */
+/* {{{ mysqlnd_stmt_copy_it */
+static void
+mysqlnd_stmt_copy_it(zval *** copies, zval *original, uint param_count, uint
current)
+{
+ if (!*copies) {
+ *copies = ecalloc(param_count, sizeof(zval *));
+ }
+ MAKE_STD_ZVAL((*copies)[current]);
+ *(*copies)[current] = *original;
+ Z_SET_REFCOUNT_P((*copies)[current], 1);
+ zval_copy_ctor((*copies)[current]);
+}
+/* }}} */
+
+
/* {{{ mysqlnd_stmt_execute_store_params */
-void
+static void
mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf,
zend_uchar **p,
size_t
*buf_len, unsigned int null_byte_offset TSRMLS_DC)
{
unsigned int i = 0;
unsigned left = (*buf_len - (*p - *buf));
unsigned int data_size = 0;
+ zval **copies = NULL;/* if there are different types */
/* 1. Store type information */
if (stmt->send_types_to_server) {
@@ -689,26 +705,44 @@
/* 2. Store data */
/* 2.1 Calculate how much space we need */
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) {
continue;
}
+ for (j = i + 1; j < stmt->param_count; j++) {
+ if (stmt->param_bind[j].zv == stmt->param_bind[i].zv) {
+ /* Double binding of the same zval, make a copy
*/
+ mysqlnd_stmt_copy_it(&copies,
stmt->param_bind[i].zv, stmt->param_count, i);
+ break;
+ }
+ }
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 (!copies || !copies[i]) {
+ mysqlnd_stmt_copy_it(&copies,
stmt->param_bind[i].zv, stmt->param_count, i);
+ }
+ }
break;
#if SIZEOF_LONG==8
case MYSQL_TYPE_LONGLONG:
data_size += 8;
- break;
#elif SIZEOF_LONG==4
case MYSQL_TYPE_LONG:
data_size += 4;
- break;
#else
#error "Should not happen"
#endif
+ if (Z_TYPE_P(stmt->param_bind[i].zv) !=
IS_LONG) {
+ if (!copies || !copies[i]) {
+ mysqlnd_stmt_copy_it(&copies,
stmt->param_bind[i].zv, stmt->param_count, i);
+ }
+ }
+ break;
case MYSQL_TYPE_LONG_BLOB:
if (!(stmt->param_bind[i].flags &
MYSQLND_PARAM_BIND_BLOB_USED)) {
/*
@@ -721,8 +755,25 @@
break;
case MYSQL_TYPE_VAR_STRING:
data_size += 8; /* max 8 bytes for size */
- convert_to_string_ex(&stmt->param_bind[i].zv);
- data_size += Z_STRLEN_P(stmt->param_bind[i].zv);
+#if PHP_MAJOR_VERSION < 6
+ if (Z_TYPE_P(stmt->param_bind[i].zv) !=
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))
+#endif
+ {
+ if (!copies || !copies[i]) {
+ mysqlnd_stmt_copy_it(&copies,
stmt->param_bind[i].zv, stmt->param_count, i);
+ }
+ the_var = copies[i];
+#if PHP_MAJOR_VERSION >= 6
+ if (UG(unicode) && Z_TYPE_P(the_var) ==
IS_UNICODE) {
+
zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC);
+ }
+#endif
+ }
+ convert_to_string_ex(&the_var);
+ data_size += Z_STRLEN_P(the_var);
break;
}
@@ -743,7 +794,7 @@
/* 2.3 Store the actual data */
for (i = 0; i < stmt->param_count; i++) {
- zval *data = 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));
@@ -791,7 +842,6 @@
memcpy(*p, Z_STRVAL_P(data),
len);
(*p) += len;
}
-
break;
default:
/* Won't happen, but set to NULL */
@@ -800,6 +850,14 @@
}
}
}
+ if (copies) {
+ for (i = 0; i < stmt->param_count; i++) {
+ if (copies[i]) {
+ zval_ptr_dtor(&copies[i]);
+ }
+ }
+ efree(copies);
+ }
}
/* }}} */
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqli/tests/mysqli_stmt_datatype_change.phpt?view=markup&rev=1.1
Index: php-src/ext/mysqli/tests/mysqli_stmt_datatype_change.phpt
+++ php-src/ext/mysqli/tests/mysqli_stmt_datatype_change.phpt
--TEST--
mysqli_stmt_bind_param() - playing with references
--SKIPIF--
<?php
require_once('skipif.inc');
require_once('skipifemb.inc');
require_once('skipifconnectfailure.inc');
?>
--FILE--
<?php
include "connect.inc";
require('table.inc');
if (!$c1 = 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);
}
if (!$c2 = 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);
}
$c1->query("use $db");
$c2->query("use $db");
$c1->query("drop table if exists type_change");
$c1->query("create table type_change(a int, b char(10))");
$c1->query("insert into type_change values (1, 'one'), (2, 'two')");
$s1 = $c1->prepare("select a from type_change order by a");
var_dump($s1);
var_dump($s1->execute(), $s1->bind_result($col1));
echo "---- Row 1\n";
var_dump($s1->fetch());
var_dump($col1);
echo "---- Row 2\n";
var_dump($s1->fetch());
var_dump($col1);
echo "---- Row 3\n";
var_dump($s1->fetch());
echo "----\n";
echo "ALTER\n";
var_dump($c2->query("alter table type_change drop a"));
var_dump($s1->execute());
var_dump($c1->error);
echo "---- Row 1\n";
var_dump($s1->fetch());
var_dump($col1);
echo "---- Row 2\n";
var_dump($s1->fetch());
var_dump($col1);
echo "---- Row 3\n";
var_dump($s1->fetch());
echo "----\n";
echo "done!";
?>
--EXPECTF--
object(mysqli_stmt)#%d (%d) {
["affected_rows"]=>
int(0)
["insert_id"]=>
int(0)
["num_rows"]=>
int(0)
["param_count"]=>
int(0)
["field_count"]=>
int(1)
["errno"]=>
int(0)
["error"]=>
string(0) ""
["sqlstate"]=>
string(5) "00000"
["id"]=>
int(1)
}
bool(true)
bool(true)
---- Row 1
bool(true)
int(1)
---- Row 2
bool(true)
int(2)
---- Row 3
NULL
----
ALTER
bool(true)
bool(false)
string(34) "Unknown column 'a' in 'field list'"
---- Row 1
bool(false)
int(2)
---- Row 2
bool(false)
int(2)
---- Row 3
bool(false)
----
done!
--UEXPECTF--
object(mysqli_stmt)#%d (%d) {
[u"affected_rows"]=>
int(0)
[u"insert_id"]=>
int(0)
[u"num_rows"]=>
int(0)
[u"param_count"]=>
int(0)
[u"field_count"]=>
int(1)
[u"errno"]=>
int(0)
[u"error"]=>
unicode(0) ""
[u"sqlstate"]=>
unicode(5) "00000"
[u"id"]=>
int(1)
}
bool(true)
bool(true)
---- Row 1
bool(true)
int(1)
---- Row 2
bool(true)
int(2)
---- Row 3
NULL
----
ALTER
bool(true)
bool(false)
unicode(34) "Unknown column 'a' in 'field list'"
---- Row 1
bool(false)
int(2)
---- Row 2
bool(false)
int(2)
---- Row 3
bool(false)
----
done!
--
PHP CVS Mailing List (http://www.php.net/)
To unsubscribe, visit: http://www.php.net/unsub.php