andrey          Thu Mar 20 13:25:49 2008 UTC

  Added files:                 
    /php-src/ext/mysqli/tests   mysqli_stmt_datatype_change.phpt 

  Modified files:              
    /php-src/ext/mysqlnd        mysqlnd.c mysqlnd_ps.c mysqlnd_ps_codec.c 
                                mysqlnd_result.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.
  - 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/mysqlnd/mysqlnd.c?r1=1.19&r2=1.20&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd.c
diff -u php-src/ext/mysqlnd/mysqlnd.c:1.19 php-src/ext/mysqlnd/mysqlnd.c:1.20
--- php-src/ext/mysqlnd/mysqlnd.c:1.19  Thu Feb 14 12:51:00 2008
+++ php-src/ext/mysqlnd/mysqlnd.c       Thu Mar 20 13:25:49 2008
@@ -18,7 +18,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: mysqlnd.c,v 1.19 2008/02/14 12:51:00 andrey Exp $ */
+/* $Id: mysqlnd.c,v 1.20 2008/03/20 13:25:49 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*/
@@ -805,14 +806,14 @@
 
        if (errstr) {
                DBG_ERR_FMT("[%d] %.64s (trying to connect via %s)", errcode, 
errstr, conn->scheme);
-               SET_CLIENT_ERROR(conn->error_info, errcode, UNKNOWN_SQLSTATE, 
errstr);
-
+               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;
        }
 
@@ -1316,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.13&r2=1.14&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd_ps.c
diff -u php-src/ext/mysqlnd/mysqlnd_ps.c:1.13 
php-src/ext/mysqlnd/mysqlnd_ps.c:1.14
--- php-src/ext/mysqlnd/mysqlnd_ps.c:1.13       Thu Feb 14 14:48:57 2008
+++ php-src/ext/mysqlnd/mysqlnd_ps.c    Thu Mar 20 13:25:49 2008
@@ -18,7 +18,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: mysqlnd_ps.c,v 1.13 2008/02/14 14:48:57 andrey Exp $ */
+/* $Id: mysqlnd_ps.c,v 1.14 2008/03/20 13:25:49 andrey Exp $ */
 #include "php.h"
 #include "mysqlnd.h"
 #include "mysqlnd_wireprotocol.h"
@@ -297,7 +297,9 @@
 
        stmt->stmt_id = prepare_resp.stmt_id;
        stmt->warning_count = stmt->conn->upsert_status.warning_count = 
prepare_resp.warning_count;
-       stmt->field_count = stmt->conn->field_count = prepare_resp.field_count;
+       stmt->upsert_status.affected_rows = 0;
+       stmt->field_count =  prepare_resp.field_count;
+       stmt->conn->field_count = 0;
        stmt->param_count = prepare_resp.param_count;
        PACKET_FREE_ALLOCA(prepare_resp);
 
@@ -522,17 +524,14 @@
                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);
                stmt->send_types_to_server = 0;
                stmt->upsert_status = conn->upsert_status;
                stmt->state = MYSQLND_STMT_EXECUTED;
-               if (conn->last_query_type == QUERY_UPSERT) {
-                       stmt->upsert_status = conn->upsert_status;
-                       DBG_INF("PASS");
-                       DBG_RETURN(PASS);
-               } else if (conn->last_query_type == QUERY_LOAD_LOCAL) {
+               if (conn->last_query_type == QUERY_UPSERT || 
conn->last_query_type == QUERY_LOAD_LOCAL) {
                        DBG_INF("PASS");
                        DBG_RETURN(PASS);
                }
http://cvs.php.net/viewvc.cgi/php-src/ext/mysqlnd/mysqlnd_ps_codec.c?r1=1.6&r2=1.7&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd_ps_codec.c
diff -u php-src/ext/mysqlnd/mysqlnd_ps_codec.c:1.6 
php-src/ext/mysqlnd/mysqlnd_ps_codec.c:1.7
--- php-src/ext/mysqlnd/mysqlnd_ps_codec.c:1.6  Thu Feb 14 12:51:00 2008
+++ php-src/ext/mysqlnd/mysqlnd_ps_codec.c      Thu Mar 20 13:25:49 2008
@@ -18,7 +18,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: mysqlnd_ps_codec.c,v 1.6 2008/02/14 12:51:00 andrey Exp $ */
+/* $Id: mysqlnd_ps_codec.c,v 1.7 2008/03/20 13:25:49 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/mysqlnd/mysqlnd_result.c?r1=1.19&r2=1.20&diff_format=u
Index: php-src/ext/mysqlnd/mysqlnd_result.c
diff -u php-src/ext/mysqlnd/mysqlnd_result.c:1.19 
php-src/ext/mysqlnd/mysqlnd_result.c:1.20
--- php-src/ext/mysqlnd/mysqlnd_result.c:1.19   Wed Feb 20 15:20:14 2008
+++ php-src/ext/mysqlnd/mysqlnd_result.c        Thu Mar 20 13:25:49 2008
@@ -18,7 +18,7 @@
   +----------------------------------------------------------------------+
 */
 
-/* $Id: mysqlnd_result.c,v 1.19 2008/02/20 15:20:14 andrey Exp $ */
+/* $Id: mysqlnd_result.c,v 1.20 2008/03/20 13:25:49 andrey Exp $ */
 #include "php.h"
 #include "mysqlnd.h"
 #include "mysqlnd_wireprotocol.h"
@@ -518,8 +518,8 @@
                                conn->last_query_type = QUERY_SELECT;
                                CONN_SET_STATE(conn, CONN_FETCHING_DATA);
                                /* PS has already allocated it */
+                               conn->field_count = rset_header.field_count;
                                if (!stmt) {
-                                       conn->field_count = 
rset_header.field_count;
                                        result =
                                                conn->current_result=
                                                        
mysqlnd_result_init(rset_header.field_count,
@@ -533,7 +533,6 @@
                                                  prepared statements can't 
send result set metadata for these queries
                                                  on prepare stage. Read it now.
                                                */
-                                               conn->field_count = 
rset_header.field_count;
                                                result =
                                                        stmt->result =
                                                                
mysqlnd_result_init(rset_header.field_count,

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

Reply via email to