Update ext/mysql's and ext/mysqli's tests

Add mysqli_stmt_more_result()/mysqli_stmt_next_result(), but only in
mysqlnd builds as libmysql doesn't support this feature.
This commit is contained in:
Andrey Hristov 2008-04-24 14:22:19 +00:00
parent 2667f76d7b
commit f4e659d2af
23 changed files with 603 additions and 200 deletions

View file

@ -184,9 +184,9 @@ func_mysql_fetch_array($link, $engine, "BIGINT", NULL, NULL, 260);
// func_mysql_fetch_array($link, $engine, "BIGINT UNSIGNED", 18446744073709551615, "1.84467e+019", 270, "/1\.84467e\+[0]?19/iu");
func_mysql_fetch_array($link, $engine, "BIGINT UNSIGNED", NULL, NULL, 280);
func_mysql_fetch_array($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+[0]?18/iu");
func_mysql_fetch_array($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+?[0]?18/iu");
func_mysql_fetch_array($link, $engine, "FLOAT", NULL, NULL, 300);
func_mysql_fetch_array($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+[0]?19/iu");
func_mysql_fetch_array($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+?[0]?19/iu");
func_mysql_fetch_array($link, $engine, "FLOAT UNSIGNED ", NULL, NULL, 320);
func_mysql_fetch_array($link, $engine, "DOUBLE(10,2)", -99999999.99, "-99999999.99", 330);

View file

@ -19,6 +19,9 @@ ob_end_clean();
if (!stristr($phpinfo, "mysql support"))
printf("[001] ext/mysql should have exposed itself.\n");
if (!stristr($phpinfo, "client api library version"))
printf("[002] ext/mysql should have exposed the library version.\n");
if (!stristr($phpinfo, "mysql.default_host"))
printf("[003] php.ini setting mysql.default_host not shown.\n");
@ -70,4 +73,4 @@ if ($IS_MYSQLND) {
print "done!";
?>
--EXPECTF--
done!
done!

View file

@ -1471,6 +1471,48 @@ PHP_FUNCTION(mysqli_next_result) {
}
/* }}} */
#ifdef MYSQLI_USE_MYSQLND
/* {{{ proto bool mysqli_stmt_next_result(object link)
check if there any more query results from a multi query */
PHP_FUNCTION(mysqli_stmt_more_results)
{
MY_STMT *stmt;
zval *mysql_stmt;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID);
RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
}
/* }}} */
/* {{{ proto bool mysqli_stmt_next_result(object link)
read next result from multi_query */
PHP_FUNCTION(mysqli_stmt_next_result) {
MY_STMT *stmt;
zval *mysql_stmt;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID);
if (!mysqlnd_stmt_more_results(stmt->stmt)) {
php_error_docref(NULL TSRMLS_CC, E_STRICT, "There is no next result set. "
"Please, call mysqli_stmt_more_results()/mysqli_stmt::more_results() to check "
"whether to call this function/method");
}
RETURN_BOOL(!mysqlnd_stmt_next_result(stmt->stmt));
}
/* }}} */
#endif
/* {{{ proto int mysqli_num_fields(object result)
Get number of fields in result */
PHP_FUNCTION(mysqli_num_fields)

View file

@ -155,6 +155,10 @@ const zend_function_entry mysqli_functions[] = {
PHP_FE(mysqli_stmt_data_seek, NULL)
PHP_FE(mysqli_stmt_errno, NULL)
PHP_FE(mysqli_stmt_error, NULL)
#if defined(MYSQLI_USE_MYSQLND)
PHP_FE(mysqli_stmt_more_results, NULL)
PHP_FE(mysqli_stmt_next_result, NULL)
#endif
PHP_FE(mysqli_stmt_num_rows, NULL)
PHP_FE(mysqli_stmt_sqlstate, NULL)
PHP_FE(mysqli_stmt_store_result, NULL)
@ -280,6 +284,10 @@ const zend_function_entry mysqli_stmt_methods[] = {
PHP_FALIAS(get_warnings, mysqli_stmt_get_warnings, NULL)
PHP_FALIAS(result_metadata, mysqli_stmt_result_metadata,NULL)
PHP_FALIAS(num_rows, mysqli_stmt_num_rows,NULL)
#if defined(MYSQLI_USE_MYSQLND)
PHP_FALIAS(more_results, mysqli_stmt_more_results, NULL)
PHP_FALIAS(next_result, mysqli_stmt_next_result, NULL)
#endif
PHP_FALIAS(send_long_data,mysqli_stmt_send_long_data,NULL)
PHP_FALIAS(stmt,mysqli_prepare,NULL)
PHP_FALIAS(free_result,mysqli_stmt_free_result,NULL)

View file

@ -409,8 +409,8 @@ PHP_FUNCTION(mysqli_fetch_all)
Returns statistics about the zval cache */
PHP_FUNCTION(mysqli_get_cache_stats)
{
if (ZEND_NUM_ARGS()) {
WRONG_PARAM_COUNT;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
mysqlnd_palloc_stats(mysqli_mysqlnd_zval_cache, return_value);
}
@ -421,8 +421,8 @@ PHP_FUNCTION(mysqli_get_cache_stats)
Returns statistics about the zval cache */
PHP_FUNCTION(mysqli_get_client_stats)
{
if (ZEND_NUM_ARGS()) {
WRONG_PARAM_COUNT;
if (zend_parse_parameters_none() == FAILURE) {
return;
}
mysqlnd_get_client_stats(return_value);
}
@ -665,7 +665,7 @@ PHP_FUNCTION(mysqli_set_charset)
MY_MYSQL *mysql;
zval *mysql_link;
char *cs_name;
int csname_len;
int csname_len;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &mysql_link, mysqli_link_class_entry, &cs_name, &csname_len) == FAILURE) {
return;

View file

@ -463,6 +463,8 @@ PHP_FUNCTION(mysqli_stmt_get_result);
PHP_FUNCTION(mysqli_stmt_get_warnings);
PHP_FUNCTION(mysqli_stmt_reset);
PHP_FUNCTION(mysqli_stmt_insert_id);
PHP_FUNCTION(mysqli_stmt_more_results);
PHP_FUNCTION(mysqli_stmt_next_result);
PHP_FUNCTION(mysqli_stmt_num_rows);
PHP_FUNCTION(mysqli_stmt_sqlstate);
PHP_FUNCTION(mysqli_stmt_store_result);

View file

@ -41,8 +41,11 @@ Interface of the class mysqli_stmt
'store_result' => true,
);
if ($IS_MYSQLND)
if ($IS_MYSQLND) {
$expected_methods['get_result'] = true;
$expected_methods['more_results'] = true;
$expected_methods['next_result'] = true;
}
foreach ($methods as $k => $method) {
if (isset($expected_methods[$method])) {

View file

@ -198,9 +198,9 @@ if (!function_exists('mysqli_fetch_all'))
func_mysqli_fetch_all($link, $engine, "BIGINT UNSIGNED", 18446744073709551615, "18446744073709551615", 270);
func_mysqli_fetch_all($link, $engine, "BIGINT UNSIGNED", NULL, NULL, 280);
func_mysqli_fetch_all($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+[0]?18/iu");
func_mysqli_fetch_all($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+?[0]?18/iu");
func_mysqli_fetch_all($link, $engine, "FLOAT", NULL, NULL, 300);
func_mysqli_fetch_all($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+[0]?19/iu");
func_mysqli_fetch_all($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+?[0]?19/iu");
func_mysqli_fetch_all($link, $engine, "FLOAT UNSIGNED ", NULL, NULL, 320);
func_mysqli_fetch_all($link, $engine, "DOUBLE(10,2)", -99999999.99, "-99999999.99", 330);

View file

@ -198,9 +198,9 @@ if (!function_exists('mysqli_fetch_all'))
func_mysqli_fetch_all_oo($link, $engine, "BIGINT UNSIGNED", 18446744073709551615, "18446744073709551615", 270);
func_mysqli_fetch_all_oo($link, $engine, "BIGINT UNSIGNED", NULL, NULL, 280);
func_mysqli_fetch_all_oo($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+[0]?18/iu");
func_mysqli_fetch_all_oo($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+?[0]?18/iu");
func_mysqli_fetch_all_oo($link, $engine, "FLOAT", NULL, NULL, 300);
func_mysqli_fetch_all_oo($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+[0]?19/iu");
func_mysqli_fetch_all_oo($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+?19", 310, "/1\.84467e\+?[0]?19/iu");
func_mysqli_fetch_all_oo($link, $engine, "FLOAT UNSIGNED ", NULL, NULL, 320);
func_mysqli_fetch_all_oo($link, $engine, "DOUBLE(10,2)", -99999999.99, "-99999999.99", 330);

View file

@ -191,9 +191,9 @@ require_once('skipifconnectfailure.inc');
func_mysqli_fetch_array($link, $engine, "BIGINT UNSIGNED", NULL, NULL, 280);
}
func_mysqli_fetch_array($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+[0]?18/iu");
func_mysqli_fetch_array($link, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+?[0]?18/iu");
func_mysqli_fetch_array($link, $engine, "FLOAT", NULL, NULL, 300);
func_mysqli_fetch_array($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+[0]?19/iu");
func_mysqli_fetch_array($link, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+?19", 310, "/1\.84467e\+?[0]?19/iu");
func_mysqli_fetch_array($link, $engine, "FLOAT UNSIGNED ", NULL, NULL, 320);
func_mysqli_fetch_array($link, $engine, "DOUBLE(10,2)", -99999999.99, "-99999999.99", 330);

View file

@ -175,9 +175,9 @@ require_once('skipifconnectfailure.inc');
func_mysqli_fetch_array($mysqli, $engine, "BIGINT UNSIGNED", NULL, NULL, 280);
}
func_mysqli_fetch_array($mysqli, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+[0]?18/iu");
func_mysqli_fetch_array($mysqli, $engine, "FLOAT", -9223372036854775808 - 1.1, "-9.22337e+18", 290, "/-9\.22337e\+?[0]?18/iu");
func_mysqli_fetch_array($mysqli, $engine, "FLOAT", NULL, NULL, 300);
func_mysqli_fetch_array($mysqli, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+19", 310, "/1\.84467e\+[0]?19/iu");
func_mysqli_fetch_array($mysqli, $engine, "FLOAT UNSIGNED", 18446744073709551615 + 1.1, "1.84467e+?19", 310, "/1\.84467e\+?[0]?19/iu");
func_mysqli_fetch_array($mysqli, $engine, "FLOAT UNSIGNED ", NULL, NULL, 320);
func_mysqli_fetch_array($mysqli, $engine, "DOUBLE(10,2)", -99999999.99, "-99999999.99", 330);

View file

@ -5,11 +5,22 @@ mysqli_fetch_field() - flags/field->flags
require_once('skipif.inc');
require_once('skipifemb.inc');
require_once('skipifconnectfailure.inc');
require_once('connect.inc');
if (!$link = mysqli_connect($host, $user, $passwd, $db, $port, $socket))
die(printf("skip: [%d] %s\n", mysqli_connect_errno(), mysqli_connect_error()));
if (mysqli_get_server_version($link) < 50041)
die("skip: Due to many MySQL Server differences, the test requires 5.0.41+");
mysqli_close($link);
?>
--FILE--
<?php
include "connect.inc";
/* TODO: mysqli.c needs to export a few more constants - see all the defined() calls! */
$flags = array(
MYSQLI_NOT_NULL_FLAG => 'NOT_NULL',
MYSQLI_PRI_KEY_FLAG => 'PRI_KEY',
@ -23,12 +34,19 @@ require_once('skipifconnectfailure.inc');
MYSQLI_SET_FLAG => 'SET',
MYSQLI_NUM_FLAG => 'NUM',
MYSQLI_PART_KEY_FLAG => 'PART_KEY',
MYSQLI_GROUP_FLAG => 'MYSQLI_GROUP_FLAG'
// MYSQLI_NO_DEFAULT_VALUE_FLAG
// MYSQLI_BINARY_FLAG
// MYSQLI_ENUM_FLAG
// MYSQLI_GROUP_FLAG => 'MYSQLI_GROUP_FLAG' - internal usage only
(defined('MYSQLI_NO_DEFAULT_VALUE_FLAG') ? MYSQLI_NO_DEFAULT_VALUE_FLAG : 4096) => 'NO_DEFAULT_VALUE',
(defined('MYSQLI_BINARY_FLAG') ? MYSQLI_BINARY_FLAG : 128) => 'BINARY',
(defined('MYSQLI_ENUM_FLAG') ? MYSQLI_ENUM_FLAG : 256) => 'ENUM',
// MYSQLI_BINCMP_FLAG
);
// 5.1.24 / 6.0.4+
if (defined('MYSQLI_ON_UPDATE_NOW'))
$flags[MYSQLI_ON_UPDATE_NOW] = 'ON_UPDATE_NOW';
else
$flags[8192] = 'ON_UPDATE_NOW';
krsort($flags);
$columns = array(
@ -37,13 +55,13 @@ require_once('skipifconnectfailure.inc');
'INT NOT NULL DEFAULT 1' => 'NOT_NULL NUM',
'INT UNSIGNED DEFAULT NULL' => 'UNSIGNED NUM',
'INT UNSIGNED NOT NULL' => 'NOT_NULL UNSIGNED NO_DEFAULT_VALUE NUM',
'INT UNSIGNED NOT NULL DEFAULT 1' => 'NOT_NULL UNSIGNED NULL',
'INT UNSIGNED NOT NULL DEFAULT 1' => 'NOT_NULL UNSIGNED NUM',
'INT UNSIGNED ZEROFILL DEFAULT NULL' => 'UNSIGNED ZEROFILL NUM',
'INT UNSIGNED NOT NULL AUTO_INCREMENT PRIMARY KEY' => 'NOT_NULL PRI_KEY UNSIGNED AUTO_INCREMENT NUM PART_KEY',
'CHAR(1) DEFAULT NULL' => '',
'CHAR(1) NOT NULL' => 'NOT_NULL NO_DEFAULT_VALUE',
'TIMESTAMP NOT NULL' => 'NOT_NULL UNSIGNED ZEROFILL BINARY TIMESTAMP',
'VARBINARY(127) DEFAULT NULL' => 'NOT_NULL BINARY',
'VARBINARY(127) DEFAULT NULL' => 'BINARY',
'BLOB' => 'BLOB BINARY',
'TINYBLOB' => 'BLOB BINARY',
'MEDIUMBLOB' => 'BLOB BINARY',
@ -67,10 +85,9 @@ require_once('skipifconnectfailure.inc');
);
function checkFlags($reported_flags, $expected_flags, $flags) {
$found_flags = $unexpected_flags = '';
foreach ($flags as $code => $name) {
if ($code >= $reported_flags) {
if ($reported_flags >= $code) {
$reported_flags -= $code;
$found_flags .= $name . ' ';
if (stristr($expected_flags, $name)) {
@ -118,13 +135,57 @@ require_once('skipifconnectfailure.inc');
continue;
}
/*
TODO
Unfortunately different server versions give you slightly different
results.The test does not yet fully reflect all server changes/bugs etc.
*/
switch ($column_def) {
case 'TIMESTAMP NOT NULL':
// http://bugs.mysql.com/bug.php?id=30081 - new flag introduced in 5.1.24/6.0.4
$version = mysqli_get_server_version($link);
if ((($version > 50122) && ($version < 60000)) ||
($version >= 60004)) {
// new flag ON_UPDATE_NOW_FLAG (8192)
$expected_flags .= ' ON_UPDATE_NOW';
}
break;
case 'INT UNSIGNED NOT NULL':
case 'INT NOT NULL':
case 'CHAR(1) NOT NULL':
case 'SET("one", "two") NOT NULL':
case 'ENUM("one", "two") NOT NULL':
$version = mysqli_get_server_version($link);
if ($version < 50000) {
// TODO - check exact version!
$expected_flags = trim(str_replace('NO_DEFAULT_VALUE', '', $expected_flags));
}
break;
case 'BIT':
$version = mysqli_get_server_version($link);
if ($version <= 50105) {
// TODO - check exact version!
$expected_flags = trim(str_replace('UNSIGNED', '', $expected_flags));
}
default:
break;
}
list($missing_flags, $unexpected_flags, $flags_found) = checkFlags($field->flags, $expected_flags, $flags);
if ($unexpected_flags)
if ($unexpected_flags) {
printf("[006] Found unexpected flags '%s' for %s, found '%s'\n",
$unexpected_flags, $column_def, $flags_found);
if ($missing_flags)
}
if ($missing_flags) {
printf("[007] The flags '%s' have not been reported for %s, found '%s'\n",
$missing_flags, $column_def, $flags_found);
var_dump($create);
var_dump(mysqli_get_server_version($link));
die($missing_flags);
}
mysqli_free_result($res);
}

View file

@ -57,15 +57,61 @@ require_once('skipifconnectfailure.inc');
if (true !== ($tmp = mysqli_stmt_execute($stmt)))
printf("[012] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
// calling reset between executions
mysqli_stmt_close($stmt);
if (!$stmt = mysqli_stmt_init($link))
printf("[013] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
if (!mysqli_stmt_prepare($stmt, "SELECT id FROM test ORDER BY id LIMIT 1"))
printf("[014] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (true !== ($tmp = mysqli_stmt_execute($stmt)))
printf("[015] Expecting boolean/true, got %s/%s. [%d] %s\n",
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
$id = null;
if (!mysqli_stmt_bind_result($stmt, $id) || !mysqli_stmt_fetch($stmt))
printf("[016] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if ($id !== 1)
printf("[017] Expecting int/1 got %s/%s\n", gettype($id), $id);
if (true !== ($tmp = mysqli_stmt_reset($stmt)))
printf("[018] Expecting boolean/true, got %s/%s. [%d] %s\n",
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
printf("Don't know what we should expect\n");
var_dump(mysqli_stmt_execute($stmt));
var_dump(mysqli_stmt_fetch($stmt));
mysqli_stmt_close($stmt);
if (!$stmt = mysqli_stmt_init($link))
printf("[019] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
if (!mysqli_stmt_prepare($stmt, "SELECT id FROM test ORDER BY id LIMIT 1"))
printf("[020] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (true !== ($tmp = mysqli_stmt_execute($stmt)))
printf("[021] Expecting boolean/true, got %s/%s. [%d] %s\n",
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
if (true !== ($tmp = mysqli_stmt_reset($stmt)))
printf("[022] Expecting boolean/true, got %s/%s. [%d] %s\n",
gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
printf("Don't know what we should expect\n");
var_dump(mysqli_stmt_execute($stmt));
var_dump(mysqli_stmt_fetch($stmt));
mysqli_kill($link, mysqli_thread_id($link));
if (false !== ($tmp = mysqli_stmt_execute($stmt)))
printf("[014] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
printf("[023] Expecting boolean/false, got %s/%s\n", gettype($tmp), $tmp);
mysqli_stmt_close($stmt);
if (NULL !== ($tmp = mysqli_stmt_execute($stmt)))
printf("[015] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
printf("[024] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
mysqli_close($link);
print "done!";

View file

@ -1274,10 +1274,12 @@ MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn, enum_connection_close_type c
/* {{{ mysqlnd_conn::get_reference */
static MYSQLND *
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference)(MYSQLND * const conn)
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference)(MYSQLND * const conn TSRMLS_DC)
{
DBG_ENTER("mysqlnd_conn::get_reference");
++conn->refcount;
return conn;
DBG_INF_FMT("conn=%llu new_refcount=%u", conn->thread_id, conn->refcount);
DBG_RETURN(conn);
}
/* }}} */
@ -1288,7 +1290,7 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference)(MYSQLND * const conn TSRMLS
{
enum_func_status ret = PASS;
DBG_ENTER("mysqlnd_conn::free_reference");
DBG_INF_FMT("conn=%llu conn->refcount=%u", conn->thread_id, conn->refcount);
DBG_INF_FMT("conn=%llu old_refcount=%u", conn->thread_id, conn->refcount);
if (!(--conn->refcount)) {
/*
No multithreading issues as we don't share the connection :)
@ -1474,10 +1476,11 @@ MYSQLND_METHOD(mysqlnd_conn, get_server_version)(const MYSQLND * const conn)
/* {{{ mysqlnd_conn::more_results */
static zend_bool
MYSQLND_METHOD(mysqlnd_conn,more_results)(const MYSQLND * const conn)
MYSQLND_METHOD(mysqlnd_conn, more_results)(const MYSQLND * const conn TSRMLS_DC)
{
DBG_ENTER("mysqlnd_conn::more_results");
/* (conn->state == CONN_NEXT_RESULT_PENDING) too */
return conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS? TRUE:FALSE;
DBG_RETURN(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS? TRUE:FALSE);
}
/* }}} */
@ -1792,7 +1795,7 @@ MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
result = conn->current_result;
conn->current_result = NULL;
result->conn = conn->m->get_reference(conn);
result->conn = conn->m->get_reference(conn TSRMLS_CC);
result = result->m.use_result(result, FALSE TSRMLS_CC);
DBG_RETURN(result);
@ -1956,7 +1959,7 @@ PHPAPI MYSQLND *_mysqlnd_init(zend_bool persistent TSRMLS_DC)
ret->persistent = persistent;
ret->m = & mysqlnd_mysqlnd_conn_methods;
ret->m->get_reference(ret);
ret->m->get_reference(ret TSRMLS_CC);
#ifdef MYSQLND_THREADED
ret->LOCK_state = tsrm_mutex_alloc();

View file

@ -112,7 +112,7 @@ PHPAPI void _mysqlnd_debug(const char *mode TSRMLS_DC);
#define mysqlnd_store_result(conn) (conn)->m->store_result((conn) TSRMLS_CC)
#define mysqlnd_bg_store_result(conn) (conn)->m->background_store_result((conn) TSRMLS_CC)
#define mysqlnd_next_result(conn) (conn)->m->next_result((conn) TSRMLS_CC)
#define mysqlnd_more_results(conn) (conn)->m->more_results((conn))
#define mysqlnd_more_results(conn) (conn)->m->more_results((conn) TSRMLS_CC)
#define mysqlnd_free_result(r,e_or_i) ((MYSQLND_RES*)r)->m.free_result(((MYSQLND_RES*)(r)), (e_or_i) TSRMLS_CC)
#define mysqlnd_data_seek(result, row) (result)->m.seek_data((result), (row) TSRMLS_CC)
@ -262,6 +262,8 @@ PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size
#define mysqlnd_stmt_store_result(stmt) (!mysqlnd_stmt_field_count((stmt)) ? PASS:((stmt)->m->store_result((stmt) TSRMLS_CC)? PASS:FAIL))
#define mysqlnd_stmt_bg_store_result(stmt) (!mysqlnd_stmt_field_count((stmt)) ? PASS:((stmt)->m->background_store_result((stmt) TSRMLS_CC)? PASS:FAIL))
#define mysqlnd_stmt_get_result(stmt) (stmt)->m->get_result((stmt) TSRMLS_CC)
#define mysqlnd_stmt_more_results(stmt) (stmt)->m->more_results((stmt) TSRMLS_CC)
#define mysqlnd_stmt_next_result(stmt) (stmt)->m->next_result((stmt) TSRMLS_CC)
#define mysqlnd_stmt_data_seek(stmt, row) (stmt)->m->seek_data((stmt), (row) TSRMLS_CC)
#define mysqlnd_stmt_prepare(stmt, q, qlen) (stmt)->m->prepare((stmt), (q), (qlen) TSRMLS_CC)
#define mysqlnd_stmt_execute(stmt) (stmt)->m->execute((stmt) TSRMLS_CC)
@ -271,6 +273,7 @@ PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size
#define mysqlnd_stmt_refresh_bind_param(s) (s)->m->refresh_bind_param((s) TSRMLS_CC)
#define mysqlnd_stmt_set_param_bind_dtor(s,d) (s)->m->set_param_bind_dtor((s), (d) TSRMLS_CC)
#define mysqlnd_stmt_bind_result(stmt,bind) (stmt)->m->bind_result((stmt), (bind) TSRMLS_CC)
#define mysqlnd_stmt_bind_one_result(s,no) (s)->m->bind_one_result((s), (no) TSRMLS_CC)
#define mysqlnd_stmt_set_result_bind_dtor(s,d) (s)->m->set_result_bind_dtor((s), (d) TSRMLS_CC)
#define mysqlnd_stmt_param_metadata(stmt) (stmt)->m->get_parameter_metadata((stmt))
#define mysqlnd_stmt_result_metadata(stmt) (stmt)->m->get_result_metadata((stmt) TSRMLS_CC)
@ -305,9 +308,10 @@ PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * cache TSRM
#define mysqlnd_palloc_init_thd_cache(cache) _mysqlnd_palloc_init_thd_cache((cache) TSRMLS_CC)
#define mysqlnd_palloc_free_thd_cache_reference(cache) _mysqlnd_palloc_free_thd_cache_reference((cache) TSRMLS_CC)
#define mysqlnd_palloc_get_thd_cache_reference(cache) _mysqlnd_palloc_get_thd_cache_reference((cache) TSRMLS_CC)
PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC);
MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache);
MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache TSRMLS_DC);
PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC);

View file

@ -28,8 +28,26 @@
#define MYSQLND_SQLSTATE_LENGTH 5
#define MYSQLND_SQLSTATE_NULL "00000"
#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */
#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */
#define MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED 16
#define MYSQLND_SERVER_QUERY_NO_INDEX_USED 32
/*
The server was able to fulfill the clients request and opened a
read-only non-scrollable cursor for a query. This flag comes
in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
*/
#define SERVER_STATUS_CURSOR_EXISTS 64
/*
This flag is sent when a read-only cursor is exhausted, in reply to
COM_STMT_FETCH command.
*/
#define SERVER_STATUS_LAST_ROW_SENT 128
#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */
#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512
#define SERVER_QUERY_WAS_SLOW 1024
#define MYSQLND_NO_DATA 100
#define MYSQLND_DATA_TRUNCATED 101

View file

@ -151,14 +151,16 @@ PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCAC
/* }}} */
/* {{{ mysqlnd_palloc_get_thd_cache_reference */
MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache)
/* {{{ _mysqlnd_palloc_get_thd_cache_reference */
MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache TSRMLS_DC)
{
DBG_ENTER("_mysqlnd_palloc_get_thd_cache_reference");
if (cache) {
++cache->references;
DBG_INF_FMT("cache=%p new_refc=%d", *cache, cache->references);
mysqlnd_palloc_get_cache_reference(cache->parent);
}
return cache;
DBG_RETURN(cache);
}
/* }}} */
@ -190,8 +192,8 @@ PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **c
{
DBG_ENTER("_mysqlnd_palloc_free_thd_cache_reference");
if (*cache) {
DBG_INF_FMT("cache=%p refs=%d", *cache, (*cache)->references);
--(*cache)->parent->references;
DBG_INF_FMT("cache=%p references_left=%d", *cache, (*cache)->references);
if (--(*cache)->references == 0) {
mysqlnd_palloc_free_thd_cache(*cache TSRMLS_CC);
@ -493,7 +495,7 @@ PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS
++cache->free_items;
#ifdef ZTS
memset(&((*p)->thread_id), 0, sizeof(THREAD_T));
#endif
#endif
p++;
}
UNLOCK_PCACHE(cache);

View file

@ -74,23 +74,6 @@
#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */
#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */
/*
The server was able to fulfill the clients request and opened a
read-only non-scrollable cursor for a query. This flag comes
in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
*/
#define SERVER_STATUS_CURSOR_EXISTS 64
/*
This flag is sent when a read-only cursor is exhausted, in reply to
COM_STMT_FETCH command.
*/
#define SERVER_STATUS_LAST_ROW_SENT 128
#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */
#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512
#define SERVER_QUERY_WAS_SLOW 1024
/* Client Error codes */

View file

@ -57,7 +57,10 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param,
zend_bool *fetched_anything TSRMLS_DC);
static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, uint param_no TSRMLS_DC);
static void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC);
static enum_func_status mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC);
/* {{{ mysqlnd_stmt::store_result */
static MYSQLND_RES *
@ -100,7 +103,9 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
result->type = MYSQLND_RES_PS_BUF;
result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
result->m.fetch_lengths = NULL;/* makes no sense */
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
if (!result->zval_cache) {
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
}
/* Create room for 'next_extend' rows */
@ -167,7 +172,9 @@ MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt
result->type = MYSQLND_RES_PS_BUF;
result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
result->m.fetch_lengths = NULL;/* makes no sense */
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
if (!result->zval_cache) {
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
}
/* Create room for 'next_extend' rows */
@ -248,6 +255,45 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
/* }}} */
/* {{{ mysqlnd_stmt::more_results */
static zend_bool
MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * stmt TSRMLS_DC)
{
DBG_ENTER("mysqlnd_stmt::more_results");
/* (conn->state == CONN_NEXT_RESULT_PENDING) too */
DBG_RETURN((stmt->conn && (stmt->conn->upsert_status.server_status &
SERVER_MORE_RESULTS_EXISTS))?
TRUE:
FALSE);
}
/* }}} */
/* {{{ mysqlnd_stmt::next_result */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * stmt TSRMLS_DC)
{
MYSQLND *conn = stmt->conn;
DBG_ENTER("mysqlnd_stmt::next_result");
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
if (!conn ||
CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING ||
!(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) ||
!stmt->result)
{
DBG_RETURN(FAIL);
}
/* Free space for next result */
mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
DBG_RETURN(mysqlnd_stmt_execute_parse_response(stmt TSRMLS_CC));
}
/* }}} */
/* {{{ mysqlnd_stmt_skip_metadata */
static enum_func_status
mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
@ -399,7 +445,7 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * co
/* Allocate the result now as it is needed for the reading of metadata */
stmt_to_prepare->result = result;
result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn);
result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn TSRMLS_CC);
result->type = MYSQLND_RES_PS_BUF;
@ -411,7 +457,7 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const stmt, const char * co
if (stmt_to_prepare != stmt) {
/* Free old buffers, binding and resources on server */
stmt->m->close(stmt, TRUE TSRMLS_CC);
stmt->m->net_close(stmt, TRUE TSRMLS_CC);
memcpy(stmt, stmt_to_prepare, sizeof(MYSQLND_STMT));
@ -434,6 +480,92 @@ fail:
/* }}} */
/* {{{ mysqlnd_stmt_execute_parse_response */
static enum_func_status
mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
{
enum_func_status ret;
MYSQLND *conn = stmt->conn;
DBG_ENTER("mysqlnd_stmt_execute_parse_response");
CONN_SET_STATE(conn, CONN_QUERY_SENT);
ret = mysqlnd_query_read_result_set_header(stmt->conn, stmt TSRMLS_CC);
if (ret == FAIL) {
stmt->error_info = conn->error_info;
stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
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 || conn->last_query_type == QUERY_LOAD_LOCAL) {
DBG_INF("PASS");
DBG_RETURN(PASS);
}
stmt->result->type = MYSQLND_RES_PS_BUF;
if (!stmt->result->conn) {
/*
For SHOW we don't create (bypasses PS in server)
a result set at prepare and thus a connection was missing
*/
stmt->result->conn = stmt->conn->m->get_reference(stmt->conn TSRMLS_CC);
}
/* Update stmt->field_count as SHOW sets it to 0 at prepare */
stmt->field_count = stmt->result->field_count = conn->field_count;
stmt->result->lengths = NULL;
if (stmt->field_count) {
stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
/*
We need to set this because the user might not call
use_result() or store_result() and we should be able to scrap the
data on the line, if he just decides to close the statement.
*/
DBG_INF_FMT("server_status=%d cursor=%d", stmt->upsert_status.server_status,
stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
stmt->cursor_exists = TRUE;
CONN_SET_STATE(conn, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = stmt->m->use_result;
DBG_INF("use_result");
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
stmt->default_rset_handler = stmt->m->store_result;
DBG_INF("store_result");
} else {
/* preferred is unbuffered read */
stmt->default_rset_handler = stmt->m->use_result;
DBG_INF("use_result");
}
}
}
DBG_INF(ret == PASS? "PASS":"FAIL");
DBG_RETURN(ret);
}
/* }}} */
/* {{{ mysqlnd_stmt::execute */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
@ -451,6 +583,12 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
SET_ERROR_AFF_ROWS(stmt->conn);
if (stmt->state > MYSQLND_STMT_PREPARED && stmt->field_count) {
/*
We don need to copy the data from the buffers which we will clean.
Because it has already been copied. See
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
*/
#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
if (stmt->result_bind &&
stmt->result_zvals_separated_once == TRUE &&
stmt->state >= MYSQLND_STMT_USER_FETCHING)
@ -474,6 +612,29 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
}
}
}
#endif
/*
If right after execute() we have to call the appropriate
use_result() or store_result() and clean.
*/
if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
DBG_INF("fetching result set header");
/* Do implicit use_result and then flush the result */
stmt->default_rset_handler = stmt->m->use_result;
stmt->default_rset_handler(stmt TSRMLS_CC);
}
if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
DBG_INF("skipping result");
/* Flush if anything is left and unbuffered set */
stmt->result->m.skip_result(stmt->result TSRMLS_CC);
}
if (stmt->state > MYSQLND_STMT_PREPARED) {
/* As the buffers have been freed, we should go back to PREPARED */
stmt->state = MYSQLND_STMT_PREPARED;
}
/*
Executed, but the user hasn't started to fetch
@ -534,79 +695,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
}
stmt->execute_count++;
CONN_SET_STATE(conn, CONN_QUERY_SENT);
ret = mysqlnd_query_read_result_set_header(stmt->conn, stmt TSRMLS_CC);
if (ret == FAIL) {
stmt->error_info = conn->error_info;
stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
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 || conn->last_query_type == QUERY_LOAD_LOCAL) {
DBG_INF("PASS");
DBG_RETURN(PASS);
}
stmt->result->type = MYSQLND_RES_PS_BUF;
if (!stmt->result->conn) {
/*
For SHOW we don't create (bypasses PS in server)
a result set at prepare and thus a connection was missing
*/
stmt->result->conn = stmt->conn->m->get_reference(stmt->conn);
}
/* Update stmt->field_count as SHOW sets it to 0 at prepare */
stmt->field_count = stmt->result->field_count = conn->field_count;
stmt->result->lengths = NULL;
if (stmt->field_count) {
stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
/*
We need to set this because the user might not call
use_result() or store_result() and we should be able to scrap the
data on the line, if he just decides to close the statement.
*/
DBG_INF_FMT("server_status=%d cursor=%d", stmt->upsert_status.server_status,
stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
stmt->cursor_exists = TRUE;
CONN_SET_STATE(conn, CONN_READY);
/* Only cursor read */
stmt->default_rset_handler = stmt->m->use_result;
DBG_INF("use_result");
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
/*
We have asked for CURSOR but got no cursor, because the condition
above is not fulfilled. Then...
This is a single-row result set, a result set with no rows, EXPLAIN,
SHOW VARIABLES, or some other command which either a) bypasses the
cursors framework in the server and writes rows directly to the
network or b) is more efficient if all (few) result set rows are
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
stmt->default_rset_handler = stmt->m->store_result;
DBG_INF("store_result");
} else {
/* preferred is unbuffered read */
stmt->default_rset_handler = stmt->m->use_result;
DBG_INF("use_result");
}
}
}
DBG_INF(ret == PASS? "PASS":"FAIL");
DBG_RETURN(ret);
DBG_RETURN(mysqlnd_stmt_execute_parse_response(stmt TSRMLS_CC));
}
/* }}} */
@ -661,7 +750,9 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
for (i = 0; i < result->field_count; i++) {
/* Clean what we copied last time */
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
zval_dtor(stmt->result_bind[i].zv);
if (stmt->result_bind[i].zv) {
zval_dtor(stmt->result_bind[i].zv);
}
#endif
/* copy the type */
if (stmt->result_bind[i].bound == TRUE) {
@ -978,7 +1069,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
stmt->conn->upsert_status.server_status =
row_packet->server_status;
DBG_INF_FMT("ret=%s fetched=%d s_status=%d warns=%d eof=%d",
DBG_INF_FMT("ret=%s fetched=%d server_status=%d warnings=%d eof=%d",
ret == PASS? "PASS":"FAIL", *fetched_anything,
row_packet->server_status, row_packet->warning_count,
result->unbuf->eof_reached);
@ -1079,8 +1170,13 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
DBG_INF("skipping result");
stmt->result->m.skip_result(stmt->result TSRMLS_CC);
}
/* Now the line should be free, if it wasn't */
DBG_INF("freeing result");
/* free_result() doesn't actually free stmt->result but only the buffers */
stmt->m->free_result(stmt TSRMLS_CC);
int4store(cmd_buf, stmt->stmt_id);
if (CONN_GET_STATE(conn) == CONN_READY &&
FAIL == (ret = mysqlnd_simple_command(conn, COM_STMT_RESET, (char *)cmd_buf,
@ -1365,8 +1461,6 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
DBG_ENTER("mysqlnd_stmt::bind_result");
DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
@ -1377,6 +1471,9 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
DBG_RETURN(FAIL);
}
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->field_count) {
uint i = 0;
@ -1386,7 +1483,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
}
mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
stmt->result_zvals_separated_once = FALSE;
stmt->result_bind = result_bind;
for (i = 0; i < stmt->field_count; i++) {
/* Prevent from freeing */
@ -1407,6 +1504,50 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
/* }}} */
/* {{{ mysqlnd_stmt::bind_result */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const stmt, uint param_no TSRMLS_DC)
{
DBG_ENTER("mysqlnd_stmt::bind_result");
DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
DBG_ERR("not prepared");
DBG_RETURN(FAIL);
}
if (param_no < 0 || param_no >= stmt->field_count) {
SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
DBG_ERR("invalid param_no");
DBG_RETURN(FAIL);
}
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->field_count) {
mysqlnd_stmt_separate_one_result_bind(stmt, param_no TSRMLS_CC);
/* Guaranteed is that stmt->result_bind is NULL */
if (!stmt->result_bind) {
stmt->result_bind = ecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND));
} else {
stmt->result_bind = erealloc(stmt->result_bind, stmt->field_count * sizeof(MYSQLND_RESULT_BIND));
}
ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
/*
Don't update is_ref !!! it's not our job
Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
will fail.
*/
stmt->result_bind[param_no].bound = TRUE;
}
DBG_INF("PASS");
DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_stmt::set_bind_result_dtor */
static void
MYSQLND_METHOD(mysqlnd_stmt, set_result_bind_dtor)(MYSQLND_STMT * const stmt,
@ -1613,7 +1754,7 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
/* {{{ mysqlnd_stmt::attr_get */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, attr_get)(MYSQLND_STMT * const stmt,
MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const stmt,
enum mysqlnd_stmt_attr attr_type,
void * const value TSRMLS_DC)
{
@ -1638,7 +1779,7 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_get)(MYSQLND_STMT * const stmt,
}
/* }}} */
/* free_result() doesn't actually free stmt->result but only the buffers */
/* {{{ mysqlnd_stmt::free_result */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
@ -1651,6 +1792,10 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
DBG_RETURN(PASS);
}
/*
If right after execute() we have to call the appropriate
use_result() or store_result() and clean.
*/
if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
DBG_INF("fetching result set header");
/* Do implicit use_result and then flush the result */
@ -1672,8 +1817,10 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
}
/* As the buffers have been freed, we should go back to PREPARED */
stmt->state = MYSQLND_STMT_PREPARED;
if (stmt->state > MYSQLND_STMT_PREPARED) {
/* As the buffers have been freed, we should go back to PREPARED */
stmt->state = MYSQLND_STMT_PREPARED;
}
/* Line is free! */
CONN_SET_STATE(stmt->conn, CONN_READY);
@ -1737,9 +1884,55 @@ void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
/* }}} */
/* {{{ mysqlnd_stmt_separate_one_result_bind */
void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, uint param_no TSRMLS_DC)
{
DBG_ENTER("mysqlnd_stmt_separate_one_result_bind");
DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%d",
stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no);
if (!stmt->result_bind) {
DBG_VOID_RETURN;
}
/*
Because only the bound variables can point to our internal buffers, then
separate or free only them. Free is possible because the user could have
lost reference.
*/
/* Let's try with no cache */
if (stmt->result_bind[param_no].bound == TRUE) {
DBG_INF_FMT("%d has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
/*
We have to separate the actual zval value of the bound
variable from our allocated zvals or we will face double-free
*/
if (Z_REFCOUNT_P(stmt->result_bind[param_no].zv) > 1) {
#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
zval_copy_ctor(stmt->result_bind[param_no].zv);
#endif
zval_ptr_dtor(&stmt->result_bind[param_no].zv);
} else {
/*
If it is a string, what is pointed will be freed
later in free_result(). We need to remove the variable to
which the user has lost reference.
*/
#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
ZVAL_NULL(stmt->result_bind[param_no].zv);
#endif
zval_ptr_dtor(&stmt->result_bind[param_no].zv);
}
}
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_internal_free_stmt_content */
static
void mysqlnd_internal_free_stmt_content(MYSQLND_STMT *stmt TSRMLS_DC)
void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC)
{
DBG_ENTER("mysqlnd_internal_free_stmt_content");
DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u",
@ -1778,24 +1971,15 @@ void mysqlnd_internal_free_stmt_content(MYSQLND_STMT *stmt TSRMLS_DC)
stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
stmt->result = NULL;
}
if (stmt->cmd_buffer.buffer) {
mnd_efree(stmt->cmd_buffer.buffer);
stmt->cmd_buffer.buffer = NULL;
}
if (stmt->conn) {
stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
stmt->conn = NULL;
}
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_stmt::close */
/* {{{ mysqlnd_stmt::net_close */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, close)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC)
MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC)
{
MYSQLND * conn = stmt->conn;
zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
@ -1854,16 +2038,25 @@ MYSQLND_METHOD(mysqlnd_stmt, close)(MYSQLND_STMT * const stmt, zend_bool implici
MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
}
if (stmt->execute_cmd_buffer.buffer) {
mnd_efree(stmt->execute_cmd_buffer.buffer);
stmt->execute_cmd_buffer.buffer = NULL;
}
mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
if (stmt->conn) {
stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
stmt->conn = NULL;
}
DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_stmt::dtor */
static enum_func_status
MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, dtor)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC)
MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC)
{
enum_func_status ret;
@ -1873,9 +2066,8 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, dtor)(MYSQLND_STMT * const stmt, zend_bool
MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
STAT_STMT_CLOSE_EXPLICIT);
if (PASS == (ret = stmt->m->close(stmt, implicit TSRMLS_CC))) {
mnd_efree(stmt);
}
ret = stmt->m->net_close(stmt, implicit TSRMLS_CC);
mnd_efree(stmt);
DBG_INF(ret == PASS? "PASS":"FAIL");
DBG_RETURN(ret);
@ -1891,11 +2083,13 @@ struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = {
MYSQLND_METHOD(mysqlnd_stmt, store_result),
MYSQLND_METHOD(mysqlnd_stmt, background_store_result),
MYSQLND_METHOD(mysqlnd_stmt, get_result),
MYSQLND_METHOD(mysqlnd_stmt, more_results),
MYSQLND_METHOD(mysqlnd_stmt, next_result),
MYSQLND_METHOD(mysqlnd_stmt, free_result),
MYSQLND_METHOD(mysqlnd_stmt, data_seek),
MYSQLND_METHOD(mysqlnd_stmt, reset),
MYSQLND_METHOD(mysqlnd_stmt, close),
MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, dtor),
MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close),
MYSQLND_METHOD(mysqlnd_stmt, dtor),
MYSQLND_METHOD(mysqlnd_stmt, fetch),
@ -1904,6 +2098,7 @@ struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = {
MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
MYSQLND_METHOD(mysqlnd_stmt, set_param_bind_dtor),
MYSQLND_METHOD(mysqlnd_stmt, bind_result),
MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
MYSQLND_METHOD(mysqlnd_stmt, set_result_bind_dtor),
MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
@ -1936,8 +2131,8 @@ MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
stmt->m = &mysqlnd_stmt_methods;
stmt->state = MYSQLND_STMT_INITTED;
stmt->cmd_buffer.length = 4096;
stmt->cmd_buffer.buffer = mnd_emalloc(stmt->cmd_buffer.length);
stmt->execute_cmd_buffer.length = 4096;
stmt->execute_cmd_buffer.buffer = mnd_emalloc(stmt->execute_cmd_buffer.length);
stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
/*
@ -1945,7 +2140,7 @@ MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
be destructed till there is open statements. The last statement
or normal query result will close it then.
*/
stmt->conn = conn->m->get_reference(conn);
stmt->conn = conn->m->get_reference(conn TSRMLS_CC);
stmt->m->set_param_bind_dtor(stmt, mysqlnd_efree_param_bind_dtor TSRMLS_CC);
stmt->m->set_result_bind_dtor(stmt, mysqlnd_efree_result_bind_dtor TSRMLS_CC);

View file

@ -771,9 +771,9 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uch
zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
zend_bool *free_buffer TSRMLS_DC)
{
zend_uchar *p = stmt->cmd_buffer.buffer,
*cmd_buffer = stmt->cmd_buffer.buffer;
size_t cmd_buffer_length = stmt->cmd_buffer.length;
zend_uchar *p = stmt->execute_cmd_buffer.buffer,
*cmd_buffer = stmt->execute_cmd_buffer.buffer;
size_t cmd_buffer_length = stmt->execute_cmd_buffer.length;
unsigned int null_byte_offset,
null_count= (stmt->param_count + 7) / 8;
@ -801,7 +801,7 @@ zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *re
mysqlnd_stmt_execute_store_params(stmt, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC);
*free_buffer = (cmd_buffer != stmt->cmd_buffer.buffer);
*free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer);
*request_len = (p - cmd_buffer);
return cmd_buffer;
}

View file

@ -177,6 +177,7 @@ void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
}
/* }}} */
/* {{{ mysqlnd_free_buffered_data */
void mysqlnd_free_buffered_data(MYSQLND_RES *result TSRMLS_DC)
{
@ -231,6 +232,7 @@ void mysqlnd_free_buffered_data(MYSQLND_RES *result TSRMLS_DC)
}
/* }}} */
#ifdef MYSQLND_THREADED
/* {{{ mysqlnd_free_background_buffered_data */
void mysqlnd_free_background_buffered_data(MYSQLND_RES *result TSRMLS_DC)
@ -309,8 +311,9 @@ void mysqlnd_free_background_buffered_data(MYSQLND_RES *result TSRMLS_DC)
/* }}} */
#endif /* MYSQL_THREADING */
/* {{{ mysqlnd_res::free_result_buffers */
void
static void
MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES *result TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res::free_result_buffers");
@ -580,8 +583,15 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT *stmt TSRMLS_DC
stmt->state = MYSQLND_STMT_INITTED;
}
} else {
DBG_INF_FMT("warns=%u status=%u", fields_eof.warning_count, fields_eof.server_status);
DBG_INF_FMT("warnings=%u server_status=%u", fields_eof.warning_count, fields_eof.server_status);
conn->upsert_status.warning_count = fields_eof.warning_count;
/*
If SERVER_MORE_RESULTS_EXISTS is set then this is either MULTI_QUERY or a CALL()
The first packet after sending the query/com_execute has the bit set only
in this cases. Not sure why it's a needed but it marks that the whole stream
will include many result sets. What actually matters are the bits set at the end
of every result set (the EOF packet).
*/
conn->upsert_status.server_status = fields_eof.server_status;
if (fields_eof.server_status & MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED) {
stat = STAT_BAD_INDEX_USED;
@ -789,7 +799,7 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES *result TSRMLS_DC)
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
} else if (row_packet->eof) {
/* Mark the connection as usable again */
DBG_INF_FMT("warns=%u status=%u", row_packet->warning_count, row_packet->server_status);
DBG_INF_FMT("warningss=%u server_status=%u", row_packet->warning_count, row_packet->server_status);
result->unbuf->eof_reached = TRUE;
result->conn->upsert_status.warning_count = row_packet->warning_count;
result->conn->upsert_status.server_status = row_packet->server_status;
@ -929,7 +939,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flag
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
} else if (row_packet->eof) {
/* Mark the connection as usable again */
DBG_INF_FMT("warns=%u status=%u", row_packet->warning_count, row_packet->server_status);
DBG_INF_FMT("warnings=%u server_status=%u", row_packet->warning_count, row_packet->server_status);
result->unbuf->eof_reached = TRUE;
result->conn->upsert_status.warning_count = row_packet->warning_count;
result->conn->upsert_status.server_status = row_packet->server_status;
@ -1261,7 +1271,7 @@ mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
}
PACKET_FREE(row_packet);
DBG_INF_FMT("ret=%s row_count=%u warns=%u status=%u", ret == PASS? "PASS":"FAIL",
DBG_INF_FMT("ret=%s row_count=%u warnings=%u server_status=%u", ret == PASS? "PASS":"FAIL",
set->row_count, conn->upsert_status.warning_count, conn->upsert_status.server_status);
DBG_RETURN(ret);
}
@ -1281,7 +1291,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
DBG_INF_FMT("conn=%d ps_protocol=%d", conn->thread_id, ps_protocol);
/* We need the conn because we are doing lazy zval initialization in buffered_fetch_row */
result->conn = conn->m->get_reference(conn);
result->conn = conn->m->get_reference(conn TSRMLS_CC);
result->type = MYSQLND_RES_NORMAL;
result->m.fetch_row = result->m.fetch_row_normal_buffered;
result->m.fetch_lengths = mysqlnd_fetch_lengths_buffered;
@ -1305,6 +1315,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
}
/* }}} */
#ifdef MYSQLND_THREADED
/* {{{ mysqlnd_fetch_row_async_buffered */
static enum_func_status
@ -1432,6 +1443,7 @@ mysqlnd_fetch_row_async_buffered(MYSQLND_RES *result, void *param, unsigned int
}
/* }}} */
/* {{{ mysqlnd_background_store_result_fetch_data */
enum_func_status
mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
@ -1465,7 +1477,9 @@ mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
old_size = set->data_size;
set->data_size = total_rows;
set->data = mnd_perealloc(set->data, set->data_size * sizeof(zval **), set->persistent);
// memset(set->data + old_size, 0, (set->data_size - old_size) * sizeof(zval **));
#if 0
memset(set->data + old_size, 0, (set->data_size - old_size) * sizeof(zval **));
#endif
set->row_buffers = mnd_perealloc(set->row_buffers,
total_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *),
set->persistent);
@ -1511,11 +1525,12 @@ mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
transfered above.
*/
}
// MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats,
// binary_protocol? STAT_ROWS_BUFFERED_FROM_CLIENT_PS:
// STAT_ROWS_BUFFERED_FROM_CLIENT_NORMAL,
// set->row_count);
#if 0
MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats,
binary_protocol? STAT_ROWS_BUFFERED_FROM_CLIENT_PS:
STAT_ROWS_BUFFERED_FROM_CLIENT_NORMAL,
set->row_count);
#endif
tsrm_mutex_lock(set->LOCK);
/* Finally clean */
if (row_packet->eof) {
@ -1551,7 +1566,7 @@ mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
} else {
CONN_SET_STATE(conn, CONN_READY);
}
DBG_INF_FMT("ret=%s row_count=%u warns=%u status=%u", ret == PASS? "PASS":"FAIL",
DBG_INF_FMT("ret=%s row_count=%u warnings=%u server_status=%u", ret == PASS? "PASS":"FAIL",
set->row_count, conn->upsert_status.warning_count, conn->upsert_status.server_status);
DBG_RETURN(ret);
}
@ -1560,7 +1575,7 @@ mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC)
/* {{{ mysqlnd_res::background_store_result */
MYSQLND_RES *
static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_res, background_store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps TSRMLS_DC)
{
#ifndef MYSQLND_THREADED
@ -1573,7 +1588,7 @@ MYSQLND_METHOD(mysqlnd_res, background_store_result)(MYSQLND_RES * result, MYSQL
DBG_INF_FMT("conn=%d ps_protocol=%d", conn->thread_id, ps);
/* We need the conn because we are doing lazy zval initialization in buffered_fetch_row */
result->conn = conn->m->get_reference(conn);
result->conn = conn->m->get_reference(conn TSRMLS_CC);
result->type = MYSQLND_RES_NORMAL;
result->m.fetch_row = mysqlnd_fetch_row_async_buffered;
result->m.fetch_lengths = mysqlnd_fetch_lengths_async_buffered;

View file

@ -241,7 +241,7 @@ struct st_mysqlnd_conn_methods
MYSQLND_RES * (*store_result)(MYSQLND * const conn TSRMLS_DC);
MYSQLND_RES * (*background_store_result)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*next_result)(MYSQLND * const conn TSRMLS_DC);
zend_bool (*more_results)(const MYSQLND * const conn);
zend_bool (*more_results)(const MYSQLND * const conn TSRMLS_DC);
MYSQLND_STMT * (*stmt_init)(MYSQLND * const conn TSRMLS_DC);
@ -282,7 +282,7 @@ struct st_mysqlnd_conn_methods
enum_func_status (*close)(MYSQLND *conn, enum_connection_close_type close_type TSRMLS_DC);
void (*dtor)(MYSQLND *conn TSRMLS_DC); /* private */
MYSQLND * (*get_reference)(MYSQLND * const conn);
MYSQLND * (*get_reference)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*free_reference)(MYSQLND * const conn TSRMLS_DC);
enum mysqlnd_connection_state (*get_state)(MYSQLND * const conn TSRMLS_DC);
void (*set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC);
@ -344,10 +344,12 @@ struct st_mysqlnd_stmt_methods
MYSQLND_RES * (*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
MYSQLND_RES * (*background_store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
MYSQLND_RES * (*get_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
zend_bool (*more_results)(const MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*next_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*free_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*seek_data)(const MYSQLND_STMT * const stmt, uint64 row TSRMLS_DC);
enum_func_status (*reset)(MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*close)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC); /* private */
enum_func_status (*net_close)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC); /* private */
enum_func_status (*dtor)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC); /* use this for mysqlnd_stmt_close */
enum_func_status (*fetch)(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything TSRMLS_DC);
@ -357,6 +359,7 @@ struct st_mysqlnd_stmt_methods
enum_func_status (*refresh_bind_param)(MYSQLND_STMT * const stmt TSRMLS_DC);
void (*set_param_bind_dtor)(MYSQLND_STMT * const stmt, void (*param_bind_dtor)(MYSQLND_PARAM_BIND *) TSRMLS_DC);
enum_func_status (*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC);
enum_func_status (*bind_one_result)(MYSQLND_STMT * const stmt, uint param_no TSRMLS_DC);
void (*set_result_bind_dtor)(MYSQLND_STMT * const stmt, void (*result_bind_dtor)(MYSQLND_RESULT_BIND *) TSRMLS_DC);
enum_func_status (*send_long_data)(MYSQLND_STMT * const stmt, unsigned int param_num,
const char * const data, unsigned long length TSRMLS_DC);
@ -375,7 +378,7 @@ struct st_mysqlnd_stmt_methods
const char * (*get_error_str)(const MYSQLND_STMT * const stmt);
const char * (*get_sqlstate)(const MYSQLND_STMT * const stmt);
enum_func_status (*get_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, void * const value TSRMLS_DC);
enum_func_status (*get_attribute)(const MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, void * const value TSRMLS_DC);
enum_func_status (*set_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, const void * const value TSRMLS_DC);
};
@ -587,7 +590,6 @@ struct st_mysqlnd_param_bind
struct st_mysqlnd_result_bind
{
zval *zv;
zend_uchar original_type;
zend_bool bound;
};
@ -617,7 +619,7 @@ struct st_mysqlnd_stmt
zend_bool cursor_exists;
mysqlnd_stmt_use_or_store_func default_rset_handler;
MYSQLND_CMD_BUFFER cmd_buffer;
MYSQLND_CMD_BUFFER execute_cmd_buffer;
unsigned int execute_count;/* count how many times the stmt was executed */
void (*param_bind_dtor)(MYSQLND_PARAM_BIND *);

View file

@ -587,6 +587,13 @@ php_mysqlnd_greet_read(void *_packet, MYSQLND *conn TSRMLS_DC)
} else {
packet->pre41 = TRUE;
}
DBG_INF_FMT("proto=%d server=%s thread_id=%ld",
packet->protocol_version, packet->server_version, packet->thread_id);
DBG_INF_FMT("server_capabilities=%d charset_no=%d server_status=%d",
packet->server_capabilities, packet->charset_no, packet->server_status);
if (p - begin > packet->header.size) {
DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet %d bytes shorter than expected. PID=%d",
@ -783,8 +790,8 @@ php_mysqlnd_ok_read(void *_packet, MYSQLND *conn TSRMLS_DC)
}
DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%d warnings=%d",
packet->affected_rows, packet->last_insert_id, packet->server_status,
packet->warning_count);
packet->affected_rows, packet->last_insert_id, packet->server_status,
packet->warning_count);
if (p - begin > packet->header.size) {
DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
@ -865,7 +872,8 @@ php_mysqlnd_eof_read(void *_packet, MYSQLND *conn TSRMLS_DC)
p - begin - packet->header.size, getpid());
}
DBG_INF_FMT("EOF packet: status=%d warnings=%d", packet->server_status, packet->warning_count);
DBG_INF_FMT("EOF packet: fields=%d status=%d warnings=%d",
packet->field_count, packet->server_status, packet->warning_count);
DBG_RETURN(PASS);
}
@ -986,6 +994,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
packet->field_count= php_mysqlnd_net_field_length(&p);
switch (packet->field_count) {
case MYSQLND_NULL_LENGTH:
DBG_INF("LOAD LOCAL");
/*
First byte in the packet is the field count.
Thus, the name is size - 1. And we add 1 for a trailing \0.
@ -997,6 +1006,7 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
packet->info_or_local_file_len = len;
break;
case 0x00:
DBG_INF("UPSERT");
packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
packet->last_insert_id= php_mysqlnd_net_field_length_ll(&p);
packet->server_status = uint2korr(p);
@ -1010,13 +1020,17 @@ php_mysqlnd_rset_header_read(void *_packet, MYSQLND *conn TSRMLS_DC)
packet->info_or_local_file[len] = '\0';
packet->info_or_local_file_len = len;
}
DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%d warning_count=%d",
packet->affected_rows, packet->last_insert_id,
packet->server_status, packet->warning_count);
break;
default:
DBG_INF("SELECT");
/* Result set */
break;
}
if (p - begin > packet->header.size) {
DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin - packet->header.size);
DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin - packet->header.size);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet %d bytes shorter than expected. PID=%d",
p - begin - packet->header.size, getpid());
}
@ -1097,7 +1111,7 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC)
*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
break;
case MYSQLND_NULL_LENGTH:
goto faulty_fake;
goto faulty_or_fake;
default:
*(char **)(((char *)meta) + rset_field_offsets[i]) = (char *)p;
*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
@ -1156,7 +1170,7 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC)
}
if (p - begin > packet->header.size) {
DBG_ERR_FMT("Result set field packet %d bytes shorter than expected", p - begin - packet->header.size);
DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin - packet->header.size);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set field packet %d bytes "
"shorter than expected. PID=%d", p - begin - packet->header.size, getpid());
}
@ -1210,7 +1224,7 @@ php_mysqlnd_rset_field_read(void *_packet, MYSQLND *conn TSRMLS_DC)
*/
DBG_RETURN(PASS);
faulty_fake:
faulty_or_fake:
DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
" The server is faulty");
@ -1629,6 +1643,8 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC)
p += 2;
packet->server_status = uint2korr(p);
/* Seems we have 3 bytes reserved for future use */
DBG_INF_FMT("server_status=%d warning_count=%d",
packet->server_status, packet->warning_count);
}
} else {
MYSQLND_INC_CONN_STATISTIC(&conn->stats,