Add mysqli_error_list() that returns an array with errors. Typically only

one and just one for libmysql. mysqlnd can return generate more than one error
during its work and with mysqli_error() only the last error is being reported.
In the array returned by mysqli_error_list() / $mysqli->error_list, all errors will be found.
The list is reset when the next command is executed
This commit is contained in:
Andrey Hristov 2011-08-04 09:51:26 +00:00
parent 463de70efd
commit 11f198b203
23 changed files with 363 additions and 31 deletions

View file

@ -352,6 +352,7 @@ const zend_function_entry mysqli_functions[] = {
#endif #endif
PHP_FE(mysqli_errno, arginfo_mysqli_only_link) PHP_FE(mysqli_errno, arginfo_mysqli_only_link)
PHP_FE(mysqli_error, arginfo_mysqli_only_link) PHP_FE(mysqli_error, arginfo_mysqli_only_link)
PHP_FE(mysqli_error_list, arginfo_mysqli_only_link)
PHP_FE(mysqli_stmt_execute, arginfo_mysqli_only_statement) PHP_FE(mysqli_stmt_execute, arginfo_mysqli_only_statement)
PHP_FALIAS(mysqli_execute, mysqli_stmt_execute, arginfo_mysqli_only_statement) PHP_FALIAS(mysqli_execute, mysqli_stmt_execute, arginfo_mysqli_only_statement)
PHP_FE(mysqli_fetch_field, arginfo_mysqli_only_result) PHP_FE(mysqli_fetch_field, arginfo_mysqli_only_result)
@ -424,6 +425,7 @@ const zend_function_entry mysqli_functions[] = {
PHP_FE(mysqli_stmt_data_seek, arginfo_mysqli_stmt_data_seek) PHP_FE(mysqli_stmt_data_seek, arginfo_mysqli_stmt_data_seek)
PHP_FE(mysqli_stmt_errno, arginfo_mysqli_only_statement) PHP_FE(mysqli_stmt_errno, arginfo_mysqli_only_statement)
PHP_FE(mysqli_stmt_error, arginfo_mysqli_only_statement) PHP_FE(mysqli_stmt_error, arginfo_mysqli_only_statement)
PHP_FE(mysqli_stmt_error_list, arginfo_mysqli_only_statement)
PHP_FE(mysqli_stmt_fetch, arginfo_mysqli_only_statement) PHP_FE(mysqli_stmt_fetch, arginfo_mysqli_only_statement)
PHP_FE(mysqli_stmt_field_count, arginfo_mysqli_only_statement) PHP_FE(mysqli_stmt_field_count, arginfo_mysqli_only_statement)
PHP_FE(mysqli_stmt_free_result, arginfo_mysqli_only_statement) PHP_FE(mysqli_stmt_free_result, arginfo_mysqli_only_statement)

View file

@ -38,6 +38,7 @@ PHP_FUNCTION(mysqli_debug);
PHP_FUNCTION(mysqli_dump_debug_info); PHP_FUNCTION(mysqli_dump_debug_info);
PHP_FUNCTION(mysqli_errno); PHP_FUNCTION(mysqli_errno);
PHP_FUNCTION(mysqli_error); PHP_FUNCTION(mysqli_error);
PHP_FUNCTION(mysqli_error_list);
PHP_FUNCTION(mysqli_fetch_all); PHP_FUNCTION(mysqli_fetch_all);
PHP_FUNCTION(mysqli_fetch_array); PHP_FUNCTION(mysqli_fetch_array);
PHP_FUNCTION(mysqli_fetch_assoc); PHP_FUNCTION(mysqli_fetch_assoc);
@ -111,6 +112,7 @@ PHP_FUNCTION(mysqli_stmt_close);
PHP_FUNCTION(mysqli_stmt_data_seek); PHP_FUNCTION(mysqli_stmt_data_seek);
PHP_FUNCTION(mysqli_stmt_errno); PHP_FUNCTION(mysqli_stmt_errno);
PHP_FUNCTION(mysqli_stmt_error); PHP_FUNCTION(mysqli_stmt_error);
PHP_FUNCTION(mysqli_stmt_error_list);
PHP_FUNCTION(mysqli_stmt_free_result); PHP_FUNCTION(mysqli_stmt_free_result);
PHP_FUNCTION(mysqli_stmt_get_result); PHP_FUNCTION(mysqli_stmt_get_result);
PHP_FUNCTION(mysqli_stmt_get_warnings); PHP_FUNCTION(mysqli_stmt_get_warnings);

View file

@ -385,6 +385,7 @@ PHP_FUNCTION(mysqli_fetch_all)
/* }}} */ /* }}} */
/* {{{ proto array mysqli_get_client_stats(void) /* {{{ proto array mysqli_get_client_stats(void)
Returns statistics about the zval cache */ Returns statistics about the zval cache */
PHP_FUNCTION(mysqli_get_client_stats) PHP_FUNCTION(mysqli_get_client_stats)
@ -415,6 +416,93 @@ PHP_FUNCTION(mysqli_get_connection_stats)
#endif #endif
/* }}} */ /* }}} */
/* {{{ proto mixed mysqli_error_list (object connection)
Fetches all client errors */
PHP_FUNCTION(mysqli_error_list)
{
MY_MYSQL *mysql;
zval *mysql_link;
if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) {
return;
}
MYSQLI_FETCH_RESOURCE_CONN(mysql, &mysql_link, MYSQLI_STATUS_VALID);
array_init(return_value);
#if defined(MYSQLI_USE_MYSQLND)
if (mysql->mysql->error_info.error_list) {
MYSQLND_ERROR_LIST_ELEMENT * message;
zend_llist_position pos;
for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(mysql->mysql->error_info.error_list, &pos);
message;
message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(mysql->mysql->error_info.error_list, &pos))
{
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), message->error_no);
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), message->sqlstate, 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), message->error, 1);
add_next_index_zval(return_value, single_error);
}
}
#else
if (mysql_errno(mysql->mysql)) {
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), mysql_errno(mysql->mysql));
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), mysql_sqlstate(mysql->mysql), 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), mysql_error(mysql->mysql), 1);
add_next_index_zval(return_value, single_error);
}
#endif
}
/* }}} */
/* {{{ proto string mysqli_stmt_error_list(object stmt)
*/
PHP_FUNCTION(mysqli_stmt_error_list)
{
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(stmt, &mysql_stmt, MYSQLI_STATUS_INITIALIZED);
array_init(return_value);
#if defined(MYSQLI_USE_MYSQLND)
if (stmt->stmt && stmt->stmt->data && stmt->stmt->data->error_info.error_list) {
MYSQLND_ERROR_LIST_ELEMENT * message;
zend_llist_position pos;
for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(stmt->stmt->data->error_info.error_list, &pos);
message;
message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(stmt->stmt->data->error_info.error_list, &pos))
{
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), message->error_no);
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), message->sqlstate, 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), message->error, 1);
add_next_index_zval(return_value, single_error);
}
}
#else
if (mysql_stmt_errno(stmt->stmt)) {
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), mysql_stmt_errno(stmt->stmt));
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), mysql_stmt_sqlstate(stmt->stmt), 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), mysql_stmt_error(stmt->stmt), 1);
add_next_index_zval(return_value, single_error);
}
#endif
}
/* }}} */
/* {{{ proto mixed mysqli_fetch_object (object result [, string class_name [, NULL|array ctor_params]]) /* {{{ proto mixed mysqli_fetch_object (object result [, string class_name [, NULL|array ctor_params]])
Fetch a result row as an object */ Fetch a result row as an object */

View file

@ -189,6 +189,54 @@ static int link_affected_rows_read(mysqli_object *obj, zval **retval TSRMLS_DC)
} }
/* }}} */ /* }}} */
/* {{{ property link_error_list_read */
static int link_error_list_read(mysqli_object *obj, zval **retval TSRMLS_DC)
{
MY_MYSQL *mysql;
MAKE_STD_ZVAL(*retval);
CHECK_STATUS(MYSQLI_STATUS_VALID);
mysql = (MY_MYSQL *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
array_init(*retval);
if (mysql) {
#if defined(MYSQLI_USE_MYSQLND)
if (mysql->mysql->error_info.error_list) {
MYSQLND_ERROR_LIST_ELEMENT * message;
zend_llist_position pos;
for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(mysql->mysql->error_info.error_list, &pos);
message;
message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(mysql->mysql->error_info.error_list, &pos))
{
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), message->error_no);
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), message->sqlstate, 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), message->error, 1);
add_next_index_zval(*retval, single_error);
}
}
#else
if (mysql_errno(mysql->mysql)) {
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), mysql_errno(mysql->mysql));
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), mysql_sqlstate(mysql->mysql), 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), mysql_error(mysql->mysql), 1);
add_next_index_zval(*retval, single_error);
}
#endif
}
return SUCCESS;
}
/* }}} */
/* link properties */ /* link properties */
MYSQLI_MAP_PROPERTY_FUNC_LONG(link_errno_read, mysql_errno, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED), ulong, "%lu") MYSQLI_MAP_PROPERTY_FUNC_LONG(link_errno_read, mysql_errno, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED), ulong, "%lu")
MYSQLI_MAP_PROPERTY_FUNC_STRING(link_error_read, mysql_error, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED)) MYSQLI_MAP_PROPERTY_FUNC_STRING(link_error_read, mysql_error, MYSQLI_GET_MYSQL(MYSQLI_STATUS_INITIALIZED))
@ -202,6 +250,7 @@ MYSQLI_MAP_PROPERTY_FUNC_LONG(link_server_version_read, mysql_get_server_version
MYSQLI_MAP_PROPERTY_FUNC_STRING(link_sqlstate_read, mysql_sqlstate, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID)) MYSQLI_MAP_PROPERTY_FUNC_STRING(link_sqlstate_read, mysql_sqlstate, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID))
MYSQLI_MAP_PROPERTY_FUNC_LONG(link_thread_id_read, mysql_thread_id, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), ulong, "%lu") MYSQLI_MAP_PROPERTY_FUNC_LONG(link_thread_id_read, mysql_thread_id, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), ulong, "%lu")
MYSQLI_MAP_PROPERTY_FUNC_LONG(link_warning_count_read, mysql_warning_count, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), ulong, "%lu") MYSQLI_MAP_PROPERTY_FUNC_LONG(link_warning_count_read, mysql_warning_count, MYSQLI_GET_MYSQL(MYSQLI_STATUS_VALID), ulong, "%lu")
/* result properties */ /* result properties */
/* {{{ property result_type_read */ /* {{{ property result_type_read */
@ -306,6 +355,51 @@ static int stmt_affected_rows_read(mysqli_object *obj, zval **retval TSRMLS_DC)
} }
/* }}} */ /* }}} */
/* {{{ property stmt_error_list_read */
static int stmt_error_list_read(mysqli_object *obj, zval **retval TSRMLS_DC)
{
MY_STMT * stmt;
MAKE_STD_ZVAL(*retval);
CHECK_STATUS(MYSQLI_STATUS_INITIALIZED);
stmt = (MY_STMT *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr;
array_init(*retval);
if (stmt && stmt->stmt) {
#if defined(MYSQLI_USE_MYSQLND)
if (stmt->stmt->data && stmt->stmt->data->error_info.error_list) {
MYSQLND_ERROR_LIST_ELEMENT * message;
zend_llist_position pos;
for (message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_first_ex(stmt->stmt->data->error_info.error_list, &pos);
message;
message = (MYSQLND_ERROR_LIST_ELEMENT *) zend_llist_get_next_ex(stmt->stmt->data->error_info.error_list, &pos))
{
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), message->error_no);
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), message->sqlstate, 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), message->error, 1);
add_next_index_zval(*retval, single_error);
}
}
#else
if (mysql_stmt_errno(stmt->stmt)) {
zval * single_error;
MAKE_STD_ZVAL(single_error);
array_init(single_error);
add_assoc_long_ex(single_error, "errno", sizeof("errno"), mysql_stmt_errno(stmt->stmt));
add_assoc_string_ex(single_error, "sqlstate", sizeof("sqlstate"), mysql_stmt_sqlstate(stmt->stmt), 1);
add_assoc_string_ex(single_error, "error", sizeof("error"), mysql_stmt_error(stmt->stmt), 1);
add_next_index_zval(*retval, single_error);
}
#endif
}
return SUCCESS;
}
/* }}} */
MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_insert_id_read, mysql_stmt_insert_id, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC) MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_insert_id_read, mysql_stmt_insert_id, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_num_rows_read, mysql_stmt_num_rows, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC) MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_num_rows_read, mysql_stmt_num_rows, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), my_ulonglong, MYSQLI_LLU_SPEC)
MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_param_count_read, mysql_stmt_param_count, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), ulong, "%lu") MYSQLI_MAP_PROPERTY_FUNC_LONG(stmt_param_count_read, mysql_stmt_param_count, MYSQLI_GET_STMT(MYSQLI_STATUS_VALID), ulong, "%lu")
@ -323,6 +417,7 @@ const mysqli_property_entry mysqli_link_property_entries[] = {
{"connect_error", sizeof("connect_error") - 1, link_connect_error_read, NULL}, {"connect_error", sizeof("connect_error") - 1, link_connect_error_read, NULL},
{"errno", sizeof("errno") - 1, link_errno_read, NULL}, {"errno", sizeof("errno") - 1, link_errno_read, NULL},
{"error", sizeof("error") - 1, link_error_read, NULL}, {"error", sizeof("error") - 1, link_error_read, NULL},
{"error_list", sizeof("error_list") - 1, link_error_list_read, NULL},
{"field_count", sizeof("field_count") - 1, link_field_count_read, NULL}, {"field_count", sizeof("field_count") - 1, link_field_count_read, NULL},
{"host_info", sizeof("host_info") - 1, link_host_info_read, NULL}, {"host_info", sizeof("host_info") - 1, link_host_info_read, NULL},
{"info", sizeof("info") - 1, link_info_read, NULL}, {"info", sizeof("info") - 1, link_info_read, NULL},
@ -345,6 +440,7 @@ const zend_property_info mysqli_link_property_info_entries[] = {
{ZEND_ACC_PUBLIC, "connect_error", sizeof("connect_error") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "connect_error", sizeof("connect_error") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "errno", sizeof("errno") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "errno", sizeof("errno") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "error", sizeof("error") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "error", sizeof("error") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "error_list", sizeof("error_list") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "field_count", sizeof("field_count") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "field_count", sizeof("field_count") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "host_info", sizeof("host_info") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "host_info", sizeof("host_info") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "info", sizeof("info") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "info", sizeof("info") - 1, -1, 0, NULL, 0, NULL},
@ -385,6 +481,7 @@ const mysqli_property_entry mysqli_stmt_property_entries[] = {
{"field_count", sizeof("field_count") - 1, stmt_field_count_read, NULL}, {"field_count", sizeof("field_count") - 1, stmt_field_count_read, NULL},
{"errno", sizeof("errno") - 1, stmt_errno_read, NULL}, {"errno", sizeof("errno") - 1, stmt_errno_read, NULL},
{"error", sizeof("error") - 1, stmt_error_read, NULL}, {"error", sizeof("error") - 1, stmt_error_read, NULL},
{"error_list", sizeof("error_list") - 1, stmt_error_list_read, NULL},
{"sqlstate", sizeof("sqlstate") - 1, stmt_sqlstate_read, NULL}, {"sqlstate", sizeof("sqlstate") - 1, stmt_sqlstate_read, NULL},
{"id", sizeof("id") - 1, stmt_id_read, NULL}, {"id", sizeof("id") - 1, stmt_id_read, NULL},
{NULL, 0, NULL, NULL} {NULL, 0, NULL, NULL}
@ -399,6 +496,7 @@ const zend_property_info mysqli_stmt_property_info_entries[] = {
{ZEND_ACC_PUBLIC, "field_count",sizeof("field_count") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "field_count",sizeof("field_count") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "errno", sizeof("errno") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "errno", sizeof("errno") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "error", sizeof("error") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "error", sizeof("error") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "error_list", sizeof("error_list") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "sqlstate", sizeof("sqlstate") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "sqlstate", sizeof("sqlstate") - 1, -1, 0, NULL, 0, NULL},
{ZEND_ACC_PUBLIC, "id", sizeof("id") - 1, -1, 0, NULL, 0, NULL}, {ZEND_ACC_PUBLIC, "id", sizeof("id") - 1, -1, 0, NULL, 0, NULL},
{0, NULL, 0, -1, 0, NULL, 0, NULL} {0, NULL, 0, -1, 0, NULL, 0, NULL}

View file

@ -91,6 +91,9 @@ object(mysqli_stmt)#%d (%d) {
int(0) int(0)
[%u|b%"error"]=> [%u|b%"error"]=>
%unicode|string%(0) "" %unicode|string%(0) ""
[%u|b%"error_list"]=>
array(0) {
}
[%u|b%"sqlstate"]=> [%u|b%"sqlstate"]=>
%unicode|string%(5) "00000" %unicode|string%(5) "00000"
[%u|b%"id"]=> [%u|b%"id"]=>

View file

@ -77,6 +77,9 @@ object(mysqli)#%d (%d) {
int(0) int(0)
[%u|b%"error"]=> [%u|b%"error"]=>
%unicode|string%(0) "" %unicode|string%(0) ""
[%u|b%"error_list"]=>
array(0) {
}
[%u|b%"field_count"]=> [%u|b%"field_count"]=>
int(0) int(0)
[%u|b%"host_info"]=> [%u|b%"host_info"]=>
@ -113,6 +116,8 @@ object(mysqli)#%d (%d) {
int(0) int(0)
[%u|b%"error"]=> [%u|b%"error"]=>
%unicode|string%(0) "" %unicode|string%(0) ""
[%u|b%"error_list"]=>
NULL
[%u|b%"field_count"]=> [%u|b%"field_count"]=>
NULL NULL
[%u|b%"host_info"]=> [%u|b%"host_info"]=>

View file

@ -131,6 +131,11 @@ require_once('skipifconnectfailure.inc');
$mysqli->error, gettype($mysqli->error), $mysqli->error, gettype($mysqli->error),
mysqli_error($link), gettype(mysqli_error($link))); mysqli_error($link), gettype(mysqli_error($link)));
assert(mysqli_error_list($link) === $mysqli->error_list);
printf("mysqli->error_list = '%s'/%s ('%s'/%s)\n",
$mysqli->error_list, gettype($mysqli->error_list),
mysqli_error_list($link), gettype(mysqli_error_list($link)));
assert(mysqli_field_count($link) === $mysqli->field_count); assert(mysqli_field_count($link) === $mysqli->field_count);
printf("mysqli->field_count = '%s'/%s ('%s'/%s)\n", printf("mysqli->field_count = '%s'/%s ('%s'/%s)\n",
$mysqli->field_count, gettype($mysqli->field_count), $mysqli->field_count, gettype($mysqli->field_count),
@ -222,6 +227,7 @@ connect_errno
connect_error connect_error
errno errno
error error
error_list
field_count field_count
host_info host_info
info info
@ -241,6 +247,7 @@ connect_errno
connect_error connect_error
errno errno
error error
error_list
field_count field_count
host_info host_info
info info
@ -258,6 +265,7 @@ mysqli->client_info = '%s'/%unicode|string% ('%s'/%unicode|string%)
mysqli->client_version = '%d'/integer ('%d'/integer) mysqli->client_version = '%d'/integer ('%d'/integer)
mysqli->errno = '0'/integer ('0'/integer) mysqli->errno = '0'/integer ('0'/integer)
mysqli->error = ''/%unicode|string% (''/%unicode|string%) mysqli->error = ''/%unicode|string% (''/%unicode|string%)
mysqli->error_list = 'Array'/array ('Array'/array)
mysqli->field_count = '0'/integer ('0'/integer) mysqli->field_count = '0'/integer ('0'/integer)
mysqli->insert_id = '0'/integer ('0'/integer) mysqli->insert_id = '0'/integer ('0'/integer)
mysqli->sqlstate = '00000'/%unicode|string% ('00000'/%unicode|string%) mysqli->sqlstate = '00000'/%unicode|string% ('00000'/%unicode|string%)

View file

@ -151,6 +151,7 @@ connect_errno = '%s'
connect_error = ''%s' connect_error = ''%s'
errno = 'NULL' errno = 'NULL'
error = 'NULL' error = 'NULL'
error_list = 'NULL'
field_count = 'NULL' field_count = 'NULL'
host_info = 'NULL' host_info = 'NULL'
info = 'NULL' info = 'NULL'
@ -170,6 +171,7 @@ connect_errno = '%s'
connect_error = '%s' connect_error = '%s'
errno = 'NULL' errno = 'NULL'
error = 'NULL' error = 'NULL'
error_list = 'NULL'
field_count = 'NULL' field_count = 'NULL'
host_info = 'NULL' host_info = 'NULL'
info = 'NULL' info = 'NULL'
@ -220,6 +222,7 @@ connect_errno = '%s'
connect_error = '%s' connect_error = '%s'
errno = 'NULL' errno = 'NULL'
error = 'NULL' error = 'NULL'
error_list = 'NULL'
field_count = 'NULL' field_count = 'NULL'
host_info = 'NULL' host_info = 'NULL'
info = 'NULL' info = 'NULL'
@ -239,6 +242,7 @@ connect_errno = '%s'
connect_error = '%s' connect_error = '%s'
errno = 'NULL' errno = 'NULL'
error = 'NULL' error = 'NULL'
error_list = 'NULL'
field_count = 'NULL' field_count = 'NULL'
host_info = 'NULL' host_info = 'NULL'
info = 'NULL' info = 'NULL'

View file

@ -1129,6 +1129,14 @@ isStatic: no
isDefault: yes isDefault: yes
Modifiers: 256 Modifiers: 256
Inspecting property 'error_list'
isPublic: yes
isPrivate: no
isProtected: no
isStatic: no
isDefault: yes
Modifiers: 256
Inspecting property 'field_count' Inspecting property 'field_count'
isPublic: yes isPublic: yes
isPrivate: no isPrivate: no
@ -1215,6 +1223,7 @@ Default property 'connect_errno'
Default property 'connect_error' Default property 'connect_error'
Default property 'errno' Default property 'errno'
Default property 'error' Default property 'error'
Default property 'error_list'
Default property 'field_count' Default property 'field_count'
Default property 'host_info' Default property 'host_info'
Default property 'info' Default property 'info'

View file

@ -97,6 +97,9 @@ printf("stmt->errno = '%s'\n", $stmt->errno);
assert(mysqli_stmt_error($stmt) === $stmt->error); assert(mysqli_stmt_error($stmt) === $stmt->error);
printf("stmt->error = '%s'\n", $stmt->error); printf("stmt->error = '%s'\n", $stmt->error);
assert(mysqli_stmt_error_list($stmt) === $stmt->error_list);
var_dump("stmt->error = ", $stmt->error_list);
assert(mysqli_stmt_field_count($stmt) === $stmt->field_count); assert(mysqli_stmt_field_count($stmt) === $stmt->field_count);
printf("stmt->field_count = '%s'\n", $stmt->field_count); printf("stmt->field_count = '%s'\n", $stmt->field_count);
@ -143,6 +146,7 @@ Class variables:
affected_rows affected_rows
errno errno
error error
error_list
field_count field_count
id id
insert_id insert_id
@ -158,6 +162,7 @@ param_count
field_count field_count
errno errno
error error
error_list
sqlstate sqlstate
id id
@ -173,6 +178,9 @@ stmt->affected_rows = ''
stmt->affected_rows = '1' stmt->affected_rows = '1'
stmt->errno = '0' stmt->errno = '0'
stmt->error = '' stmt->error = ''
string(14) "stmt->error = "
array(0) {
}
stmt->field_count = '0' stmt->field_count = '0'
stmt->id = '%d' stmt->id = '%d'
stmt->insert_id = '0' stmt->insert_id = '0'

View file

@ -146,7 +146,7 @@ mysqli_connect()
print "done!"; print "done!";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: mysqli_connect(): (%d/%d): Access denied for user '%s'@'%s' (using password: YES) in %s on line %d Warning: mysqli_connect(): (%s/%d): Access denied for user '%s'@'%s' (using password: YES) in %s on line %d
array(1) { array(1) {
[%u|b%"testing"]=> [%u|b%"testing"]=>
%unicode|string%(21) "mysqli.default_socket" %unicode|string%(21) "mysqli.default_socket"

View file

@ -144,7 +144,7 @@ new mysqli()
print "done!"; print "done!";
?> ?>
--EXPECTF-- --EXPECTF--
Warning: mysqli::mysqli(): (%d/%d): Access denied for user '%sunknown%s'@'%s' (using password: %s) in %s on line %d Warning: mysqli::mysqli(): (%s/%d): Access denied for user '%sunknown%s'@'%s' (using password: %s) in %s on line %d
... and now Exceptions ... and now Exceptions
Access denied for user '%s'@'%s' (using password: %s) Access denied for user '%s'@'%s' (using password: %s)
done! done!

View file

@ -96,6 +96,18 @@ object(mysqli)#%d (%d) {
int(2006) int(2006)
[%u|b%"error"]=> [%u|b%"error"]=>
%unicode|string%(%d) "%s" %unicode|string%(%d) "%s"
[%u|b%"error_list"]=>
array(1) {
[0]=>
array(3) {
[%u|b%"errno"]=>
int(2006)
[%u|b%"sqlstate"]=>
%unicode|string%(5) "%s"
[%u|b%"error"]=>
%unicode|string%(%d) "%s"
}
}
[%u|b%"field_count"]=> [%u|b%"field_count"]=>
int(0) int(0)
[%u|b%"host_info"]=> [%u|b%"host_info"]=>

View file

@ -175,7 +175,7 @@ require_once('skipifconnectfailure.inc');
require_once("clean_table.inc"); require_once("clean_table.inc");
?> ?>
--EXPECTF-- --EXPECTF--
Warning: mysqli_real_connect(): (%d/%d): Access denied for user '%s'@'%s' (using password: YES) in %s on line %d Warning: mysqli_real_connect(): (%s/%d): Access denied for user '%s'@'%s' (using password: YES) in %s on line %d
object(mysqli)#%d (%d) { object(mysqli)#%d (%d) {
[%u|b%"affected_rows"]=> [%u|b%"affected_rows"]=>
NULL NULL
@ -191,6 +191,8 @@ object(mysqli)#%d (%d) {
%s %s
[%u|b%"error"]=> [%u|b%"error"]=>
%s %s
[%u|b%"error_list"]=>
NULL
[%u|b%"field_count"]=> [%u|b%"field_count"]=>
NULL NULL
[%u|b%"host_info"]=> [%u|b%"host_info"]=>

View file

@ -151,5 +151,5 @@ mysqli.max_persistent=10
require_once("clean_table.inc"); require_once("clean_table.inc");
?> ?>
--EXPECTF-- --EXPECTF--
Warning: mysqli_real_connect(): (%d/%d): Access denied for user '%s'@'%s' (using password: YES) in %s on line %d Warning: mysqli_real_connect(): (%s/%d): Access denied for user '%s'@'%s' (using password: YES) in %s on line %d
done! done!

View file

@ -69,6 +69,21 @@ static struct st_mysqlnd_conn_methods *mysqlnd_conn_methods;
static struct st_mysqlnd_plugin_core mysqlnd_plugin_core; static struct st_mysqlnd_plugin_core mysqlnd_plugin_core;
/* {{{ mysqlnd_error_list_pdtor */
static void
mysqlnd_error_list_pdtor(void * pDest)
{
MYSQLND_ERROR_LIST_ELEMENT * element = (MYSQLND_ERROR_LIST_ELEMENT *) pDest;
TSRMLS_FETCH();
DBG_ENTER("mysqlnd_error_list_pdtor");
if (element->error) {
mnd_pefree(element->error, TRUE);
}
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_library_end */ /* {{{ mysqlnd_library_end */
PHPAPI void mysqlnd_library_end(TSRMLS_D) PHPAPI void mysqlnd_library_end(TSRMLS_D)
{ {
@ -178,6 +193,11 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND * conn TSRMLS_DC)
mnd_pefree(conn->last_message, pers); mnd_pefree(conn->last_message, pers);
conn->last_message = NULL; conn->last_message = NULL;
} }
if (conn->error_info.error_list) {
zend_llist_clean(conn->error_info.error_list);
mnd_pefree(conn->error_info.error_list, pers);
conn->error_info.error_list = NULL;
}
conn->charset = NULL; conn->charset = NULL;
conn->greet_charset = NULL; conn->greet_charset = NULL;
@ -2492,6 +2512,14 @@ PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC)
ret = NULL; ret = NULL;
} }
ret->error_info.error_list = mnd_pecalloc(1, sizeof(zend_llist), persistent);
if (!ret->error_info.error_list) {
ret->m->dtor(ret TSRMLS_CC);
ret = NULL;
} else {
zend_llist_init(ret->error_info.error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t)mysqlnd_error_list_pdtor, persistent);
}
DBG_RETURN(ret); DBG_RETURN(ret);
} }
/* }}} */ /* }}} */

View file

@ -137,8 +137,7 @@ mysqlnd_auth_handshake(MYSQLND * conn,
strlcpy(conn->error_info.sqlstate, auth_resp_packet->sqlstate, sizeof(conn->error_info.sqlstate)); strlcpy(conn->error_info.sqlstate, auth_resp_packet->sqlstate, sizeof(conn->error_info.sqlstate));
DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", auth_resp_packet->error_no, auth_resp_packet->sqlstate, auth_resp_packet->error); DBG_ERR_FMT("ERROR:%u [SQLSTATE:%s] %s", auth_resp_packet->error_no, auth_resp_packet->sqlstate, auth_resp_packet->error);
} }
conn->error_info.error_no = auth_resp_packet->error_no; SET_CLIENT_ERROR(conn->error_info, auth_resp_packet->error_no, UNKNOWN_SQLSTATE, auth_resp_packet->error);
strlcpy(conn->error_info.error, auth_resp_packet->error, sizeof(conn->error_info.error));
} }
goto end; goto end;
} }
@ -235,7 +234,7 @@ mysqlnd_auth_change_user(MYSQLND * const conn,
} }
ret = PACKET_READ(chg_user_resp, conn); ret = PACKET_READ(chg_user_resp, conn);
conn->error_info = chg_user_resp->error_info; COPY_CLIENT_ERROR(conn->error_info, chg_user_resp->error_info);
if (0xFE == chg_user_resp->response_code) { if (0xFE == chg_user_resp->response_code) {
ret = FAIL; ret = FAIL;

View file

@ -181,11 +181,12 @@ mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_w
/* init handler: allocate read buffer and open file */ /* init handler: allocate read buffer and open file */
if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) { if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) {
char tmp_buf[sizeof(conn->error_info.error)];
int tmp_error_no;
*is_warning = TRUE; *is_warning = TRUE;
/* error occured */ /* error occured */
strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE); tmp_error_no = infile.local_infile_error(info, tmp_buf, sizeof(tmp_buf) TSRMLS_CC);
conn->error_info.error_no = SET_CLIENT_ERROR(conn->error_info, tmp_error_no, UNKNOWN_SQLSTATE, tmp_buf);
infile.local_infile_error(info, conn->error_info.error, sizeof(conn->error_info.error) TSRMLS_CC);
/* write empty packet to server */ /* write empty packet to server */
ret = conn->net->m.send(conn, empty_packet, 0 TSRMLS_CC); ret = conn->net->m.send(conn, empty_packet, 0 TSRMLS_CC);
goto infile_error; goto infile_error;
@ -208,11 +209,12 @@ mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_w
/* error during read occured */ /* error during read occured */
if (bufsize < 0) { if (bufsize < 0) {
char tmp_buf[sizeof(conn->error_info.error)];
int tmp_error_no;
*is_warning = TRUE; *is_warning = TRUE;
DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn); DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE); tmp_error_no = infile.local_infile_error(info, tmp_buf, sizeof(tmp_buf) TSRMLS_CC);
conn->error_info.error_no = SET_CLIENT_ERROR(conn->error_info, tmp_error_no, UNKNOWN_SQLSTATE, tmp_buf);
infile.local_infile_error(info, conn->error_info.error, sizeof(conn->error_info.error) TSRMLS_CC);
goto infile_error; goto infile_error;
} }

View file

@ -134,15 +134,41 @@
(error_info).error_no = 0; \ (error_info).error_no = 0; \
(error_info).error[0] = '\0'; \ (error_info).error[0] = '\0'; \
strlcpy((error_info).sqlstate, "00000", sizeof((error_info).sqlstate)); \ strlcpy((error_info).sqlstate, "00000", sizeof((error_info).sqlstate)); \
if ((error_info).error_list) { \
zend_llist_clean((error_info).error_list); \
} \
} }
#define SET_CLIENT_ERROR(error_info, a, b, c) \ #define SET_CLIENT_ERROR(error_info, a, b, c) \
{ \ { \
if (0 == (a)) { \
SET_EMPTY_ERROR((error_info)); \
} else { \
(error_info).error_no = (a); \ (error_info).error_no = (a); \
strlcpy((error_info).sqlstate, (b), sizeof((error_info).sqlstate)); \ strlcpy((error_info).sqlstate, (b), sizeof((error_info).sqlstate)); \
strlcpy((error_info).error, (c), sizeof((error_info).error)); \ strlcpy((error_info).error, (c), sizeof((error_info).error)); \
if ((error_info).error_list) {\
MYSQLND_ERROR_LIST_ELEMENT error_for_the_list = {0}; \
\
error_for_the_list.error_no = (a); \
strlcpy(error_for_the_list.sqlstate, (b), sizeof(error_for_the_list.sqlstate)); \
error_for_the_list.error = mnd_pestrdup((c), TRUE); \
if (error_for_the_list.error) { \
DBG_INF_FMT("adding error [%s] to the list", error_for_the_list.error); \
zend_llist_add_element((error_info).error_list, &error_for_the_list); \
} \
} \
} \
}
#define COPY_CLIENT_ERROR(error_info_to, error_info_from) \
{ \
SET_CLIENT_ERROR((error_info_to), (error_info_from).error_no, (error_info_from).sqlstate, (error_info_from).error); \
} }
#define SET_OOM_ERROR(error_info) SET_CLIENT_ERROR((error_info), CR_OUT_OF_MEMORY, UNKNOWN_SQLSTATE, mysqlnd_out_of_memory) #define SET_OOM_ERROR(error_info) SET_CLIENT_ERROR((error_info), CR_OUT_OF_MEMORY, UNKNOWN_SQLSTATE, mysqlnd_out_of_memory)

View file

@ -52,6 +52,22 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param,
static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt 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, unsigned int param_no TSRMLS_DC); static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC);
/* {{{ mysqlnd_ps_error_list_pdtor */
static void
mysqlnd_ps_error_list_pdtor(void * pDest)
{
MYSQLND_ERROR_LIST_ELEMENT * element = (MYSQLND_ERROR_LIST_ELEMENT *) pDest;
TSRMLS_FETCH();
DBG_ENTER("mysqlnd_ps_error_list_pdtor");
if (element->error) {
mnd_pefree(element->error, TRUE);
}
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_stmt::store_result */ /* {{{ mysqlnd_stmt::store_result */
static MYSQLND_RES * static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
@ -110,7 +126,7 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED; stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
} else { } else {
conn->error_info = result->stored_data->error_info; COPY_CLIENT_ERROR(conn->error_info, result->stored_data->error_info);
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC); stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
mnd_efree(stmt->result); mnd_efree(stmt->result);
stmt->result = NULL; stmt->result = NULL;
@ -177,7 +193,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
stmt->state = MYSQLND_STMT_PREPARED; stmt->state = MYSQLND_STMT_PREPARED;
result->type = MYSQLND_RES_PS_BUF; result->type = MYSQLND_RES_PS_BUF;
} else { } else {
stmt->error_info = conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, conn->error_info);
stmt->state = MYSQLND_STMT_PREPARED; stmt->state = MYSQLND_STMT_PREPARED;
break; break;
} }
@ -300,7 +316,8 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
} }
if (0xFF == prepare_resp->error_code) { if (0xFF == prepare_resp->error_code) {
stmt->error_info = stmt->conn->error_info = prepare_resp->error_info; COPY_CLIENT_ERROR(stmt->error_info, prepare_resp->error_info);
COPY_CLIENT_ERROR(stmt->conn->error_info, prepare_resp->error_info);
goto done; goto done;
} }
ret = PASS; ret = PASS;
@ -484,7 +501,7 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC)
ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC); ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC);
if (ret == FAIL) { if (ret == FAIL) {
stmt->error_info = conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, conn->error_info);
stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows; stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) { if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
/* close the statement here, the connection has been closed */ /* close the statement here, the connection has been closed */
@ -685,7 +702,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
} }
if (ret == FAIL) { if (ret == FAIL) {
stmt->error_info = conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, conn->error_info);
DBG_INF("FAIL"); DBG_INF("FAIL");
DBG_RETURN(FAIL); DBG_RETURN(FAIL);
} }
@ -902,8 +919,8 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
*fetched_anything = TRUE; *fetched_anything = TRUE;
} else if (ret == FAIL) { } else if (ret == FAIL) {
if (row_packet->error_info.error_no) { if (row_packet->error_info.error_no) {
stmt->conn->error_info = row_packet->error_info; COPY_CLIENT_ERROR(stmt->conn->error_info, row_packet->error_info);
stmt->error_info = row_packet->error_info; COPY_CLIENT_ERROR(stmt->error_info, row_packet->error_info);
} }
CONN_SET_STATE(result->conn, CONN_READY); CONN_SET_STATE(result->conn, CONN_READY);
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
@ -1014,7 +1031,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, buf, sizeof(buf), if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, buf, sizeof(buf),
PROT_LAST /* we will handle the response packet*/, PROT_LAST /* we will handle the response packet*/,
FALSE, TRUE TSRMLS_CC)) { FALSE, TRUE TSRMLS_CC)) {
stmt->error_info = stmt->conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, stmt->conn->error_info);
DBG_RETURN(FAIL); DBG_RETURN(FAIL);
} }
@ -1218,7 +1235,7 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s TSRMLS_DC)
FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, cmd_buf, FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, cmd_buf,
sizeof(cmd_buf), PROT_OK_PACKET, sizeof(cmd_buf), PROT_OK_PACKET,
FALSE, TRUE TSRMLS_CC))) { FALSE, TRUE TSRMLS_CC))) {
stmt->error_info = conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, conn->error_info);
} }
stmt->upsert_status = conn->upsert_status; stmt->upsert_status = conn->upsert_status;
@ -1337,7 +1354,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned in
ret = conn->m->simple_command(conn, cmd, cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC); ret = conn->m->simple_command(conn, cmd, cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC);
mnd_efree(cmd_buf); mnd_efree(cmd_buf);
if (FAIL == ret) { if (FAIL == ret) {
stmt->error_info = conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, conn->error_info);
} }
} else { } else {
ret = FAIL; ret = FAIL;
@ -2117,6 +2134,11 @@ MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC
stmt->result->m.free_result_internal(stmt->result TSRMLS_CC); stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
stmt->result = NULL; stmt->result = NULL;
} }
if (stmt->error_info.error_list) {
zend_llist_clean(stmt->error_info.error_list);
mnd_pefree(stmt->error_info.error_list, s->persistent);
stmt->error_info.error_list = NULL;
}
DBG_VOID_RETURN; DBG_VOID_RETURN;
} }
@ -2174,7 +2196,7 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_boo
FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf), FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf),
PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/, PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
FALSE, TRUE TSRMLS_CC)) { FALSE, TRUE TSRMLS_CC)) {
stmt->error_info = conn->error_info; COPY_CLIENT_ERROR(stmt->error_info, conn->error_info);
DBG_RETURN(FAIL); DBG_RETURN(FAIL);
} }
} }
@ -2375,6 +2397,11 @@ MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
or normal query result will close it then. or normal query result will close it then.
*/ */
stmt->conn = conn->m->get_reference(conn TSRMLS_CC); stmt->conn = conn->m->get_reference(conn TSRMLS_CC);
stmt->error_info.error_list = mnd_pecalloc(1, sizeof(zend_llist), ret->persistent);
if (!stmt->error_info.error_list) {
break;
}
zend_llist_init(stmt->error_info.error_list, sizeof(MYSQLND_ERROR_LIST_ELEMENT), (llist_dtor_func_t) mysqlnd_ps_error_list_pdtor, conn->persistent);
DBG_RETURN(ret); DBG_RETURN(ret);
} while (0); } while (0);

View file

@ -400,7 +400,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC)
This will copy the error code and the messages, as they This will copy the error code and the messages, as they
are buffers in the struct are buffers in the struct
*/ */
conn->error_info = rset_header->error_info; COPY_CLIENT_ERROR(conn->error_info, rset_header->error_info);
ret = FAIL; ret = FAIL;
DBG_ERR_FMT("error=%s", rset_header->error_info.error); DBG_ERR_FMT("error=%s", rset_header->error_info.error);
/* Return back from CONN_QUERY_SENT */ /* Return back from CONN_QUERY_SENT */
@ -705,7 +705,7 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC)
} }
} else if (ret == FAIL) { } else if (ret == FAIL) {
if (row_packet->error_info.error_no) { if (row_packet->error_info.error_no) {
result->conn->error_info = row_packet->error_info; COPY_CLIENT_ERROR(result->conn->error_info, row_packet->error_info);
DBG_ERR_FMT("errorno=%u error=%s", row_packet->error_info.error_no, row_packet->error_info.error); DBG_ERR_FMT("errorno=%u error=%s", row_packet->error_info.error_no, row_packet->error_info.error);
} }
CONN_SET_STATE(result->conn, CONN_READY); CONN_SET_STATE(result->conn, CONN_READY);
@ -840,7 +840,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla
result->unbuf->row_count++; result->unbuf->row_count++;
} else if (ret == FAIL) { } else if (ret == FAIL) {
if (row_packet->error_info.error_no) { if (row_packet->error_info.error_no) {
result->conn->error_info = row_packet->error_info; COPY_CLIENT_ERROR(result->conn->error_info, row_packet->error_info);
DBG_ERR_FMT("errorno=%u error=%s", row_packet->error_info.error_no, row_packet->error_info.error); DBG_ERR_FMT("errorno=%u error=%s", row_packet->error_info.error_no, row_packet->error_info.error);
} }
CONN_SET_STATE(result->conn, CONN_READY); CONN_SET_STATE(result->conn, CONN_READY);
@ -1228,7 +1228,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL
} }
if (ret == FAIL) { if (ret == FAIL) {
set->error_info = row_packet->error_info; COPY_CLIENT_ERROR(set->error_info, row_packet->error_info);
} else { } else {
/* Position at the first row */ /* Position at the first row */
set->data_cursor = set->data; set->data_cursor = set->data;
@ -1277,7 +1277,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
ret = result->m.store_result_fetch_data(conn, result, result->meta, ps_protocol TSRMLS_CC); ret = result->m.store_result_fetch_data(conn, result, result->meta, ps_protocol TSRMLS_CC);
if (FAIL == ret) { if (FAIL == ret) {
if (result->stored_data) { if (result->stored_data) {
conn->error_info = result->stored_data->error_info; COPY_CLIENT_ERROR(conn->error_info, result->stored_data->error_info);
} else { } else {
SET_OOM_ERROR(conn->error_info); SET_OOM_ERROR(conn->error_info);
} }

View file

@ -170,7 +170,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met
DBG_RETURN(FAIL); DBG_RETURN(FAIL);
} }
if (field_packet->error_info.error_no) { if (field_packet->error_info.error_no) {
conn->error_info = field_packet->error_info; COPY_CLIENT_ERROR(conn->error_info, field_packet->error_info);
/* Return back from CONN_QUERY_SENT */ /* Return back from CONN_QUERY_SENT */
PACKET_FREE(field_packet); PACKET_FREE(field_packet);
DBG_RETURN(FAIL); DBG_RETURN(FAIL);

View file

@ -102,9 +102,18 @@ typedef struct st_mysqlnd_error_info
char error[MYSQLND_ERRMSG_SIZE+1]; char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1]; char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no; unsigned int error_no;
zend_llist * error_list;
} MYSQLND_ERROR_INFO; } MYSQLND_ERROR_INFO;
typedef struct st_mysqlnd_error_list_element
{
char * error;
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no;
} MYSQLND_ERROR_LIST_ELEMENT;
typedef struct st_mysqlnd_infile_info typedef struct st_mysqlnd_infile_info
{ {
php_stream *fd; php_stream *fd;