<file role="src" name="mysql.mak"/>
<file role="src" name="php_mysql.c"/>
<file role="src" name="php_mysql.h"/>
+ <file role="src" name="mysql_mysqlnd.h"/>
<file role="test" name="tests/001.phpt"/>
<file role="test" name="tests/002.phpt"/>
<file role="test" name="tests/003.phpt"/>
/*
+----------------------------------------------------------------------+
- | PHP Version 5 |
+ | PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
/* {{{ mysql_functions[]
*/
-const zend_function_entry mysql_functions[] = {
+static const zend_function_entry mysql_functions[] = {
PHP_FE(mysql_connect, NULL)
PHP_FE(mysql_pconnect, NULL)
PHP_FE(mysql_close, NULL)
#if MYSQL_VERSION_ID >= 40000
#ifdef PHP_WIN32
unsigned long client_ver = mysql_get_client_version();
- /* Can't call mysql_server_end() multiple times prior to 5.0.42 on Windows */
- if ((client_ver > 50042 && client_ver < 50100) || client_ver > 50122) {
+ /*
+ Can't call mysql_server_end() multiple times prior to 5.0.42 on Windows.
+ PHP bug#41350 MySQL bug#25621
+ */
+ if ((client_ver >= 50042 && client_ver < 50100) || client_ver > 50122) {
mysql_server_end();
}
#else
/* Now we kind of realloc() by returning a zval pointing to a buffer with enough size */
RETVAL_UTF8_STRINGL(new_str, new_str_len, ZSTR_DUPLICATE);
efree(new_str);
+ if (MySG(trace_mode)){
+ php_error_docref("function.mysql-real-escape-string" TSRMLS_CC, E_WARNING, "This function is deprecated; use mysql_real_escape_string() instead.");
+ }
}
/* }}} */
static int le_pmysqli;
-/* Destructor for Persistent Connections */
-ZEND_RSRC_DTOR_FUNC(php_mysqli_dtor)
+
+static int php_mysqli_persistent_on_rshut(zend_rsrc_list_entry *le TSRMLS_DC)
{
- if (rsrc->ptr) {
- MYSQL *mysql = (MYSQL *)rsrc->ptr;
+ if (le->type == le_pmysqli) {
+ mysqli_plist_entry *plist = (mysqli_plist_entry *) le->ptr;
+ HashPosition pos;
+ MYSQL **mysql;
+ ulong idx;
+ dtor_func_t pDestructor = plist->used_links.pDestructor;
+ plist->used_links.pDestructor = NULL; /* Don't call pDestructor now */
+
+ zend_hash_internal_pointer_reset_ex(&plist->used_links, &pos);
+ while (SUCCESS == zend_hash_get_current_data_ex(&plist->used_links, (void **)&mysql, &pos)) {
+ zend_hash_get_current_key_ex(&plist->used_links, NULL, NULL, &idx, FALSE, &pos);
+ /* Make it free */
+ zend_hash_next_index_insert(&plist->free_links, mysql, sizeof(MYSQL *), NULL);
+ /* First move forward */
+ zend_hash_move_forward_ex(&plist->used_links, &pos);
+ /* The delete, because del will free memory, but we need it's ->nextItem */
+ zend_hash_index_del(&plist->used_links, idx);
+ }
+
+ /* restore pDestructor, which should be php_mysqli_dtor_p_elements() */
+ plist->used_links.pDestructor = pDestructor;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+
+/* Destructor for mysqli entries in free_links/used_links */
+void php_mysqli_dtor_p_elements(void *data)
+{
+ MYSQL **mysql = (MYSQL **) data;
+ TSRMLS_FETCH();
#if defined(HAVE_MYSQLND)
- mysqlnd_end_psession(mysql);
+ mysqlnd_end_psession(*mysql);
#endif
- mysqli_close(mysql, MYSQLI_CLOSE_IMPLICIT);
+ mysqli_close(*mysql, MYSQLI_CLOSE_IMPLICIT);
+}
+
+
+ZEND_RSRC_DTOR_FUNC(php_mysqli_dtor)
+{
+ if (rsrc->ptr) {
+ mysqli_plist_entry *plist = (mysqli_plist_entry *) rsrc->ptr;
+ zend_hash_destroy(&plist->free_links);
+ zend_hash_destroy(&plist->used_links);
+ free(plist);
}
}
/* {{{ php_clear_mysql */
void php_clear_mysql(MY_MYSQL *mysql) {
+ if (mysql->hash_key) {
+ efree(mysql->hash_key);
+ mysql->hash_key = NULL;
+ }
if (mysql->li_read) {
efree(Z_STRVAL_P(mysql->li_read));
FREE_ZVAL(mysql->li_read);
*/
PHP_INI_BEGIN()
STD_PHP_INI_ENTRY_EX("mysqli.max_links", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_links, zend_mysqli_globals, mysqli_globals, display_link_numbers)
+ STD_PHP_INI_ENTRY_EX("mysqli.max_persistent", "-1", PHP_INI_SYSTEM, OnUpdateLong, max_persistent, zend_mysqli_globals, mysqli_globals, display_link_numbers)
+ STD_PHP_INI_BOOLEAN("mysqli.allow_persistent", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_persistent, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_host", NULL, PHP_INI_ALL, OnUpdateString, default_host, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_user", NULL, PHP_INI_ALL, OnUpdateString, default_user, zend_mysqli_globals, mysqli_globals)
STD_PHP_INI_ENTRY("mysqli.default_pw", NULL, PHP_INI_ALL, OnUpdateString, default_pw, zend_mysqli_globals, mysqli_globals)
static PHP_GINIT_FUNCTION(mysqli)
{
mysqli_globals->num_links = 0;
+ mysqli_globals->num_active_persistent = 0;
+ mysqli_globals->num_inactive_persistent = 0;
mysqli_globals->max_links = -1;
+ mysqli_globals->max_persistent = -1;
+ mysqli_globals->allow_persistent = 1;
mysqli_globals->default_port = 0;
mysqli_globals->default_host = NULL;
mysqli_globals->default_user = NULL;
REGISTER_INI_ENTRIES();
#ifndef HAVE_MYSQLND
+#if MYSQL_VERSION_ID >= 40000
if (mysql_server_init(0, NULL, NULL)) {
return FAILURE;
}
+#endif
#else
mysqli_mysqlnd_zval_cache = mysqlnd_palloc_init_cache(MyG(cache_size));
mysqli_mysqlnd_qcache = mysqlnd_qcache_init_cache();
REGISTER_LONG_CONSTANT("MYSQLI_INIT_COMMAND", MYSQL_INIT_COMMAND, CONST_CS | CONST_PERSISTENT);
#if defined(HAVE_MYSQLND)
REGISTER_LONG_CONSTANT("MYSQLI_OPT_NUMERIC_AND_DATETIME_AS_UNICODE", MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("MYSQLI_OPT_NET_CMD_BUFFER_SIZE", MYSQLND_OPT_NET_CMD_BUFFER_SIZE, CONST_CS | CONST_PERSISTENT);
+ REGISTER_LONG_CONSTANT("MYSQLI_OPT_NET_READ_BUFFER_SIZE", MYSQLND_OPT_NET_READ_BUFFER_SIZE, CONST_CS | CONST_PERSISTENT);
#endif
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
REGISTER_LONG_CONSTANT("MYSQLI_OPT_INT_AND_YEAR_AS_INT", MYSQLND_OPT_INT_AND_YEAR_AS_INT, CONST_CS | CONST_PERSISTENT);
PHP_MSHUTDOWN_FUNCTION(mysqli)
{
#ifndef HAVE_MYSQLND
+#if MYSQL_VERSION_ID >= 40000
#ifdef PHP_WIN32
- unsigned long client_ver = mysql_get_client_version;
- /* Can't call mysql_server_end() multiple times prior to 5.0.42 on Windows */
- if ((client_ver > 50042 && client_ver < 50100) || client_ver > 50122) {
+ unsigned long client_ver = mysql_get_client_version();
+ /*
+ Can't call mysql_server_end() multiple times prior to 5.0.42 on Windows.
+ PHP bug#41350 MySQL bug#25621
+ */
+ if ((client_ver >= 50042 && client_ver < 50100) || client_ver > 50122) {
mysql_server_end();
}
#else
mysql_server_end();
#endif
+#endif
#else
mysqlnd_palloc_free_cache(mysqli_mysqlnd_zval_cache);
mysqlnd_qcache_free_cache_reference(&mysqli_mysqlnd_qcache);
*/
PHP_RINIT_FUNCTION(mysqli)
{
-#if !defined(HAVE_MYSQLND) && defined(ZTS)
+#if !defined(HAVE_MYSQLND) && defined(ZTS) && MYSQL_VERSION_ID >= 40000
if (mysql_thread_init()) {
return FAILURE;
}
*/
PHP_RSHUTDOWN_FUNCTION(mysqli)
{
-#if !defined(HAVE_MYSQLND) && defined(ZTS)
+ /* check persistent connections, move used to free */
+ zend_hash_apply(&EG(persistent_list), (apply_func_t) php_mysqli_persistent_on_rshut TSRMLS_CC);
+
+#if !defined(HAVE_MYSQLND) && defined(ZTS) && MYSQL_VERSION_ID >= 40000
mysql_thread_end();
#endif
if (MyG(error_msg)) {
*/
PHP_MINFO_FUNCTION(mysqli)
{
+#if defined(HAVE_MYSQLND)
+ char buf[32];
+#endif
+
php_info_print_table_start();
php_info_print_table_header(2, "MysqlI Support", "enabled");
php_info_print_table_row(2, "Client API library version", mysql_get_client_info());
php_info_print_table_row(2, "Client API header version", MYSQL_SERVER_VERSION);
php_info_print_table_row(2, "MYSQLI_SOCKET", MYSQL_UNIX_ADDR);
#else
+ snprintf(buf, sizeof(buf), "%ld", MyG(num_active_persistent));
+ php_info_print_table_row(2, "Active Persistent Links", buf);
+ snprintf(buf, sizeof(buf), "%ld", MyG(num_inactive_persistent));
+ php_info_print_table_row(2, "Inactive Persistent Links", buf);
+ snprintf(buf, sizeof(buf), "%ld", MyG(num_links));
+ php_info_print_table_row(2, "Active Links", buf);
{
zval values;
}
/* }}} */
+#if !defined(HAVE_MYSQLND)
+
+
#define ALLOC_CALLBACK_ARGS(a, b, c)\
if (c) {\
a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\
#define LOCAL_INFILE_ERROR_MSG(source,dest)\
memset(source, 0, LOCAL_INFILE_ERROR_LEN);\
-memcpy(source, dest, LOCAL_INFILE_ERROR_LEN-1);\
+memcpy(source, dest, MIN(strlen(dest), LOCAL_INFILE_ERROR_LEN-1));\
php_error_docref(NULL TSRMLS_CC, E_WARNING, dest);
+
/* {{{ void php_set_local_infile_handler_default
*/
void php_set_local_infile_handler_default(MY_MYSQL *mysql) {
/* register internal callback functions */
-#if !defined(HAVE_MYSQLND)
mysql_set_local_infile_handler(mysql->mysql, &php_local_infile_init, &php_local_infile_read,
&php_local_infile_end, &php_local_infile_error, (void *)mysql);
if (mysql->li_read) {
zval_ptr_dtor(&mysql->li_read);
mysql->li_read = NULL;
}
-#else
- mysqlnd_local_infile_default(mysql->mysql, TRUE);
-#endif
}
/* }}} */
-#if !defined(HAVE_MYSQLND)
/* {{{ php_local_infile_init
*/
int php_local_infile_init(void **ptr, const char *filename, void *userdata)
LOCAL_INFILE_ERROR_MSG(data->error_msg, "Can't execute load data local init callback function");
rc = -1;
}
+ /*
+ If the (ab)user has closed the file handle we should
+ not try to use it anymore or even close it
+ */
+ if (!zend_rsrc_list_get_rsrc_type(Z_LVAL_P(fp) TSRMLS_CC)) {
+ LOCAL_INFILE_ERROR_MSG(data->error_msg, "File handle closed");
+ rc = -1;
+ /* Thus the end handler won't try to free already freed memory */
+ mysql->li_stream = NULL;
+ }
FREE_CALLBACK_ARGS(callback_args, 1, argc);
efree(fp);
}
return;
}
-
- php_stream_close(mysql->li_stream);
+ if (mysql->li_stream) {
+ php_stream_close(mysql->li_stream);
+ }
free(data);
return;
}
#include "php.h"
#include "php_ini.h"
+#include "php_globals.h"
#include "ext/standard/info.h"
#include "php_mysqli_structs.h"
RETURN_FALSE;
}
+ /* Change user resets the charset in the server, change it back */
+ if (UG(unicode)) {
+ mysql_set_character_set(mysql->mysql, "utf8");
+ }
+
RETURN_TRUE;
}
/* }}} */
MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_INITIALIZED);
- php_clear_mysql(mysql);
if (!mysql->persistent) {
mysqli_close(mysql->mysql, MYSQLI_CLOSE_EXPLICIT);
+ mysql->mysql = NULL;
+ } else {
+ zend_rsrc_list_entry *le;
+ if (zend_hash_find(&EG(persistent_list), mysql->hash_key, strlen(mysql->hash_key) + 1, (void **)&le) == SUCCESS) {
+ if (Z_TYPE_P(le) == php_le_pmysqli()) {
+ mysqli_plist_entry *plist = (mysqli_plist_entry *) le->ptr;
+ dtor_func_t pDestructor = plist->used_links.pDestructor;
+
+ plist->used_links.pDestructor = NULL; /* Don't call pDestructor now */
+ zend_hash_index_del(&plist->used_links, mysql->hash_index);
+ plist->used_links.pDestructor = pDestructor; /* Restore the destructor */
+
+ zend_hash_next_index_insert(&plist->free_links, &mysql->mysql, sizeof(MYSQL *), NULL);
+ MyG(num_links)--;
+ MyG(num_active_persistent)--;
+ MyG(num_inactive_persistent)++;
+ }
+ }
}
+ php_clear_mysql(mysql);
+
MYSQLI_CLEAR_RESOURCE(&mysql_link);
efree(mysql);
RETURN_TRUE;
/* {{{ proto void mysqli_set_local_infile_default(object link) U
unsets user defined handler for load local infile command */
+#if !defined(HAVE_MYSQLND)
PHP_FUNCTION(mysqli_set_local_infile_default)
{
MY_MYSQL *mysql;
MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID);
-#if !defined(HAVE_MYSQLND)
if (mysql->li_read) {
- efree(Z_STRVAL_P(mysql->li_read));
zval_dtor(mysql->li_read);
mysql->li_read = NULL;
}
-#else
- mysqlnd_local_infile_default(mysql->mysql, TRUE);
-#endif
}
/* }}} */
zval_dtor(&callback_name);
/* save callback function */
-#if !defined(HAVE_MYSQLND)
if (!mysql->li_read) {
MAKE_STD_ZVAL(mysql->li_read);
} else {
zval_dtor(mysql->li_read);
}
ZVAL_STRINGL(mysql->li_read, Z_STRVAL_P(callback_func), Z_STRLEN_P(callback_func), 1);
-#else
- mysqlnd_set_local_infile_handler(mysql->mysql, callback_func->value.str.val);
-#endif
RETURN_TRUE;
}
+#endif
/* }}} */
/* {{{ proto bool mysqli_more_results(object link) U
newstr_len = mysql_real_escape_string(mysql->mysql, newstr, escapestr, escapestr_len);
newstr = erealloc(newstr, newstr_len + 1);
- RETURN_UTF8_STRING(newstr, ZSTR_AUTOFREE);
+ RETURN_UTF8_STRINGL(newstr, newstr_len, ZSTR_AUTOFREE);
}
/* }}} */
int i = 0;
for (i = mysql_stmt_field_count(stmt->stmt) - 1; i >=0; --i) {
- if (stmt->stmt->fields && stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB) {
+ if (stmt->stmt->fields && (stmt->stmt->fields[i].type == MYSQL_TYPE_BLOB ||
+ stmt->stmt->fields[i].type == MYSQL_TYPE_MEDIUM_BLOB ||
+ stmt->stmt->fields[i].type == MYSQL_TYPE_LONG_BLOB))
+ {
my_bool tmp=1;
mysql_stmt_attr_set(stmt->stmt, STMT_ATTR_UPDATE_MAX_LENGTH, &tmp);
break;
((mysqli_object *) zend_object_store_get_object(getThis() TSRMLS_CC))->ptr = mysqli_resource;
}
-mysqli_property_entry mysqli_driver_property_entries[] = {
+const mysqli_property_entry mysqli_driver_property_entries[] = {
{"client_info", driver_client_info_read, NULL},
{"client_version", driver_client_version_read, NULL},
{"driver_version", driver_driver_version_read, NULL},
PHP_FE(mysqli_info, NULL)
PHP_FE(mysqli_insert_id, NULL)
PHP_FE(mysqli_kill, NULL)
+#if !defined(HAVE_MYSQLND)
PHP_FE(mysqli_set_local_infile_default, NULL)
PHP_FE(mysqli_set_local_infile_handler, NULL)
+#endif
PHP_FE(mysqli_more_results, NULL)
PHP_FE(mysqli_multi_query, NULL)
PHP_FE(mysqli_next_result, NULL)
PHP_FALIAS(get_warnings, mysqli_get_warnings, NULL)
PHP_FALIAS(init,mysqli_init,NULL)
PHP_FALIAS(kill,mysqli_kill,NULL)
+#if !defined(HAVE_MYSQLND)
PHP_FALIAS(set_local_infile_default,mysqli_set_local_infile_default,NULL)
PHP_FALIAS(set_local_infile_handler,mysqli_set_local_infile_handler,NULL)
+#endif
PHP_FALIAS(multi_query,mysqli_multi_query,NULL)
PHP_FALIAS(mysqli,mysqli_connect,NULL)
PHP_FALIAS(more_results,mysqli_more_results, NULL)
*/
-#ifndef MYSQL_MYSQLND_H
-#define MYSQL_MYSQLND_H
+#ifndef MYSQLI_MYSQLND_H
+#define MYSQLI_MYSQLND_H
#include "ext/mysqlnd/mysqlnd_libmysql_compat.h"
Open a connection to a mysql server */
PHP_FUNCTION(mysqli_connect)
{
- MY_MYSQL *mysql;
- MYSQLI_RESOURCE *mysqli_resource;
- zval *object = getThis();
- char *hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL;
- unsigned int hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0;
+ MY_MYSQL *mysql = NULL;
+ MYSQLI_RESOURCE *mysqli_resource = NULL;
+ zval *object = getThis();
+ char *hostname = NULL, *username=NULL, *passwd=NULL, *dbname=NULL, *socket=NULL;
+ unsigned int hostname_len = 0, username_len = 0, passwd_len = 0, dbname_len = 0, socket_len = 0;
zend_bool persistent = FALSE;
- long port=0;
+ long port = 0;
uint hash_len;
char *hash_key = NULL;
zend_bool new_connection = FALSE;
zend_rsrc_list_entry *le;
+ mysqli_plist_entry *plist = NULL;
if (getThis() && !ZEND_NUM_ARGS()) {
RETURN_NULL();
hostname = MyG(default_host);
}
- mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL));
- if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) {
- mysql->persistent = persistent = TRUE;
- hostname += 2;
-
- if (!strlen(hostname)) {
- hostname = MyG(default_host);
+ if (object && instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) {
+ mysqli_resource = ((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr;
+ if (mysqli_resource && mysqli_resource->ptr &&
+ mysqli_resource->status >= MYSQLI_STATUS_INITIALIZED)
+ {
+ mysql = (MY_MYSQL*)mysqli_resource->ptr;
+ php_clear_mysql(mysql);
+ if (mysql->mysql) {
+ mysqli_close(mysql->mysql, MYSQLI_CLOSE_EXPLICIT);
+ mysql->mysql = NULL;
+ }
}
+ }
+ if (!mysql) {
+ mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL));
+ }
- /* caclulate hash length: mysqli_ + Hostname + 5 (Port) + username + dbname + pw */
- hash_len = 7 + strlen(SAFE_STR(hostname)) + 5 + strlen(SAFE_STR(username))
- + strlen(SAFE_STR(dbname)) + strlen(SAFE_STR(passwd)) + 1;
-
- hash_key = emalloc(hash_len);
- hash_len = snprintf(hash_key, hash_len, "mysqli_%s%ld%s%s%s", SAFE_STR(hostname),
- port, SAFE_STR(username), SAFE_STR(dbname),
- SAFE_STR(passwd));
-
- /* check if we can reuse exisiting connection ... */
- if (zend_hash_find(&EG(persistent_list), hash_key, hash_len + 1, (void **)&le) == SUCCESS) {
- if (Z_TYPE_P(le) == php_le_pmysqli()) {
- mysql->mysql = (MYSQL *)le->ptr;
-
- /* reset variables */
- /* todo: option for ping or change_user */
+ if (strlen(SAFE_STR(hostname)) > 2 && !strncasecmp(hostname, "p:", 2)) {
+ hostname += 2;
+ if (!MyG(allow_persistent)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Persistent connections are disabled. Downgrading to normal");
+ } else {
+ mysql->persistent = persistent = TRUE;
+
+ if (!strlen(hostname)) {
+ hostname = MyG(default_host);
+ }
+
+ hash_len = spprintf(&hash_key, 0, "mysqli_%s%ld%s%s%s", SAFE_STR(hostname),
+ port, SAFE_STR(username), SAFE_STR(dbname),
+ SAFE_STR(passwd));
+
+ /* check if we can reuse exisiting connection ... */
+ if (zend_hash_find(&EG(persistent_list), hash_key, hash_len + 1, (void **)&le) == SUCCESS) {
+ if (Z_TYPE_P(le) == php_le_pmysqli()) {
+ plist = (mysqli_plist_entry *) le->ptr;
+
+ do {
+ if (zend_hash_num_elements(&plist->free_links)) {
+ HashPosition pos;
+ MYSQL **free_mysql;
+ ulong idx;
+ dtor_func_t pDestructor = plist->free_links.pDestructor;
+
+ zend_hash_internal_pointer_reset_ex(&plist->free_links, &pos);
+ if (SUCCESS != zend_hash_get_current_data_ex(&plist->free_links,
+ (void **)&free_mysql, &pos)) {
+ break;
+ }
+ if (HASH_KEY_IS_LONG != zend_hash_get_current_key_ex(&plist->free_links, NULL,
+ NULL, &idx, FALSE, &pos)) {
+ break;
+ }
+ mysql->mysql = *free_mysql;
+ plist->free_links.pDestructor = NULL; /* Don't call pDestructor now */
+ if (SUCCESS != zend_hash_index_del(&plist->free_links, idx)) {
+ plist->used_links.pDestructor = pDestructor; /* Restore the destructor */
+ break;
+ }
+ plist->used_links.pDestructor = pDestructor; /* Restore the destructor */
+ MyG(num_inactive_persistent)--;
+ MyG(num_active_persistent)++;
+
+ /* reset variables */
+ /* todo: option for ping or change_user */
#if G0
- if (!mysql_change_user(mysql->mysql, username, passwd, dbname)) {
+ if (!mysql_change_user(mysql->mysql, username, passwd, dbname)) {
+#else
+ if (!mysql_ping(mysql->mysql)) {
#endif
- if (!mysql_ping(mysql->mysql)) {
#ifdef HAVE_MYSQLND
- mysqlnd_restart_psession(mysql->mysql);
+ mysqlnd_restart_psession(mysql->mysql);
#endif
- goto end;
+ idx = zend_hash_next_free_element(&plist->used_links);
+ if (SUCCESS != zend_hash_next_index_insert(&plist->used_links, &free_mysql,
+ sizeof(MYSQL *), NULL)) {
+ php_mysqli_dtor_p_elements(free_mysql);
+ break;
+ }
+ mysql->hash_index = idx;
+ mysql->hash_key = hash_key;
+ goto end;
+ }
+ }
+ } while (0);
}
- /*
- Here we fall if the connection is not ok.
- When we update EG(persistent_list) with a new connection, this one will
- get destructed. No need to do it explicitly.
- */
- }
+ } else {
+ zend_rsrc_list_entry le;
+ le.type = php_le_pmysqli();
+ le.ptr = plist = calloc(1, sizeof(mysqli_plist_entry));
+
+ zend_hash_init(&plist->free_links, MAX(10, MyG(max_persistent)), NULL, php_mysqli_dtor_p_elements, 1);
+ zend_hash_init(&plist->used_links, MAX(10, MyG(max_persistent)), NULL, php_mysqli_dtor_p_elements, 1);
+ zend_hash_update(&EG(persistent_list), hash_key, hash_len + 1, (void *)&le, sizeof(le), NULL);
+ }
}
}
+ if (MyG(max_links) != -1 && MyG(num_links) >= MyG(max_links)) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open links (%ld)", MyG(num_links));
+ goto err;
+ }
+ if (persistent && MyG(max_persistent) != -1 &&
+ (MyG(num_active_persistent) + MyG(num_inactive_persistent))>= MyG(max_persistent))
+ {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Too many open persistent links (%ld)",
+ MyG(num_active_persistent) + MyG(num_inactive_persistent));
+ goto err;
+ }
+
#if !defined(HAVE_MYSQLND)
if (!(mysql->mysql = mysql_init(NULL))) {
#else
if (!(mysql->mysql = mysqlnd_init(persistent))) {
#endif
- efree(mysql);
- if (persistent) {
- efree(hash_key);
- }
- RETURN_FALSE;
+ goto err;
}
new_connection = TRUE;
mysql_options(mysql->mysql, MYSQL_SET_CHARSET_NAME, "utf8");
}
-
#ifdef HAVE_EMBEDDED_MYSQLI
if (hostname_len) {
unsigned int external=1;
/* free mysql structure */
mysqli_close(mysql->mysql, MYSQLI_CLOSE_DISCONNECTED);
- efree(mysql);
- if (persistent) {
- efree(hash_key);
- }
- RETURN_FALSE;
+ goto err;
}
/* when PHP runs in unicode, set default character set to utf8 */
mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&MyG(allow_local_infile));
end:
- mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
- mysqli_resource->ptr = (void *)mysql;
+ if (!mysqli_resource) {
+ mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
+ mysqli_resource->ptr = (void *)mysql;
+ }
mysqli_resource->status = MYSQLI_STATUS_VALID;
/* store persistent connection */
if (persistent && new_connection) {
- zend_rsrc_list_entry le;
-
- le.type = php_le_pmysqli();
- le.ptr = mysql->mysql;
-
+ ulong hash_index = zend_hash_next_free_element(&plist->used_links);
/* save persistent connection */
- if (zend_hash_update(&EG(persistent_list), hash_key, hash_len + 1, (void *)&le,
- sizeof(le), NULL) == FAILURE) {
+ if (SUCCESS != zend_hash_next_index_insert(&plist->used_links, &mysql->mysql,
+ sizeof(MYSQL *), NULL)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't store persistent connection");
- }
- }
- if (persistent) {
- efree(hash_key);
+ } else {
+ mysql->hash_index = hash_index;
+ }
+ MyG(num_active_persistent)++;
}
+ mysql->hash_key = hash_key;
+ MyG(num_links)++;
+
#if !defined(HAVE_MYSQLND)
mysql->multi_query = 0;
#else
mysql->multi_query = 1;
#endif
+
if (!object || !instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) {
MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_link_class_entry);
} else {
((mysqli_object *) zend_object_store_get_object(object TSRMLS_CC))->ptr = mysqli_resource;
}
+ return;
+
+err:
+ efree(mysql);
+ if (persistent) {
+ efree(hash_key);
+ }
+ RETVAL_FALSE;
}
/* }}} */
MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_sqlstate_read, mysql_stmt_sqlstate, MYSQLI_GET_STMT(MYSQLI_STATUS_INITIALIZED));
/* }}} */
-mysqli_property_entry mysqli_link_property_entries[] = {
+const mysqli_property_entry mysqli_link_property_entries[] = {
{"affected_rows", link_affected_rows_read, NULL},
{"client_info", link_client_info_read, NULL},
{"client_version", link_client_version_read, NULL},
{NULL, NULL, NULL}
};
-mysqli_property_entry mysqli_result_property_entries[] = {
+const mysqli_property_entry mysqli_result_property_entries[] = {
{"current_field", result_current_field_read, NULL},
{"field_count", result_field_count_read, NULL},
{"lengths", result_lengths_read, NULL},
{NULL, NULL, NULL}
};
-mysqli_property_entry mysqli_stmt_property_entries[] = {
+const mysqli_property_entry mysqli_stmt_property_entries[] = {
{"affected_rows", stmt_affected_rows_read, NULL},
{"insert_id", stmt_insert_id_read, NULL},
{"num_rows", stmt_num_rows_read, NULL},
/* }}} */
/* {{{ mysqli_warning_property_entries */
-mysqli_property_entry mysqli_warning_property_entries[] = {
+const mysqli_property_entry mysqli_warning_property_entries[] = {
{"message", mysqli_warning_message, NULL},
{"sqlstate", mysqli_warning_sqlstate, NULL},
{"errno", mysqli_warning_errno, NULL},
/*
+----------------------------------------------------------------------+
- | PHP Version 5 |
+ | PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2007 The PHP Group |
+----------------------------------------------------------------------+
typedef struct {
MYSQL *mysql;
+ char *hash_key;
zval *li_read;
php_stream *li_stream;
zend_bool persistent;
+ unsigned long hash_index; /* Used when persistent, hold the index in plist->used_links */
unsigned int multi_query;
UConverter *conv;
} MY_MYSQL;
} mysqli_local_infile;
#endif
+typedef struct {
+ HashTable free_links;
+ HashTable used_links;
+} mysqli_plist_entry;
+
#ifdef PHP_WIN32
#define PHP_MYSQLI_API __declspec(dllexport)
#define MYSQLI_LLU_SPEC "%I64u"
extern const zend_function_entry mysqli_warning_methods[];
extern const zend_function_entry mysqli_exception_methods[];
-extern mysqli_property_entry mysqli_link_property_entries[];
-extern mysqli_property_entry mysqli_result_property_entries[];
-extern mysqli_property_entry mysqli_stmt_property_entries[];
-extern mysqli_property_entry mysqli_driver_property_entries[];
-extern mysqli_property_entry mysqli_warning_property_entries[];
+extern const mysqli_property_entry mysqli_link_property_entries[];
+extern const mysqli_property_entry mysqli_result_property_entries[];
+extern const mysqli_property_entry mysqli_stmt_property_entries[];
+extern const mysqli_property_entry mysqli_driver_property_entries[];
+extern const mysqli_property_entry mysqli_warning_property_entries[];
#ifdef HAVE_MYSQLND
extern MYSQLND_ZVAL_PCACHE *mysqli_mysqlnd_zval_cache;
extern zend_class_entry *mysqli_warning_class_entry;
extern zend_class_entry *mysqli_exception_class_entry;
extern int php_le_pmysqli(void);
+extern void php_mysqli_dtor_p_elements(void *data);
#ifdef HAVE_SPL
extern PHPAPI zend_class_entry *spl_ce_RuntimeException;
#define MYSQLI_RETURN_LONG_LONG(__val) \
{ \
if ((__val) < LONG_MAX) { \
- RETURN_LONG((__val)); \
+ RETURN_LONG((long) (__val)); \
} else { \
char *ret; \
+ /* always used with my_ulonglong -> %llu */ \
int l = spprintf(&ret, 0, "%llu", (__val)); \
RETURN_STRINGL(ret, l, 0); \
} \
long default_link;
long num_links;
long max_links;
+ long num_active_persistent;
+ long num_inactive_persistent;
+ long max_persistent;
+ long allow_persistent;
long cache_size;
unsigned long default_port;
char *default_host;
mysqlnd_source =
"mysqlnd.c " +
// "mysqlnd_alloc.c " +
+ "mysqlnd_debug.c " +
"mysqlnd_charset.c " +
"mysqlnd_loaddata.c " +
"mysqlnd_palloc.c " +
"mysqlnd_result_meta.c " +
"mysqlnd_statistics.c " +
"mysqlnd_wireprotocol.c";
-
- EXTENSION("mysqli", mysqli_source);
- // Specify that add "mysqlnd" sources, but use same object file
- // directory as the "mysqli" sources
- // FIXME the hard coded "ext/mysqli/mysqlnd" prevents pointing
- // out sources in another directory? Like above: PHP_MYSQLI + "\\include;"
- ADD_SOURCES("ext/mysqli/mysqlnd", mysqlnd_source, "mysqli");
- AC_DEFINE('HAVE_MYSQLILIB', 1, 'Have MySQLi library');
- AC_DEFINE('HAVE_MYSQLND' , 1, 'MySQL native driver support enabled');
+ if (CHECK_LIB("ws2_32.lib", "mysqlnd")) {
+ EXTENSION("mysqli", mysqli_source);
+ // Specify that add "mysqlnd" sources, but use same object file
+ // directory as the "mysqli" sources
+ // FIXME the hard coded "ext/mysqli/mysqlnd" prevents pointing
+ // out sources in another directory? Like above: PHP_MYSQLI + "\\include;"
+ ADD_SOURCES("ext/mysqli/mysqlnd", mysqlnd_source, "mysqli");
+ AC_DEFINE('HAVE_MYSQLILIB', 1, 'Have MySQLi library');
+ AC_DEFINE('HAVE_MYSQLND' , 1, 'MySQL native driver support enabled');
+ }
}
}
mysqlnd_sources="mysqlnd.c mysqlnd_charset.c mysqlnd_wireprotocol.c \
mysqlnd_ps.c mysqlnd_loaddata.c mysqlnd_palloc.c \
mysqlnd_ps_codec.c mysqlnd_statistics.c mysqlnd_qcache.c\
- mysqlnd_result.c mysqlnd_result_meta.c"
+ mysqlnd_result.c mysqlnd_result_meta.c mysqlnd_debug.c"
PHP_NEW_EXTENSION(mysqlnd, $mysqlnd_sources, no)
PHP_ADD_BUILD_DIR([ext/mysqlnd], 1)
*/
/* $Id$ */
-
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_result.h"
#include "mysqlnd_statistics.h"
#include "mysqlnd_charset.h"
+#include "mysqlnd_debug.h"
#include "php_ini.h"
#include "ext/standard/basic_functions.h"
#include "ext/standard/php_lcg.h"
#include "ext/standard/info.h"
-#define MYSQLND_SILENT
-
/* the server doesn't support 4byte utf8, but let's make it forward compatible */
#define MYSQLND_MAX_ALLOWED_USER_LEN 256 /* 64 char * 4byte */
#define MYSQLND_MAX_ALLOWED_DB_LEN 256 /* 64 char * 4byte */
-static const char * mysqlnd_server_gone = "MySQL server has gone away";
+const char * mysqlnd_server_gone = "MySQL server has gone away";
const char * mysqlnd_out_of_sync = "Commands out of sync; you can't run this command now";
MYSQLND_STATS *mysqlnd_global_stats = NULL;
static zend_bool mysqlnd_library_initted = FALSE;
+
+enum_func_status mysqlnd_send_close(MYSQLND * conn TSRMLS_DC);
+
/* {{{ mysqlnd_library_init */
static
-void mysqlnd_library_init(zend_bool collect_statistics)
+void mysqlnd_library_init()
{
if (mysqlnd_library_initted == FALSE) {
mysqlnd_library_initted = TRUE;
_mysqlnd_init_ps_subsystem();
- if (collect_statistics) {
- mysqlnd_global_stats = calloc(1, sizeof(MYSQLND_STATS));
-
+ /* Should be calloc, as mnd_calloc will reference LOCK_access*/
+ mysqlnd_global_stats = calloc(1, sizeof(MYSQLND_STATS));
#ifdef ZTS
- mysqlnd_global_stats->LOCK_access = tsrm_mutex_alloc();
+ mysqlnd_global_stats->LOCK_access = tsrm_mutex_alloc();
#endif
- }
}
}
/* }}} */
void mysqlnd_library_end()
{
if (mysqlnd_library_initted == TRUE) {
- if (mysqlnd_global_stats) {
#ifdef ZTS
- tsrm_mutex_free(mysqlnd_global_stats->LOCK_access);
+ tsrm_mutex_free(mysqlnd_global_stats->LOCK_access);
#endif
- free(mysqlnd_global_stats);
- mysqlnd_global_stats = NULL;
- }
+ /* mnd_free will reference LOCK_access and crash...*/
+ free(mysqlnd_global_stats);
+ mysqlnd_global_stats = NULL;
mysqlnd_library_initted = FALSE;
}
}
{
zend_bool pers = conn->persistent;
- mysqlnd_local_infile_default(conn, TRUE);
+ DBG_ENTER("mysqlnd_conn::free_contents");
+
+ mysqlnd_local_infile_default(conn);
if (conn->current_result) {
conn->current_result->m.free_result_contents(conn->current_result TSRMLS_CC);
- efree(conn->current_result);
+ mnd_efree(conn->current_result);
conn->current_result = NULL;
}
if (conn->net.stream) {
- php_stream_free(conn->net.stream, (pers) ? PHP_STREAM_FREE_RSRC_DTOR :
- PHP_STREAM_FREE_CLOSE);
+ DBG_INF_FMT("Freeing stream. abstract=%p", conn->net.stream->abstract);
+ if (pers) {
+ php_stream_free(conn->net.stream, PHP_STREAM_FREE_CLOSE_PERSISTENT | PHP_STREAM_FREE_RSRC_DTOR);
+ } else {
+ php_stream_free(conn->net.stream, PHP_STREAM_FREE_CLOSE);
+
+ }
conn->net.stream = NULL;
}
+
+ DBG_INF("Freeing memory of members");
if (conn->host) {
- pefree(conn->host, pers);
+ DBG_INF("Freeing host");
+ mnd_pefree(conn->host, pers);
conn->host = NULL;
}
if (conn->user) {
- pefree(conn->user, pers);
+ DBG_INF("Freeing user");
+ mnd_pefree(conn->user, pers);
conn->user = NULL;
}
if (conn->passwd) {
- pefree(conn->passwd, pers);
+ DBG_INF("Freeing passwd");
+ mnd_pefree(conn->passwd, pers);
conn->passwd = NULL;
}
if (conn->unix_socket) {
- pefree(conn->unix_socket, pers);
+ DBG_INF("Freeing unix_socket");
+ mnd_pefree(conn->unix_socket, pers);
conn->unix_socket = NULL;
}
if (conn->scheme) {
- pefree(conn->scheme, pers);
+ DBG_INF("Freeing scheme");
+ mnd_pefree(conn->scheme, pers);
conn->scheme = NULL;
}
if (conn->server_version) {
- pefree(conn->server_version, pers);
+ DBG_INF("Freeing server_version");
+ mnd_pefree(conn->server_version, pers);
conn->server_version = NULL;
}
if (conn->host_info) {
- pefree(conn->host_info, pers);
+ DBG_INF("Freeing host_info");
+ mnd_pefree(conn->host_info, pers);
conn->host_info = NULL;
}
if (conn->scramble) {
- pefree(conn->scramble, pers);
+ DBG_INF("Freeing scramble");
+ mnd_pefree(conn->scramble, pers);
conn->scramble = NULL;
}
if (conn->last_message) {
- pefree(conn->last_message, pers);
+ mnd_pefree(conn->last_message, pers);
conn->last_message = NULL;
}
if (conn->options.charset_name) {
- pefree(conn->options.charset_name, pers);
+ mnd_pefree(conn->options.charset_name, pers);
conn->options.charset_name = NULL;
}
if (conn->options.num_commands) {
unsigned int i;
for (i=0; i < conn->options.num_commands; i++) {
- pefree(conn->options.init_commands[i], pers);
+ mnd_pefree(conn->options.init_commands[i], pers);
}
- pefree(conn->options.init_commands, pers);
+ mnd_pefree(conn->options.init_commands, pers);
conn->options.init_commands = NULL;
}
if (conn->options.cfg_file) {
- pefree(conn->options.cfg_file, pers);
+ mnd_pefree(conn->options.cfg_file, pers);
conn->options.cfg_file = NULL;
}
if (conn->options.cfg_section) {
- pefree(conn->options.cfg_section, pers);
+ mnd_pefree(conn->options.cfg_section, pers);
conn->options.cfg_section = NULL;
}
if (conn->options.ssl_key) {
- pefree(conn->options.ssl_key, pers);
+ mnd_pefree(conn->options.ssl_key, pers);
conn->options.ssl_key = NULL;
}
if (conn->options.ssl_cert) {
- pefree(conn->options.ssl_cert, pers);
+ mnd_pefree(conn->options.ssl_cert, pers);
conn->options.ssl_cert = NULL;
}
if (conn->options.ssl_ca) {
- pefree(conn->options.ssl_ca, pers);
+ mnd_pefree(conn->options.ssl_ca, pers);
conn->options.ssl_ca = NULL;
}
if (conn->options.ssl_capath) {
- pefree(conn->options.ssl_capath, pers);
+ mnd_pefree(conn->options.ssl_capath, pers);
conn->options.ssl_capath = NULL;
}
if (conn->options.ssl_cipher) {
- pefree(conn->options.ssl_cipher, pers);
+ mnd_pefree(conn->options.ssl_cipher, pers);
conn->options.ssl_cipher = NULL;
}
if (conn->zval_cache) {
+ DBG_INF("Freeing zval cache reference");
mysqlnd_palloc_free_thd_cache_reference(&conn->zval_cache);
conn->zval_cache = NULL;
}
if (conn->qcache) {
+ DBG_INF("Freeing qcache reference");
mysqlnd_qcache_free_cache_reference(&conn->qcache);
conn->qcache = NULL;
}
if (conn->net.cmd_buffer.buffer) {
- pefree(conn->net.cmd_buffer.buffer, pers);
+ DBG_INF("Freeing cmd buffer");
+ mnd_pefree(conn->net.cmd_buffer.buffer, pers);
conn->net.cmd_buffer.buffer = NULL;
}
+ conn->charset = NULL;
+ conn->greet_charset = NULL;
+
+ DBG_VOID_RETURN;
}
/* }}} */
static void
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND *conn TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_conn::dtor");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
conn->m->free_contents(conn TSRMLS_CC);
- pefree(conn, conn->persistent);
+ mnd_pefree(conn, conn->persistent);
+
+ DBG_VOID_RETURN;
}
/* }}} */
TSRMLS_DC)
{
enum_func_status ret;
+
+ DBG_ENTER("mysqlnd_simple_command_handle_response");
+ DBG_INF_FMT("silent=%d packet=%d command=%s", silent, ok_packet, mysqlnd_command_to_text[command]);
+
switch (ok_packet) {
case PROT_OK_PACKET:{
php_mysql_packet_ok ok_response;
PACKET_INIT_ALLOCA(ok_response, PROT_OK_PACKET);
if (FAIL == (ret = PACKET_READ_ALLOCA(ok_response, conn))) {
if (!silent) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet",
- mysqlnd_command_to_text[command]);
+ DBG_ERR_FMT("Error while reading %s's OK packet", mysqlnd_command_to_text[command]);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's OK packet. PID=%d",
+ mysqlnd_command_to_text[command], getpid());
}
} else {
-#ifndef MYSQLND_SILENT
- php_printf("\tOK from server\n");
-#endif
+ DBG_INF_FMT("OK from server");
if (0xFF == ok_response.field_count) {
/* The server signalled error. Set the error */
SET_CLIENT_ERROR(conn->error_info, ok_response.error_no,
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
"Malformed packet");
if (!silent) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet",
- mysqlnd_command_to_text[command]);
+ DBG_ERR_FMT("Error while reading %s's EOF packet", mysqlnd_command_to_text[command]);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading %s's EOF packet. PID=%d",
+ mysqlnd_command_to_text[command], getpid());
}
} else if (0xFF == ok_response.field_count) {
/* The server signalled error. Set the error */
SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE,
"Malformed packet");
if (!silent) {
+ DBG_ERR_FMT("EOF packet expected, field count wasn't 0xFE but 0x%2X", ok_response.field_count);
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"EOF packet expected, field count wasn't 0xFE but 0x%2X",
ok_response.field_count);
}
} else {
-#ifndef MYSQLND_SILENT
- php_printf("\tOK from server\n");
-#endif
+ DBG_INF_FMT("OK from server");
}
PACKET_FREE_ALLOCA(ok_response);
break;
ok_packet);
break;
}
- return ret;
+ DBG_INF(ret == PASS ? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
enum_func_status ret = PASS;
php_mysql_packet_command cmd_packet;
+ DBG_ENTER("mysqlnd_simple_command");
+ DBG_INF_FMT("command=%s ok_packet=%d silent=%d", mysqlnd_command_to_text[command], ok_packet, silent);
+
switch (conn->state) {
case CONN_READY:
break;
case CONN_QUIT_SENT:
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
- return FAIL;
+ DBG_ERR("Server is gone");
+ DBG_RETURN(FAIL);
default:
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
mysqlnd_out_of_sync);
- return FAIL;
+ DBG_ERR("Command out of sync");
+ DBG_RETURN(FAIL);
}
/* clean UPSERT info */
if (! PACKET_WRITE_ALLOCA(cmd_packet, conn)) {
if (!silent) {
- php_error(E_WARNING, "Error while sending %s packet", mysqlnd_command_to_text[command]);
+ DBG_ERR_FMT("Error while sending %s packet", mysqlnd_command_to_text[command]);
+ php_error(E_WARNING, "Error while sending %s packet. PID=%d", mysqlnd_command_to_text[command], getpid());
}
- SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ DBG_ERR("Server is gone");
ret = FAIL;
} else if (ok_packet != PROT_LAST) {
ret = mysqlnd_simple_command_handle_response(conn, ok_packet, silent, command TSRMLS_CC);
to us. We should not free it.
*/
- return ret;
+ DBG_INF(ret == PASS ? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn,
enum_mysqlnd_server_option option TSRMLS_DC)
{
+ enum_func_status ret;
char buffer[2];
+ DBG_ENTER("mysqlnd_conn::set_server_option");
+
int2store(buffer, (uint) option);
- return mysqlnd_simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer),
- PROT_EOF_PACKET, FALSE TSRMLS_CC);
+ ret = mysqlnd_simple_command(conn, COM_SET_OPTION, buffer, sizeof(buffer),
+ PROT_EOF_PACKET, FALSE TSRMLS_CC);
+ DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_start_psession */
-PHPAPI void mysqlnd_restart_psession(MYSQLND *conn)
+/* {{{ _mysqlnd_restart_psession */
+PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn TSRMLS_DC)
{
+ DBG_ENTER("_mysqlnd_restart_psession");
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_REUSED);
/* Free here what should not be seen by the next script */
if (conn->last_message) {
- pefree(conn->last_message, conn->persistent);
+ mnd_pefree(conn->last_message, conn->persistent);
conn->last_message = NULL;
}
+ DBG_VOID_RETURN;
}
/* }}} */
{
char *transport = NULL, *errstr = NULL;
char *hashed_details = NULL;
- int transport_len, errcode = 0;
+ int transport_len, hashed_details_len, errcode = 0;
unsigned int streams_options = ENFORCE_SAFE_MODE;
unsigned int streams_flags = STREAM_XPORT_CLIENT | STREAM_XPORT_CONNECT;
zend_bool self_alloced = FALSE;
struct timeval tv;
zend_bool unix_socket = FALSE;
const MYSQLND_CHARSET * charset;
+ zend_bool reconnect = FALSE;
php_mysql_packet_greet greet_packet;
php_mysql_packet_auth *auth_packet;
php_mysql_packet_ok ok_packet;
- if (conn && conn->state != CONN_ALLOCED) {
- SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
- mysqlnd_out_of_sync);
- return NULL;
+ DBG_ENTER("mysqlnd_connect");
+ DBG_INF_FMT("host=%s user=%s db=%s port=%d flags=%d persistent=%d state=%d",
+ host?host:"", user?user:"", db?db:"", port, mysql_flags,
+ conn? conn->persistent:0, conn? conn->state:-1);
+
+ DBG_INF_FMT("state=%d", conn->state);
+ if (conn && conn->state > CONN_ALLOCED && conn->state ) {
+ DBG_INF("Connecting on a connected handle.");
+
+ if (conn->state < CONN_QUIT_SENT) {
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CLOSE_IMPLICIT);
+ reconnect = TRUE;
+ mysqlnd_send_close(conn TSRMLS_CC);
+ }
+
+ conn->m->free_contents(conn TSRMLS_CC);
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_CONNECTIONS);
+ if (conn->persistent) {
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
+ }
+ /* Now reconnect using the same handle */
}
if (!host || !host[0]) {
{
transport_len = spprintf(&transport, 0, "tcp://%s:%d", host, port);
}
+ DBG_INF_FMT("transport=%p", transport);
if (conn->persistent) {
struct timeval tv;
gettimeofday(&tv, NULL);
/* We should generate something unique */
- spprintf(&hashed_details, 0, "%s@%s@%s@%ld@%ld@%0.8F",
- transport, user, db, tv.tv_sec, (long int)tv.tv_usec,
- php_combined_lcg(TSRMLS_C) * 10);
+ hashed_details_len = spprintf(&hashed_details, 0, "%s@%s@%s@%ld@%ld@%0.8F",
+ transport, user, db, tv.tv_sec, (long int)tv.tv_usec,
+ php_combined_lcg(TSRMLS_C) * 10);
+ DBG_INF_FMT("hashed_details=%s", hashed_details);
}
PACKET_INIT_ALLOCA(greet_packet, PROT_GREET_PACKET);
}
if (conn->persistent) {
conn->scheme = pestrndup(transport, transport_len, 1);
- efree(transport);
+ mnd_efree(transport);
} else {
conn->scheme = transport;
}
+ DBG_INF(conn->scheme);
conn->net.stream = php_stream_xport_create(conn->scheme, transport_len, streams_options, streams_flags,
hashed_details,
(conn->options.timeout_connect) ? &tv : NULL,
NULL /*ctx*/, &errstr, &errcode);
+ DBG_INF_FMT("stream=%p", conn->net.stream);
+
if (hashed_details) {
- efree(hashed_details);
+ /*
+ If persistent, the streams register it in EG(persistent_list).
+ This is unwanted. ext/mysql or ext/mysqli are responsible to clean,
+ whatever they have to.
+ */
+ zend_rsrc_list_entry *le;
+
+ if (zend_hash_find(&EG(persistent_list), hashed_details, hashed_details_len + 1,
+ (void*) &le) == SUCCESS) {
+ /*
+ in_free will let streams code skip destructing - big HACK,
+ but STREAMS suck big time regarding persistent streams.
+ Just not compatible for extensions that need persistency.
+ */
+ conn->net.stream->in_free = 1;
+ zend_hash_del(&EG(persistent_list), hashed_details, hashed_details_len + 1);
+ conn->net.stream->in_free = 0;
+ }
+#if ZEND_DEBUG
+ /* Shut-up the streams, they don't know what they are doing */
+ conn->net.stream->__exposed = 1;
+#endif
+ mnd_efree(hashed_details);
}
+
if (errstr || !conn->net.stream) {
goto err;
}
}
if (FAIL == PACKET_READ_ALLOCA(greet_packet, conn)) {
-#ifndef MYSQLND_SILENT
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet");
-#endif
+ DBG_ERR("Error while reading greeting packet");
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading greeting packet. PID=%d", getpid());
goto err;
} else if (greet_packet.error_no) {
+ DBG_ERR_FMT("errorno=%d error=%s", greet_packet.error_no, greet_packet.error);
SET_CLIENT_ERROR(conn->error_info, greet_packet.error_no,
greet_packet.sqlstate, greet_packet.error);
goto err;
} else if (greet_packet.pre41) {
+ DBG_ERR_FMT("Connecting to 3.22, 3.23 & 4.0 is not supported. Server is %-.32s",
+ greet_packet.server_version);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Connecting to 3.22, 3.23 & 4.0 "
" is not supported. Server is %-.32s", greet_packet.server_version);
SET_CLIENT_ERROR(conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
conn->server_version = greet_packet.server_version;
greet_packet.server_version = NULL; /* The string will be freed otherwise */
+ conn->greet_charset = mysqlnd_find_charset_nr(greet_packet.charset_no);
/* we allow load data local infile by default */
mysql_flags |= CLIENT_LOCAL_FILES;
auth_packet->max_packet_size= 3UL*1024UL*1024UL*1024UL;
auth_packet->client_flags= mysql_flags;
- conn->scramble = auth_packet->server_scramble_buf = pemalloc(SCRAMBLE_LENGTH, conn->persistent);
+ conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
memcpy(auth_packet->server_scramble_buf, greet_packet.scramble_buf, SCRAMBLE_LENGTH);
- PACKET_WRITE(auth_packet, conn);
+ if (!PACKET_WRITE(auth_packet, conn)) {
+ conn->state = CONN_QUIT_SENT;
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ goto err;
+ }
if (FAIL == PACKET_READ_ALLOCA(ok_packet, conn) || ok_packet.field_count >= 0xFE) {
if (ok_packet.field_count == 0xFE) {
/* old authentication with new server !*/
+ DBG_ERR("mysqlnd cannot connect to MySQL 4.1+ using old authentication");
php_error_docref(NULL TSRMLS_CC, E_WARNING, "mysqlnd cannot connect to MySQL 4.1+ using old authentication");
} else if (ok_packet.field_count == 0xFF) {
if (ok_packet.sqlstate[0]) {
if (!self_alloced) {
strncpy(conn->error_info.sqlstate, ok_packet.sqlstate, sizeof(conn->error_info.sqlstate));
}
-#ifndef MYSQLND_SILENT
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "ERROR:%d [SQLSTATE:%s] %s",
- ok_packet.error_no, ok_packet.sqlstate, ok_packet.error);
-#endif
+ DBG_ERR_FMT("ERROR:%d [SQLSTATE:%s] %s",
+ ok_packet.error_no, ok_packet.sqlstate, ok_packet.error);
}
if (!self_alloced) {
conn->error_info.error_no = ok_packet.error_no;
spprintf(&p, 0, "MySQL host info: %s via TCP/IP", conn->host);
if (conn->persistent) {
conn->host_info = pestrdup(p, 1);
- efree(p);
+ mnd_efree(p);
} else {
conn->host_info = p;
}
conn->zval_cache = mysqlnd_palloc_get_thd_cache_reference(zval_cache);
conn->net.cmd_buffer.length = 128L*1024L;
- conn->net.cmd_buffer.buffer = pemalloc(conn->net.cmd_buffer.length, conn->persistent);
+ conn->net.cmd_buffer.buffer = mnd_pemalloc(conn->net.cmd_buffer.length, conn->persistent);
+
+ mysqlnd_local_infile_default(conn);
+ {
+ uint buf_size;
+ buf_size = MYSQLND_G(net_read_buffer_size); /* this is long, cast to uint*/
+ conn->m->set_client_option(conn, MYSQLND_OPT_NET_READ_BUFFER_SIZE,
+ (char *)&buf_size TSRMLS_CC);
+
+ buf_size = MYSQLND_G(net_cmd_buffer_size); /* this is long, cast to uint*/
+ conn->m->set_client_option(conn, MYSQLND_OPT_NET_CMD_BUFFER_SIZE,
+ (char *)&buf_size TSRMLS_CC);
+ }
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_SUCCESS);
+ if (reconnect) {
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_RECONNECT);
+ }
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_OPENED_CONNECTIONS);
+ if (conn->persistent) {
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
+ }
+ DBG_INF_FMT("connection_id=%llu", conn->thread_id);
+#if PHP_MAJOR_VERSION >= 6
{
uint as_unicode = 1;
conn->m->set_client_option(conn, MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE,
- (char *)&as_unicode);
+ (char *)&as_unicode TSRMLS_CC);
+ DBG_INF("unicode set");
}
-
- return conn;
+#endif
+ DBG_RETURN(conn);
}
err:
PACKET_FREE_ALLOCA(greet_packet);
PACKET_FREE_ALLOCA(ok_packet);
if (errstr) {
+ DBG_ERR_FMT("[%d] %.64s (trying to connect via %s)", errcode, errstr, conn->scheme);
SET_CLIENT_ERROR(conn->error_info, errcode, UNKNOWN_SQLSTATE, errstr);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "[%d] %.64s (trying to connect via %s)", errcode, errstr, conn->scheme);
- efree(errstr);
+ mnd_efree(errstr);
}
if (conn->scheme) {
- pefree(conn->scheme, conn->persistent);
+ mnd_pefree(conn->scheme, conn->persistent);
conn->scheme = NULL;
}
} else {
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CONNECT_FAILURE);
}
- return NULL;
+ DBG_RETURN(NULL);
}
/* }}} */
MYSQLND_METHOD(mysqlnd_conn, query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC)
{
enum_func_status ret;
+ DBG_ENTER("mysqlnd_conn::query");
+ DBG_INF_FMT("conn=%llu query=%s", conn->thread_id, query);
if (PASS != mysqlnd_simple_command(conn, COM_QUERY, query, query_len,
PROT_LAST /* we will handle the OK packet*/,
FALSE TSRMLS_CC)) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
/*
information from the ok packet. We will fetch it ourselves.
*/
ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC);
-
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
+/*
+ COM_FIELD_LIST is special, different from a SHOW FIELDS FROM :
+ - There is no result set header - status from the command, which
+ impacts us to allocate big chunk of memory for reading the metadata.
+ - The EOF packet is consumed by the metadata packet reader.
+*/
+
+/* {{{ mysqlnd_conn::list_fields */
+MYSQLND_RES *
+MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND *conn, const char *table, const char *achtung_wild TSRMLS_DC)
+{
+ /* db + \0 + wild + \0 (for wild) */
+ char buff[MYSQLND_MAX_ALLOWED_DB_LEN * 4 * 2 + 1 + 1], *p;
+ size_t table_len, wild_len;
+ MYSQLND_RES *result = NULL;
+ DBG_ENTER("mysqlnd_conn::list_fields");
+ DBG_INF_FMT("conn=%llu table=%s wild=%s", conn->thread_id, table? table:"",achtung_wild? achtung_wild:"");
+
+ p = buff;
+ if (table && (table_len = strlen(table))) {
+ memcpy(p, table, MIN(table_len, MYSQLND_MAX_ALLOWED_DB_LEN * 4));
+ p += table_len;
+ *p++ = '\0';
+ }
+
+ if (achtung_wild && (wild_len = strlen(achtung_wild))) {
+ memcpy(p, achtung_wild, MIN(wild_len, MYSQLND_MAX_ALLOWED_DB_LEN * 4));
+ p += wild_len;
+ *p++ = '\0';
+ }
+
+ if (PASS != mysqlnd_simple_command(conn, COM_FIELD_LIST, buff, p - buff,
+ PROT_LAST /* we will handle the OK packet*/,
+ FALSE TSRMLS_CC)) {
+ DBG_RETURN(NULL);
+ }
+ /*
+ Prepare for the worst case.
+ MyISAM goes to 2500 BIT columns, double it for safety.
+ */
+ result = mysqlnd_result_init(5000, mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache) TSRMLS_CC);
+
+
+ if (FAIL == result->m.read_result_metadata(result, conn TSRMLS_CC)) {
+ DBG_ERR("Error ocurred while reading metadata");
+ result->m.free_result(result, TRUE TSRMLS_CC);
+ DBG_RETURN(NULL);
+ }
+
+ result->type = MYSQLND_RES_NORMAL;
+ result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
+ result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ result->unbuf->eof_reached = TRUE;
+
+ DBG_RETURN(result);
+}
+/* }}} */
+
/* {{{ mysqlnd_conn::list_method */
MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND *conn, const char *query, char *achtung_wild, char *par1 TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_conn, list_method)(MYSQLND *conn, const char *query,
+ const char *achtung_wild, char *par1 TSRMLS_DC)
{
char *show_query = NULL;
size_t show_query_len;
MYSQLND_RES *result = NULL;
+ DBG_ENTER("mysqlnd_conn::list_method");
+ DBG_INF_FMT("conn=%llu query=%s wild=%d", conn->thread_id, query, achtung_wild);
+
if (par1) {
if (achtung_wild) {
show_query_len = spprintf(&show_query, 0, query, par1, achtung_wild);
result = conn->m->store_result(conn TSRMLS_CC);
}
if (show_query != query) {
- efree(show_query);
+ mnd_efree(show_query);
}
- return result;
+ DBG_RETURN(result);
}
/* }}} */
+
/* {{{ mysqlnd_conn::errno */
static unsigned int
MYSQLND_METHOD(mysqlnd_conn, errno)(const MYSQLND * const conn)
/* {{{ mysqlnd_old_escape_string */
-PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len)
+PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len TSRMLS_DC)
{
- return mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"),
- newstr, escapestr, escapestr_len);
+ DBG_ENTER("mysqlnd_old_escape_string");
+ DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"),
+ newstr, escapestr, escapestr_len TSRMLS_CC));
}
/* }}} */
/* {{{ mysqlnd_conn::escape_string */
static ulong
-MYSQLND_METHOD(mysqlnd_conn, escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, int escapestr_len)
+MYSQLND_METHOD(mysqlnd_conn, escape_string)(const MYSQLND * const conn, char *newstr,
+ const char *escapestr, int escapestr_len TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_conn::escape_string");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
if (conn->upsert_status.server_status & SERVER_STATUS_NO_BACKSLASH_ESCAPES) {
- return mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len);
+ DBG_RETURN(mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC));
}
- return mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len);
+ DBG_RETURN(mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len TSRMLS_CC));
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, dump_debug_info)(MYSQLND * const conn TSRMLS_DC)
{
- return mysqlnd_simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE TSRMLS_CC);
+ DBG_ENTER("mysqlnd_conn::dump_debug_info");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+ DBG_RETURN(mysqlnd_simple_command(conn, COM_DEBUG, NULL, 0, PROT_EOF_PACKET, FALSE TSRMLS_CC));
}
/* }}} */
unsigned int db_len TSRMLS_DC)
{
enum_func_status ret;
+
+ DBG_ENTER("mysqlnd_conn::select_db");
+ DBG_INF_FMT("conn=%llu db=%s", conn->thread_id, db);
+
ret = mysqlnd_simple_command(conn, COM_INIT_DB, db, db_len, PROT_OK_PACKET, FALSE TSRMLS_CC);
/*
The server sends 0 but libmysql doesn't read it and has established
*/
SET_ERROR_AFF_ROWS(conn);
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
MYSQLND_METHOD(mysqlnd_conn, ping)(MYSQLND * const conn TSRMLS_DC)
{
enum_func_status ret;
- ret = mysqlnd_simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, FALSE TSRMLS_CC);
+
+ DBG_ENTER("mysqlnd_conn::ping");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
+ ret = mysqlnd_simple_command(conn, COM_PING, NULL, 0, PROT_OK_PACKET, TRUE TSRMLS_CC);
/*
The server sends 0 but libmysql doesn't read it and has established
a protocol of giving back -1. Thus we have to follow it :(
*/
SET_ERROR_AFF_ROWS(conn);
- return ret;
+ DBG_INF_FMT("ret=%d", ret);
+ DBG_RETURN(ret);
}
/* }}} */
enum_func_status ret;
php_mysql_packet_stats stats_header;
+ DBG_ENTER("mysqlnd_conn::stat");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
ret = mysqlnd_simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE TSRMLS_CC);
if (FAIL == ret) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
PACKET_INIT_ALLOCA(stats_header, PROT_STATS_PACKET);
if (FAIL == (ret = PACKET_READ_ALLOCA(stats_header, conn))) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
*message = stats_header.message;
*message_len = stats_header.message_len;
stats_header.message = NULL;
PACKET_FREE_ALLOCA(stats_header);
- return PASS;
+ DBG_INF(*message);
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_conn::kill */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned long pid TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned int pid TSRMLS_DC)
{
enum_func_status ret;
char buff[4];
+ DBG_ENTER("mysqlnd_conn::kill");
+ DBG_INF_FMT("conn=%llu pid=%lu", conn->thread_id, pid);
+
int4store(buff, pid);
/* If we kill ourselves don't expect OK packet, PROT_LAST will skip it */
4, PROT_LAST, FALSE TSRMLS_CC))) {
conn->state = CONN_QUIT_SENT;
}
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
size_t query_len;
const MYSQLND_CHARSET * const charset = mysqlnd_find_charset_name(csname);
+ DBG_ENTER("mysqlnd_conn::set_charset");
+ DBG_INF_FMT("conn=%llu cs=%s", conn->thread_id, csname);
+
if (!charset) {
SET_CLIENT_ERROR(conn->error_info, CR_CANT_FIND_CHARSET, UNKNOWN_SQLSTATE,
"Invalid characterset or character set not supported");
- return FAIL;
+ DBG_RETURN(FAIL);
}
query_len = spprintf(&query, 0, "SET NAMES %s", csname);
} else {
conn->charset = charset;
}
- efree(query);
- return ret;
+ mnd_efree(query);
+
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
MYSQLND_METHOD(mysqlnd_conn, refresh)(MYSQLND * const conn, unsigned long options TSRMLS_DC)
{
zend_uchar bits[1];
+ DBG_ENTER("mysqlnd_conn::refresh");
+ DBG_INF_FMT("conn=%llu options=%lu", conn->thread_id, options);
+
int1store(bits, options);
- return mysqlnd_simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC);
+ DBG_RETURN(mysqlnd_simple_command(conn, COM_REFRESH, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC));
}
/* }}} */
MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, unsigned long level TSRMLS_DC)
{
zend_uchar bits[1];
+ DBG_ENTER("mysqlnd_conn::shutdown");
+ DBG_INF_FMT("conn=%llu level=%lu", conn->thread_id, level);
+
int1store(bits, level);
- return mysqlnd_simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC);
+ DBG_RETURN(mysqlnd_simple_command(conn, COM_SHUTDOWN, (char *)bits, 1, PROT_OK_PACKET, FALSE TSRMLS_CC));
}
/* }}} */
/* {{{ mysqlnd_send_close */
-static enum_func_status
+enum_func_status
mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
{
enum_func_status ret = PASS;
+
+ DBG_ENTER("mysqlnd_send_close");
+ DBG_INF_FMT("conn=%llu conn->net.stream->abstract=%p",
+ conn->thread_id, conn->net.stream? conn->net.stream->abstract:NULL);
+
switch (conn->state) {
case CONN_READY:
+ DBG_INF("Connection clean, sending COM_QUIT");
ret = mysqlnd_simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST,
- conn->tmp_int? TRUE : FALSE TSRMLS_CC);
+ TRUE TSRMLS_CC);
/* Do nothing */
break;
case CONN_SENDING_LOAD_DATA:
case CONN_NEXT_RESULT_PENDING:
case CONN_QUERY_SENT:
case CONN_FETCHING_DATA:
- MYSQLND_INC_CONN_STATISTIC(NULL, STAT_CLOSE_IN_MIDDLE);
-#ifndef MYSQLND_SILENT
- php_printf("Brutally closing connection [%p][%s]\n", conn, conn->scheme);
-#endif
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_CLOSE_IN_MIDDLE);
+ DBG_ERR_FMT("Brutally closing connection [%p][%s]", conn, conn->scheme);
/*
Do nothing, the connection will be brutally closed
and the server will catch it and free close from its side.
*/
conn->state = CONN_QUIT_SENT;
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
};
enum_mysqlnd_collected_stats stat = close_type_to_stat_map[close_type];
- MYSQLND_INC_CONN_STATISTIC(NULL, stat);
+ DBG_ENTER("mysqlnd_conn::close");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
- mysqlnd_send_close(conn TSRMLS_CC);
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_CONNECTIONS);
+ if (conn->persistent) {
+ MYSQLND_DEC_CONN_STATISTIC(&conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS);
+ }
- conn->m->free_reference(conn TSRMLS_CC);
+ /*
+ Close now, free_reference will try,
+ if we are last, but that's not a problem.
+ */
+ ret = mysqlnd_send_close(conn TSRMLS_CC);
+
+ ret = conn->m->free_reference(conn TSRMLS_CC);
- return ret;
+
+ DBG_RETURN(ret);
}
/* }}} */
/* {{{ mysqlnd_conn::free_reference */
-static void
+static enum_func_status
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference)(MYSQLND * const conn TSRMLS_DC)
{
+ enum_func_status ret = PASS;
+ DBG_ENTER("mysqlnd_conn::free_reference");
+ DBG_INF_FMT("conn=%llu conn->refcount=%u", conn->thread_id, conn->refcount);
if (!(--conn->refcount)) {
/*
No multithreading issues as we don't share the connection :)
This will free the object too, of course because references has
reached zero.
*/
- mysqlnd_send_close(conn TSRMLS_CC);
+ ret = mysqlnd_send_close(conn TSRMLS_CC);
conn->m->dtor(conn TSRMLS_CC);
}
+ DBG_RETURN(ret);
}
/* }}} */
{
enum_func_status ret;
+ DBG_ENTER("mysqlnd_conn::next_result");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
if (conn->state != CONN_NEXT_RESULT_PENDING) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
SET_EMPTY_ERROR(conn->error_info);
in mysqlnd_store_result() or mysqlnd_fetch_row_unbuffered()
*/
if (FAIL == (ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC))) {
-#ifndef MYSQLND_SILENT
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error");
-#endif
+ DBG_ERR_FMT("Serious error. %s::%d", __FILE__, __LINE__);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. PID=%d", getpid());
conn->state = CONN_QUIT_SENT;
}
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
char buffer[MYSQLND_MAX_ALLOWED_USER_LEN + 1 + SCRAMBLE_LENGTH + MYSQLND_MAX_ALLOWED_DB_LEN + 1];
char *p = buffer;
+ DBG_ENTER("mysqlnd_conn::change_user");
+ DBG_INF_FMT("conn=%llu user=%s passwd=%s db=%s",
+ conn->thread_id, user?user:"", passwd?"***":"null", db?db:"");
+
if (!user) {
user = "";
}
}
/* 1. user ASCIIZ */
- user_len = strlen(user);
- memcpy(p, user, MIN(user_len, MYSQLND_MAX_ALLOWED_DB_LEN));
+ user_len = MIN(strlen(user), MYSQLND_MAX_ALLOWED_DB_LEN);
+ memcpy(p, user, user_len);
p += user_len;
*p++ = '\0';
if (PASS != mysqlnd_simple_command(conn, COM_CHANGE_USER, buffer, p - buffer,
PROT_LAST /* we will handle the OK packet*/,
FALSE TSRMLS_CC)) {
- return FAIL;
+ DBG_RETURN(FAIL);
}
PACKET_INIT_ALLOCA(chg_user_resp, PROT_CHG_USER_PACKET);
PACKET_INIT_ALLOCA(redundant_error_packet, PROT_OK_PACKET);
PACKET_READ_ALLOCA(redundant_error_packet, conn);
PACKET_FREE_ALLOCA(redundant_error_packet);
+ DBG_INF_FMT("Server is %d, buggy, sends two ERR messages", mysqlnd_get_server_version(conn));
}
}
+ if (ret == PASS) {
+ mnd_pefree(conn->user, conn->persistent);
+ conn->user = pestrndup(user, user_len, conn->persistent);
+ mnd_pefree(conn->passwd, conn->persistent);
+ conn->passwd = pestrdup(passwd, conn->persistent);
+ if (conn->last_message) {
+ mnd_pefree(conn->last_message, conn->persistent);
+ conn->last_message = NULL;
+ }
+ conn->charset = conn->greet_charset;
+ memset(&conn->upsert_status, 0, sizeof(conn->upsert_status));
+ }
+
+ SET_ERROR_AFF_ROWS(conn);
/*
Here we should close all statements. Unbuffered queries should not be a
problem as we won't allow sending COM_CHANGE_USER.
*/
-
- return ret;
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn,
enum mysqlnd_option option,
- const char * const value)
+ const char * const value
+ TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_conn::set_client_option");
+ DBG_INF_FMT("conn=%llu option=%d", conn->thread_id, option);
switch (option) {
+#if PHP_MAJOR_VERSION >= 6
case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE:
conn->options.numeric_and_datetime_as_unicode = *(uint*) value;
break;
+#endif
+ case MYSQLND_OPT_NET_CMD_BUFFER_SIZE:
+ conn->net.cmd_buffer.length = *(uint*) value;
+ if (!conn->net.cmd_buffer.buffer) {
+ conn->net.cmd_buffer.buffer = mnd_pemalloc(conn->net.cmd_buffer.length, conn->persistent);
+ } else {
+ conn->net.cmd_buffer.buffer = mnd_perealloc(conn->net.cmd_buffer.buffer,
+ conn->net.cmd_buffer.length,
+ conn->persistent);
+ }
+ break;
+ case MYSQLND_OPT_NET_READ_BUFFER_SIZE:
+ conn->options.net_read_buffer_size = *(uint*) value;
+ break;
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
case MYSQLND_OPT_INT_AND_YEAR_AS_INT:
conn->options.int_and_year_as_int = *(uint*) value;
/* not sure, todo ? */
#endif
default:
- return FAIL;
+ DBG_RETURN(FAIL);
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
{
MYSQLND_RES *result;
+ DBG_ENTER("mysqlnd_conn::use_result");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
if (!conn->current_result) {
- return NULL;
+ DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA */
if (conn->last_query_type != QUERY_SELECT || conn->state != CONN_FETCHING_DATA) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
- mysqlnd_out_of_sync);
- return NULL;
+ mysqlnd_out_of_sync);
+ DBG_ERR("Command out of sync");
+ DBG_RETURN(NULL);
}
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_UNBUFFERED_SETS);
conn->current_result = NULL;
result->conn = conn->m->get_reference(conn);
- return result->m.use_result(result, FALSE TSRMLS_CC);
+ result = result->m.use_result(result, FALSE TSRMLS_CC);
+ DBG_RETURN(result);
}
/* }}} */
{
MYSQLND_RES *result;
+ DBG_ENTER("mysqlnd_conn::store_result");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
+
if (!conn->current_result) {
- return NULL;
+ DBG_RETURN(NULL);
}
/* Nothing to store for UPSERT/LOAD DATA*/
if (conn->last_query_type != QUERY_SELECT || conn->state != CONN_FETCHING_DATA) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
mysqlnd_out_of_sync);
- return NULL;
+ DBG_ERR("Command out of sync");
+ DBG_RETURN(NULL);
}
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BUFFERED_SETS);
result = conn->current_result;
conn->current_result = NULL;
- return result->m.store_result(result, conn, FALSE TSRMLS_CC);
+ result = result->m.store_result(result, conn, FALSE TSRMLS_CC);
+ DBG_RETURN(result);
}
/* }}} */
zval *return_value
TSRMLS_DC ZEND_FILE_LINE_DC)
{
+ DBG_ENTER("mysqlnd_conn::get_connection_stats");
+ DBG_INF_FMT("conn=%llu", conn->thread_id);
mysqlnd_fill_stats_hash(&(conn->stats), return_value TSRMLS_CC ZEND_FILE_LINE_CC);
+ DBG_VOID_RETURN;
}
/* }}} */
-MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn);
+MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC);
MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
MYSQLND_METHOD(mysqlnd_conn, get_proto_info),
MYSQLND_METHOD(mysqlnd_conn, info),
MYSQLND_METHOD(mysqlnd_conn, charset_name),
+ MYSQLND_METHOD(mysqlnd_conn, list_fields),
MYSQLND_METHOD(mysqlnd_conn, list_method),
MYSQLND_METHOD(mysqlnd_conn, insert_id),
/* {{{ mysqlnd_init */
-PHPAPI MYSQLND *mysqlnd_init(zend_bool persistent)
+PHPAPI MYSQLND *_mysqlnd_init(zend_bool persistent TSRMLS_DC)
{
- MYSQLND *ret = pecalloc(1, sizeof(MYSQLND), persistent);
+ MYSQLND *ret = mnd_pecalloc(1, sizeof(MYSQLND), persistent);
+
+ DBG_ENTER("mysqlnd_init");
+ DBG_INF_FMT("persistent=%d", persistent);
+
SET_ERROR_AFF_ROWS(ret);
ret->persistent = persistent;
ret->m = & mysqlnd_mysqlnd_conn_methods;
ret->m->get_reference(ret);
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
*
* Every user visible function must have an entry in mysqlnd_functions[].
*/
-static const zend_function_entry mysqlnd_functions[] = {
+static zend_function_entry mysqlnd_functions[] = {
{NULL, NULL, NULL} /* Must be the last line in mysqlnd_functions[] */
};
/* }}} */
php_info_print_table_row(2, s, Z_STRVAL_PP(values_entry));
}
if (s) {
- efree(s);
+ mnd_efree(s);
}
} else {
php_info_print_table_row(2, string_key.s, Z_STRVAL_PP(values_entry));
*/
PHP_MINFO_FUNCTION(mysqlnd)
{
+ char buf[32];
zval values;
php_info_print_table_start();
php_info_print_table_header(2, "Client statistics", "");
mysqlnd_get_client_stats(&values);
mysqlnd_minfo_print_hash(&values);
+ php_info_print_table_row(2, "Collecting statistics", MYSQLND_G(collect_statistics)? "Yes":"No");
+ php_info_print_table_row(2, "Collecting memory statistics", MYSQLND_G(collect_memory_statistics)? "Yes":"No");
+
+ snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_cmd_buffer_size));
+ php_info_print_table_row(2, "Command buffer size", buf);
+ snprintf(buf, sizeof(buf), "%ld", MYSQLND_G(net_read_buffer_size));
+ php_info_print_table_row(2, "Read buffer size", buf);
+
zval_dtor(&values);
php_info_print_table_end();
}
/* }}} */
-ZEND_DECLARE_MODULE_GLOBALS(mysqlnd)
+ZEND_DECLARE_MODULE_GLOBALS(mysqlnd);
+
/* {{{ PHP_GINIT_FUNCTION
*/
static PHP_GINIT_FUNCTION(mysqlnd)
{
- mysqlnd_globals->collect_statistics = FALSE;
+ mysqlnd_globals->collect_statistics = TRUE;
+ mysqlnd_globals->collect_memory_statistics = FALSE;
+ mysqlnd_globals->debug = NULL; /* The actual string */
+ mysqlnd_globals->dbg = NULL; /* The DBG object*/
+ mysqlnd_globals->net_cmd_buffer_size = 2048;
+ mysqlnd_globals->net_read_buffer_size = 32768;
}
/* }}} */
/* {{{ PHP_INI_BEGIN
*/
PHP_INI_BEGIN()
- STD_PHP_INI_BOOLEAN("mysqlnd.collect_statistics", "1", PHP_INI_SYSTEM, OnUpdateBool, collect_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_BOOLEAN("mysqlnd.collect_statistics", "1", PHP_INI_ALL, OnUpdateBool, collect_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_BOOLEAN("mysqlnd.collect_memory_statistics", "0", PHP_INI_SYSTEM, OnUpdateBool, collect_memory_statistics, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_ENTRY("mysqlnd.debug", NULL, PHP_INI_SYSTEM, OnUpdateString, debug, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_ENTRY("mysqlnd.net_cmd_buffer_size", "2048", PHP_INI_ALL, OnUpdateLong, net_cmd_buffer_size, zend_mysqlnd_globals, mysqlnd_globals)
+ STD_PHP_INI_ENTRY("mysqlnd.net_read_buffer_size", "32768",PHP_INI_ALL, OnUpdateLong, net_read_buffer_size, zend_mysqlnd_globals, mysqlnd_globals)
PHP_INI_END()
/* }}} */
{
REGISTER_INI_ENTRIES();
- mysqlnd_library_init(MYSQLND_G(collect_statistics));
+ mysqlnd_library_init();
return SUCCESS;
}
/* }}} */
/* }}} */
+#if PHP_DEBUG
+/* {{{ PHP_RINIT_FUNCTION
+ */
+static PHP_RINIT_FUNCTION(mysqlnd)
+{
+#ifdef PHP_DEBUG
+ if (MYSQLND_G(debug)) {
+ MYSQLND_DEBUG *dbg = mysqlnd_debug_init(TSRMLS_C);
+ if (!dbg) {
+ return FAILURE;
+ }
+ dbg->m->set_mode(dbg, MYSQLND_G(debug));
+ MYSQLND_G(dbg) = dbg;
+ }
+#endif
+ return SUCCESS;
+}
+/* }}} */
+
+
+/* {{{ PHP_RSHUTDOWN_FUNCTION
+ */
+static PHP_RSHUTDOWN_FUNCTION(mysqlnd)
+{
+#ifdef PHP_DEBUG
+ MYSQLND_DEBUG *dbg = MYSQLND_G(dbg);
+ DBG_ENTER("RSHUTDOWN");
+ if (dbg) {
+ dbg->m->close(dbg);
+ dbg->m->free(dbg);
+ MYSQLND_G(dbg) = NULL;
+ }
+#endif
+ return SUCCESS;
+}
+/* }}} */
+#endif
+
+
/* {{{ mysqlnd_module_entry
*/
zend_module_entry mysqlnd_module_entry = {
mysqlnd_functions,
PHP_MINIT(mysqlnd),
PHP_MSHUTDOWN(mysqlnd),
+#if PHP_DEBUG
+ PHP_RINIT(mysqlnd),
+ PHP_RSHUTDOWN(mysqlnd),
+#else
NULL,
NULL,
+#endif
PHP_MINFO(mysqlnd),
MYSQLND_VERSION,
PHP_MODULE_GLOBALS(mysqlnd),
#ifndef MYSQLND_H
#define MYSQLND_H
-#define MYSQLND_VERSION "mysqlnd 5.0.2-dev - 070702 - $Revision$"
+#define MYSQLND_VERSION "mysqlnd 5.0.2-dev - 070928 - $Revision$"
#define MYSQLND_VERSION_ID 50002
-#define phpext_mysqlnd_ptr &mysqlnd_module_entry
-extern zend_module_entry mysqlnd_module_entry;
-
-
/* This forces inlining of some accessor functions */
#define MYSQLND_USE_OPTIMISATIONS 0
#define MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND 1
#endif
-#include "mysqlnd_portability.h"
-
#ifdef ZTS
#include "TSRM.h"
#endif
+#include "mysqlnd_portability.h"
#include "mysqlnd_enum_n_def.h"
-
-/*
- /-----> CONN_CLOSE <---------------\
- | ^ \
- | | \
- CONN_READY -> CONN_QUERY_SENT -> CONN_FETCHING_DATA
- ^ |
- \-------------------------------------/
-*/
-typedef enum mysqlnd_connection_state
-{
- CONN_ALLOCED = 0,
- CONN_READY,
- CONN_QUERY_SENT,
- CONN_SENDING_LOAD_DATA,
- CONN_FETCHING_DATA,
- CONN_NEXT_RESULT_PENDING,
- CONN_QUIT_SENT, /* object is "destroyed" at this stage */
-} enum_mysqlnd_connection_state;
-
-
-typedef enum mysqlnd_stmt_state {
- MYSQLND_STMT_INITTED = 0,
- MYSQLND_STMT_PREPARED,
- MYSQLND_STMT_EXECUTED,
- MYSQLND_STMT_WAITING_USE_OR_STORE,
- MYSQLND_STMT_USE_OR_STORE_CALLED,
- MYSQLND_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */
-} enum_mysqlnd_stmt_state;
-
-
-typedef enum param_bind_flags {
- MYSQLND_PARAM_BIND_BLOB_USED = 1
-} enum_param_bind_flags;
-
-
-/* PS */
-enum mysqlnd_stmt_attr
-{
- STMT_ATTR_UPDATE_MAX_LENGTH,
- STMT_ATTR_CURSOR_TYPE,
- STMT_ATTR_PREFETCH_ROWS
-};
-
-enum myslqnd_cursor_type
-{
- CURSOR_TYPE_NO_CURSOR= 0,
- CURSOR_TYPE_READ_ONLY= 1,
- CURSOR_TYPE_FOR_UPDATE= 2,
- CURSOR_TYPE_SCROLLABLE= 4
-};
-
-typedef enum mysqlnd_connection_close_type
-{
- MYSQLND_CLOSE_EXPLICIT = 0,
- MYSQLND_CLOSE_IMPLICIT,
- MYSQLND_CLOSE_DISCONNECTED,
- MYSQLND_CLOSE_LAST /* for checking, should always be last */
-} enum_connection_close_type;
-
-typedef enum mysqlnd_collected_stats {
- STAT_BYTES_SENT,
- STAT_BYTES_RECEIVED,
- STAT_PACKETS_SENT,
- STAT_PACKETS_RECEIVED,
- STAT_PROTOCOL_OVERHEAD_IN,
- STAT_PROTOCOL_OVERHEAD_OUT,
- STAT_RSET_QUERY,
- STAT_NON_RSET_QUERY,
- STAT_NO_INDEX_USED,
- STAT_BAD_INDEX_USED,
- STAT_BUFFERED_SETS,
- STAT_UNBUFFERED_SETS,
- STAT_PS_BUFFERED_SETS,
- STAT_PS_UNBUFFERED_SETS,
- STAT_FLUSHED_NORMAL_SETS,
- STAT_FLUSHED_PS_SETS,
- STAT_ROWS_FETCHED_FROM_SERVER,
- STAT_ROWS_FETCHED_FROM_CLIENT,
- STAT_ROWS_SKIPPED,
- STAT_COPY_ON_WRITE_SAVED,
- STAT_COPY_ON_WRITE_PERFORMED,
- STAT_CMD_BUFFER_TOO_SMALL,
- STAT_CONNECT_SUCCESS,
- STAT_CONNECT_FAILURE,
- STAT_CONNECT_REUSED,
- STAT_CLOSE_EXPLICIT,
- STAT_CLOSE_IMPLICIT,
- STAT_CLOSE_DISCONNECT,
- STAT_CLOSE_IN_MIDDLE,
- STAT_FREE_RESULT_EXPLICIT,
- STAT_FREE_RESULT_IMPLICIT,
- STAT_STMT_CLOSE_EXPLICIT,
- STAT_STMT_CLOSE_IMPLICIT,
- STAT_LAST /* Should be always the last */
-} enum_mysqlnd_collected_stats;
-
-
-typedef struct st_mysqlnd_cmd_buffer {
- zend_uchar *buffer;
- size_t length;
-} MYSQLND_CMD_BUFFER;
-
-
-typedef struct st_mysqlnd_field {
- char *name; /* Name of column */
- char *org_name; /* Original column name, if an alias */
- char *table; /* Table of column if column was a field */
- char *org_table; /* Org table name, if table was an alias */
- char *db; /* Database for table */
- char *catalog; /* Catalog for table */
- char *def; /* Default value (set by mysql_list_fields) */
- unsigned long length; /* Width of column (create length) */
- unsigned long max_length; /* Max width for selected set */
- unsigned int name_length;
- unsigned int org_name_length;
- unsigned int table_length;
- unsigned int org_table_length;
- unsigned int db_length;
- unsigned int catalog_length;
- unsigned int def_length;
- unsigned int flags; /* Diverse flags */
- unsigned int decimals; /* Number of decimals in field */
- unsigned int charsetnr; /* Character set */
- enum mysqlnd_field_types type; /* Type of field. See mysql_com.h for types */
- char *root;
- size_t root_len;
-} MYSQLND_FIELD;
-
-
-
-typedef struct st_mysqlnd_upsert_result {
- unsigned int warning_count;
- unsigned int server_status;
- unsigned long long affected_rows;
- unsigned long long last_insert_id;
-} mysqlnd_upsert_status;
-
-
-typedef struct st_mysqlnd_error_info {
- char error[MYSQLND_ERRMSG_SIZE+1];
- char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
- unsigned int error_no;
-} mysqlnd_error_info;
-
-
-typedef struct st_mysqlnd_zval_pcache MYSQLND_ZVAL_PCACHE;
-typedef struct st_mysqlnd_thread_zval_pcache MYSQLND_THD_ZVAL_PCACHE;
-typedef struct st_mysqlnd_qcache MYSQLND_QCACHE;
-
-
-typedef struct st_mysqlnd_infile_info {
- php_stream *fd;
- int error_no;
- char error_msg[MYSQLND_ERRMSG_SIZE + 1];
- const char *filename;
- zval *callback;
-} MYSQLND_INFILE_INFO;
-
-
-/* character set information */
-typedef struct st_mysqlnd_charset
-{
- uint nr;
- char *name;
- char *collation;
- uint char_minlen;
- uint char_maxlen;
- uint dangerous_for_escape_backslash;
- uint (*mb_charlen)(uint c);
- uint (*mb_valid)(const char *start, const char *end);
-} MYSQLND_CHARSET;
-
-
-/* local infile handler */
-typedef struct st_mysqlnd_infile
-{
- int (*local_infile_init)(void **ptr, char *filename, void **userdata TSRMLS_DC);
- int (*local_infile_read)(void *ptr, char *buf, uint buf_len TSRMLS_DC);
- int (*local_infile_error)(void *ptr, char *error_msg, uint error_msg_len TSRMLS_DC);
- void (*local_infile_end)(void *ptr TSRMLS_DC);
- zval *callback;
- void *userdata;
-} MYSQLND_INFILE;
-
-typedef struct st_mysqlnd_option {
- /* timeouts */
- uint timeout_connect;
- uint timeout_read;
- uint timeout_write;
-
- ulong flags;
-
- /* init commands - we need to send them to server directly after connect */
- uint num_commands;
- char **init_commands;
-
- /* configuration file information */
- char *cfg_file;
- char *cfg_section;
-
- /* SSL information */
- char *ssl_key;
- char *ssl_cert;
- char *ssl_ca;
- char *ssl_capath;
- char *ssl_cipher;
- zend_bool use_ssl;
-
- char *charset_name;
- /* maximum allowed packet size for communication */
- ulong max_allowed_packet;
-
- zend_bool numeric_and_datetime_as_unicode;
-#ifdef MYSQLND_STRING_TO_INT_CONVERSION
- zend_bool int_and_year_as_int;
-#endif
-} MYSQLND_OPTION;
-
-
-typedef struct st_mysqlnd_connection MYSQLND;
-typedef struct st_mysqlnd_res MYSQLND_RES;
-typedef char** MYSQLND_ROW; /* return data as array of strings */
-typedef struct st_mysqlnd_stmt MYSQLND_STMT;
-typedef unsigned int MYSQLND_FIELD_OFFSET;
-
-typedef struct st_mysqlnd_param_bind MYSQLND_PARAM_BIND;
-
-typedef struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND;
-
-typedef struct st_mysqlnd_result_metadata MYSQLND_RES_METADATA;
-typedef struct st_mysqlnd_buffered_result MYSQLND_RES_BUFFERED;
-typedef struct st_mysqlnd_unbuffered_result MYSQLND_RES_UNBUFFERED;
-
-
-typedef MYSQLND_RES* (*mysqlnd_stmt_use_or_store_func)(MYSQLND_STMT * const TSRMLS_DC);
-typedef enum_func_status (*mysqlnd_fetch_row_func)(MYSQLND_RES *result,
- void *param,
- unsigned int flags,
- zend_bool *fetched_anything
- TSRMLS_DC);
-
-typedef struct st_mysqlnd_stats {
- my_uint64 values[STAT_LAST];
-#ifdef ZTS
- MUTEX_T LOCK_access;
-#endif
-} MYSQLND_STATS;
-
-
-typedef struct st_mysqlnd_net {
- php_stream *stream;
- /* sequence for simple checking of correct packets */
- zend_uchar packet_no;
-
-#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
- zend_uchar last_command;
-#endif
-
- /* cmd buffer */
- MYSQLND_CMD_BUFFER cmd_buffer;
-} MYSQLND_NET;
-
-
-struct st_mysqlnd_conn_methods {
- ulong (*escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, int escapestr_len);
- enum_func_status (*set_charset)(MYSQLND * const conn, const char * const charset TSRMLS_DC);
- enum_func_status (*query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC);
- MYSQLND_RES * (*use_result)(MYSQLND * const conn TSRMLS_DC);
- MYSQLND_RES * (*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);
-
- MYSQLND_STMT * (*stmt_init)(MYSQLND * const conn);
-
- enum_func_status (*shutdown_server)(MYSQLND * const conn, unsigned long level TSRMLS_DC);
- enum_func_status (*refresh_server)(MYSQLND * const conn, unsigned long options TSRMLS_DC);
-
- enum_func_status (*ping)(MYSQLND * const conn TSRMLS_DC);
- enum_func_status (*kill_connection)(MYSQLND *conn, unsigned long pid TSRMLS_DC);
- enum_func_status (*select_db)(MYSQLND * const conn, const char * const db, unsigned int db_len TSRMLS_DC);
- enum_func_status (*server_dump_debug_information)(MYSQLND * const conn TSRMLS_DC);
- enum_func_status (*change_user)(MYSQLND * const conn, const char * user, const char * passwd, const char * db TSRMLS_DC);
-
- unsigned int (*get_error_no)(const MYSQLND * const conn);
- const char * (*get_error_str)(const MYSQLND * const conn);
- const char * (*get_sqlstate)(const MYSQLND * const conn);
- mynd_ulonglong (*get_thread_id)(const MYSQLND * const conn);
- void (*get_statistics)(const MYSQLND * const conn, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
-
- unsigned long (*get_server_version)(const MYSQLND * const conn);
- const char * (*get_server_information)(const MYSQLND * const conn);
- enum_func_status (*get_server_statistics)(MYSQLND *conn, char **message, unsigned int * message_len TSRMLS_DC);
- const char * (*get_host_information)(const MYSQLND * const conn);
- unsigned int (*get_protocol_information)(const MYSQLND * const conn);
- const char * (*get_last_message)(const MYSQLND * const conn);
- const char * (*charset_name)(const MYSQLND * const conn);
- MYSQLND_RES * (*list_method)(MYSQLND *conn, const char *query, char *achtung_wild, char *par1 TSRMLS_DC);
-
- mynd_ulonglong (*get_last_insert_id)(const MYSQLND * const conn);
- mynd_ulonglong (*get_affected_rows)(const MYSQLND * const conn);
- unsigned int (*get_warning_count)(const MYSQLND * const conn);
-
- unsigned int (*get_field_count)(const MYSQLND * const conn);
-
- enum_func_status (*set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC);
- enum_func_status (*set_client_option)(MYSQLND * const conn, enum_mysqlnd_option option, const char * const value);
- void (*free_contents)(MYSQLND *conn TSRMLS_DC); /* private */
- 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);
- void (*free_reference)(MYSQLND * const conn TSRMLS_DC);
-};
-
-
-struct st_mysqlnd_res_methods {
- mysqlnd_fetch_row_func fetch_row;
- mysqlnd_fetch_row_func fetch_row_normal_buffered; /* private */
- mysqlnd_fetch_row_func fetch_row_normal_unbuffered; /* private */
-
- MYSQLND_RES * (*use_result)(MYSQLND_RES * const result, zend_bool ps_protocol TSRMLS_DC);
- MYSQLND_RES * (*store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps TSRMLS_DC);
- void (*fetch_into)(MYSQLND_RES *result, unsigned int flags, zval *return_value, enum_mysqlnd_extension ext TSRMLS_DC ZEND_FILE_LINE_DC);
- void (*fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
- void (*fetch_field_data)(MYSQLND_RES *result, unsigned int offset, zval *return_value TSRMLS_DC);
- mynd_ulonglong (*num_rows)(const MYSQLND_RES * const result);
- unsigned int (*num_fields)(const MYSQLND_RES * const result);
- enum_func_status (*skip_result)(MYSQLND_RES * const result TSRMLS_DC);
- enum_func_status (*seek_data)(MYSQLND_RES * result, mynd_ulonglong row);
- MYSQLND_FIELD_OFFSET (*seek_field)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET field_offset);
- MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES * const result);
- MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES * const result);
- MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr);
-
- enum_func_status (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC);
- unsigned long * (*fetch_lengths)(MYSQLND_RES * const result);
- void (*free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
- enum_func_status (*free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
- void (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
- void (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
-};
-
-
-struct st_mysqlnd_res_meta_methods {
- MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES_METADATA * const meta);
- MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr);
- MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES_METADATA * const meta);
- enum_func_status (*read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND *conn TSRMLS_DC);
- MYSQLND_RES_METADATA * (*clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent);
- void (*free_metadata)(MYSQLND_RES_METADATA *meta, zend_bool persistent TSRMLS_DC);
-};
-
-
-struct st_mysqlnd_stmt_methods {
- enum_func_status (*prepare)(MYSQLND_STMT * const stmt, const char * const query, unsigned int query_len TSRMLS_DC);
- enum_func_status (*execute)(MYSQLND_STMT * const stmt TSRMLS_DC);
- MYSQLND_RES * (*use_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
- MYSQLND_RES * (*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
- MYSQLND_RES * (*get_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, mynd_ulonglong row);
- 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 (*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);
-
- enum_func_status (*bind_param)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind);
- enum_func_status (*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const result_bind);
- enum_func_status (*send_long_data)(MYSQLND_STMT * const stmt, unsigned int param_num,
- const char * const data, unsigned long length TSRMLS_DC);
- MYSQLND_RES * (*get_parameter_metadata)(MYSQLND_STMT * const stmt);
- MYSQLND_RES * (*get_result_metadata)(MYSQLND_STMT * const stmt);
-
- mynd_ulonglong (*get_last_insert_id)(const MYSQLND_STMT * const stmt);
- mynd_ulonglong (*get_affected_rows)(const MYSQLND_STMT * const stmt);
- mynd_ulonglong (*get_num_rows)(const MYSQLND_STMT * const stmt);
-
- unsigned int (*get_param_count)(const MYSQLND_STMT * const stmt);
- unsigned int (*get_field_count)(const MYSQLND_STMT * const stmt);
- unsigned int (*get_warning_count)(const MYSQLND_STMT * const stmt);
-
- unsigned int (*get_error_no)(const MYSQLND_STMT * const stmt);
- 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);
- enum_func_status (*set_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, const void * const value);
-};
-
-
-struct st_mysqlnd_connection {
-/* Operation related */
- MYSQLND_NET net;
-
-/* Information related */
- char *host;
- char *unix_socket;
- char *user;
- char *passwd;
- unsigned int *passwd_len;
- char *scheme;
- unsigned long long thread_id;
- char *server_version;
- char *host_info;
- unsigned char *scramble;
- const MYSQLND_CHARSET *charset;
- MYSQLND_INFILE infile;
- unsigned int protocol_version;
- unsigned long max_packet_size;
- unsigned int port;
- unsigned long client_flag;
- unsigned long server_capabilities;
-
- int tmp_int;
-
-
- /* For UPSERT queries */
- mysqlnd_upsert_status upsert_status;
- char *last_message;
- unsigned int last_message_len;
-
- /* If error packet, we use these */
- mysqlnd_error_info error_info;
-
- /*
- To prevent queries during unbuffered fetches. Also to
- mark the connection as destroyed for garbage collection.
- */
- enum mysqlnd_connection_state state;
- enum_mysqlnd_query_type last_query_type;
- /* Temporary storage between query and (use|store)_result() call */
- MYSQLND_RES *current_result;
-
- /*
- How many result sets reference this connection.
- It won't be freed until this number reaches 0.
- The last one, please close the door! :-)
- The result set objects can determine by inspecting
- 'quit_sent' whether the connection is still valid.
- */
- unsigned int refcount;
-
- /* Temporal storage for mysql_query */
- unsigned int field_count;
-
- /* persistent connection */
- zend_bool persistent;
-
- /* options */
- MYSQLND_OPTION options;
-
- /* zval cache */
- MYSQLND_THD_ZVAL_PCACHE *zval_cache;
-
- /* qcache */
- MYSQLND_QCACHE *qcache;
-
- /* stats */
- MYSQLND_STATS stats;
-
- struct st_mysqlnd_conn_methods *m;
-};
-
-typedef struct st_php_mysql_packet_row php_mysql_packet_row;
-
-
-struct mysqlnd_field_hash_key {
- zend_bool is_numeric;
- unsigned long key;
-#if PHP_MAJOR_VERSION >= 6
- zstr ustr;
- unsigned int ulen;
-#endif
-};
-
-
-struct st_mysqlnd_result_metadata {
- MYSQLND_FIELD *fields;
- struct mysqlnd_field_hash_key *zend_hash_keys;
- unsigned int current_field;
- unsigned int field_count;
- /* We need this to make fast allocs in rowp_read */
- unsigned int bit_fields_count;
- size_t bit_fields_total_len; /* trailing \0 not counted */
-
- struct st_mysqlnd_res_meta_methods *m;
-};
-
-
-struct st_mysqlnd_buffered_result {
- zval ***data;
- zval ***data_cursor;
- zend_uchar **row_buffers;
- mynd_ulonglong row_count;
- zend_bool persistent;
-
- MYSQLND_QCACHE *qcache;
- unsigned int references;
-
- zend_bool async_invalid;
- mysqlnd_error_info error_info;
-};
-
-
-struct st_mysqlnd_unbuffered_result {
- /* For unbuffered (both normal and PS) */
- zval **last_row_data;
- zend_uchar *last_row_buffer;
-
- mynd_ulonglong row_count;
- zend_bool eof_reached;
-};
-
-
-struct st_mysqlnd_res {
- struct st_mysqlnd_res_methods m;
-
- MYSQLND *conn;
- enum_mysqlnd_res_type type;
- unsigned int field_count;
-
- /* For metadata functions */
- MYSQLND_RES_METADATA *meta;
-
- /* To be used with store_result() - both normal and PS */
- MYSQLND_RES_BUFFERED *data;
-
- MYSQLND_RES_UNBUFFERED *unbuf;
-
- /*
- Column lengths of current row - both buffered and unbuffered.
- For buffered results it duplicates the data found in **data
- */
- unsigned long *lengths;
-
- php_mysql_packet_row *row_packet; /* Unused for PS */
-
- /* zval cache */
- MYSQLND_THD_ZVAL_PCACHE *zval_cache;
-};
-
-
-
-
-#define MYSQLND_DEFAULT_PREFETCH_ROWS (ulong) 1
-
-struct st_mysqlnd_param_bind {
- zval *zv;
- zend_uchar type;
- enum_param_bind_flags flags;
-};
-
-struct st_mysqlnd_result_bind {
- zval *zv;
- zend_uchar original_type;
- zend_bool bound;
-};
-
-
-struct st_mysqlnd_stmt {
- MYSQLND *conn;
- unsigned long stmt_id;
- unsigned long flags;/* cursor is set here */
- enum_mysqlnd_stmt_state state;
- unsigned int warning_count;
- MYSQLND_RES *result;
- unsigned int field_count;
- unsigned int param_count;
- unsigned char send_types_to_server;
- MYSQLND_PARAM_BIND *param_bind;
- MYSQLND_RESULT_BIND *result_bind;
- zend_bool result_zvals_separated_once;
-
- mysqlnd_upsert_status upsert_status;
-
- mysqlnd_error_info error_info;
-
- zend_bool update_max_length;
- unsigned long prefetch_rows;
-
- zend_bool cursor_exists;
- mysqlnd_stmt_use_or_store_func default_rset_handler;
-
- MYSQLND_CMD_BUFFER cmd_buffer;
-
- struct st_mysqlnd_stmt_methods *m;
-};
-
+#include "mysqlnd_structs.h"
/* Library related */
-PHPAPI void mysqlnd_restart_psession(MYSQLND *conn);
+#define mysqlnd_restart_psession(conn) _mysqlnd_restart_psession((conn) TSRMLS_CC)
+PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn TSRMLS_DC);
PHPAPI void mysqlnd_end_psession(MYSQLND *conn);
PHPAPI void mysqlnd_minfo_print_hash(zval *values);
#define mysqlnd_thread_safe() TRUE
/* Connect */
-PHPAPI MYSQLND * mysqlnd_init(zend_bool persistent);
+#define mysqlnd_init(persistent) _mysqlnd_init((persistent) TSRMLS_CC)
+PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC);
PHPAPI MYSQLND * mysqlnd_connect(MYSQLND *conn,
char *host, char *user,
char *passwd, unsigned int passwd_len,
#define mysqlnd_change_user(conn, user, passwd, db) (conn)->m->change_user((conn), (user), (passwd), (db) TSRMLS_CC)
-#define mysqlnd_debug(x)
+#define mysqlnd_debug(x) _mysqlnd_debug((x) TSRMLS_CC)
+void _mysqlnd_debug(const char *mode TSRMLS_DC);
/* Query */
#define mysqlnd_fetch_into(result, flags, ret_val, ext) (result)->m.fetch_into((result), (flags), (ret_val), (ext) TSRMLS_CC ZEND_FILE_LINE_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_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))
+#define mysqlnd_data_seek(result, row) (result)->m.seek_data((result), (row) TSRMLS_CC)
/*****************************************************************************************************/
#if defined(MYSQLND_USE_OPTIMISATIONS) && MYSQLND_USE_OPTIMISATIONS == 1
#define mysqlnd_field_seek(result, ofs) (result)->m.seek_field((result), (ofs))
#define mysqlnd_field_tell(result) (result)->meta? (result)->meta->current_field:0)
-#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result))
+#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result) TSRMLS_CC)
#define mysqlnd_fetch_field_direct(result,fnr) ((result)->meta? &((result)->meta->fields[(fnr)]):NULL)
/* mysqlnd metadata */
#define mysqlnd_field_seek(result, ofs) (result)->m.seek_field((result), (ofs))
#define mysqlnd_field_tell(result) (result)->m.field_tell((result))
-#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result))
-#define mysqlnd_fetch_field_direct(result,fnr) (result)->m.fetch_field_direct((result), (fnr))
+#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result) TSRMLS_CC)
+#define mysqlnd_fetch_field_direct(result,fnr) (result)->m.fetch_field_direct((result), (fnr) TSRMLS_CC)
/* mysqlnd metadata */
PHPAPI const char * mysqlnd_get_client_info();
PHPAPI const char * mysqlnd_field_type_name(enum mysqlnd_field_types field_type);
/* LOAD DATA LOCAL */
-PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn, zend_bool free_callback);
+PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn);
PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND * const conn, const char * const funcname);
/* Simple commands */
#define mysqlnd_commit(conn) (conn)->m->query((conn), "COMMIT", sizeof("COMMIT")-1 TSRMLS_CC)
#define mysqlnd_rollback(conn) (conn)->m->query((conn), "ROLLBACK", sizeof("ROLLBACK")-1 TSRMLS_CC)
#define mysqlnd_list_dbs(conn, wild) (conn)->m->list_method((conn), wild? "SHOW DATABASES LIKE %s":"SHOW DATABASES", (wild), NULL TSRMLS_CC)
-#define mysqlnd_list_fields(conn, tab,wild) (conn)->m->list_method((conn), wild? "SHOW FIELDS FROM %s LIKE %s":"SHOW FIELDS FROM %s", wild, tab TSRMLS_CC)
+#define mysqlnd_list_fields(conn, tab,wild) (conn)->m->list_fields((conn), (tab), (wild) TSRMLS_CC)
#define mysqlnd_list_processes(conn) (conn)->m->list_method((conn), "SHOW PROCESSLIST", NULL, NULL TSRMLS_CC)
#define mysqlnd_list_tables(conn, wild) (conn)->m->list_method((conn), wild? "SHOW TABLES LIKE %s":"SHOW TABLES", (wild), NULL TSRMLS_CC)
#define mysqlnd_dump_debug_info(conn) (conn)->m->server_dump_debug_information((conn) TSRMLS_CC)
#define mysqlnd_get_server_version(conn) (conn)->m->get_server_version((conn))
#define mysqlnd_set_character_set(conn, cs) (conn)->m->set_charset((conn), (cs) TSRMLS_CC)
#define mysqlnd_stat(conn, msg, msg_len) (conn)->m->get_server_statistics((conn), (msg), (msg_len) TSRMLS_CC)
-#define mysqlnd_options(conn, opt, value) (conn)->m->set_client_option((conn), (opt), (value))
+#define mysqlnd_options(conn, opt, value) (conn)->m->set_client_option((conn), (opt), (value) TSRMLS_CC)
#define mysqlnd_set_server_option(conn, op) (conn)->m->set_server_option((conn), (op) TSRMLS_CC)
/* Escaping */
#define mysqlnd_real_escape_string(conn, newstr, escapestr, escapestr_len) \
- (conn)->m->escape_string((conn), (newstr), (escapestr), (escapestr_len))
+ (conn)->m->escape_string((conn), (newstr), (escapestr), (escapestr_len) TSRMLS_CC)
#define mysqlnd_escape_string(newstr, escapestr, escapestr_len) \
- mysqlnd_old_escape_string((newstr), (escapestr), (escapestr_len))
+ mysqlnd_old_escape_string((newstr), (escapestr), (escapestr_len) TSRMLS_CC)
-PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len);
+PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len TSRMLS_DC);
/* PS */
-#define mysqlnd_stmt_init(conn) (conn)->m->stmt_init((conn))
+#define mysqlnd_stmt_init(conn) (conn)->m->stmt_init((conn) TSRMLS_CC)
#define mysqlnd_stmt_store_result(stmt) (!mysqlnd_stmt_field_count((stmt)) ? PASS:((stmt)->m->store_result((stmt) TSRMLS_CC)? PASS:FAIL))
#define mysqlnd_stmt_get_result(stmt) (stmt)->m->get_result((stmt) TSRMLS_CC)
-#define mysqlnd_stmt_data_seek(stmt, row) (stmt)->m->seek_data((stmt), (row))
+#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)
#define mysqlnd_stmt_send_long_data(s,p,d,l) (s)->m->send_long_data((s), (p), (d), (l) TSRMLS_CC)
-#define mysqlnd_stmt_bind_param(stmt,bind) (stmt)->m->bind_param((stmt), (bind))
-#define mysqlnd_stmt_bind_result(stmt,bind) (stmt)->m->bind_result((stmt), (bind))
+#define mysqlnd_stmt_bind_param(stmt,bind) (stmt)->m->bind_param((stmt), (bind) TSRMLS_CC)
+#define mysqlnd_stmt_bind_result(stmt,bind) (stmt)->m->bind_result((stmt), (bind) 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))
+#define mysqlnd_stmt_result_metadata(stmt) (stmt)->m->get_result_metadata((stmt) TSRMLS_CC)
#define mysqlnd_stmt_free_result(stmt) (stmt)->m->free_result((stmt) TSRMLS_CC)
#define mysqlnd_stmt_close(stmt, implicit) (stmt)->m->dtor((stmt), (implicit) TSRMLS_CC)
#define mysqlnd_stmt_reset(stmt) (stmt)->m->reset((stmt) TSRMLS_CC)
-#define mysqlnd_stmt_attr_get(stmt, attr, value) (stmt)->m->get_attribute((stmt), (attr), (value))
-#define mysqlnd_stmt_attr_set(stmt, attr, value) (stmt)->m->set_attribute((stmt), (attr), (value))
+#define mysqlnd_stmt_attr_get(stmt, attr, value) (stmt)->m->get_attribute((stmt), (attr), (value) TSRMLS_CC)
+#define mysqlnd_stmt_attr_set(stmt, attr, value) (stmt)->m->set_attribute((stmt), (attr), (value) TSRMLS_CC)
#define mysqlnd_stmt_fetch(stmt, fetched) (stmt)->m->fetch((stmt), (fetched) TSRMLS_CC)
PHPAPI void _mysqlnd_get_client_stats(zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
/* Persistent caching zval allocator */
-PHPAPI MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_init_cache(unsigned int cache_size);
-PHPAPI void mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache);
-PHPAPI void mysqlnd_palloc_stats(const MYSQLND_ZVAL_PCACHE * const cache, zval *return_value);
+#define mysqlnd_palloc_init_cache(size) _mysqlnd_palloc_init_cache((size) TSRMLS_CC)
+#define mysqlnd_palloc_free_cache(cache) _mysqlnd_palloc_free_cache((cache) TSRMLS_CC)
+PHPAPI MYSQLND_ZVAL_PCACHE* _mysqlnd_palloc_init_cache(unsigned int cache_size TSRMLS_DC);
+PHPAPI void _mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache TSRMLS_DC);
+PHPAPI void mysqlnd_palloc_stats(const MYSQLND_ZVAL_PCACHE * const cache,
+ zval *return_value);
+
+#define mysqlnd_palloc_rinit(cache) _mysqlnd_palloc_rinit((cache) TSRMLS_CC)
+#define mysqlnd_palloc_rshutdown(cache) _mysqlnd_palloc_rshutdown((cache) TSRMLS_CC)
+PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache TSRMLS_DC);
+PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * cache TSRMLS_DC);
-PHPAPI MYSQLND_THD_ZVAL_PCACHE * mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache);
-PHPAPI void mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * cache);
+#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)
-PHPAPI MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache);
-MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache);
-PHPAPI void mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache);
+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);
+PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC);
/* There two should not be used from outside */
-void * mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const cache, zend_bool *allocated);
+void * mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const cache, zend_bool *allocated TSRMLS_DC);
void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const cache,
enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC);
ZEND_BEGIN_MODULE_GLOBALS(mysqlnd)
zend_bool collect_statistics;
+ zend_bool collect_memory_statistics;
+ char* debug; /* The actual string */
+ MYSQLND_DEBUG *dbg; /* The DBG object */
+ long net_cmd_buffer_size;
+ long net_read_buffer_size;
ZEND_END_MODULE_GLOBALS(mysqlnd)
+ZEND_EXTERN_MODULE_GLOBALS(mysqlnd);
+
#ifdef ZTS
#define MYSQLND_G(v) TSRMG(mysqlnd_globals_id, zend_mysqlnd_globals *, v)
#else
#include "php_globals.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
+#include "mysqlnd_debug.h"
/* {{{ utf8 functions */
-static uint check_mb_utf8(const char *start, const char *end)
+static uint check_mb_utf8_sequence(const char *start, const char *end)
{
zend_uchar c;
return 0;
}
+static uint check_mb_utf8_valid(const char *start, const char *end)
+{
+ uint len = check_mb_utf8_sequence(start, end);
+ return (len > 1)? len:0;
+}
static uint mysqlnd_mbcharlen_utf8(uint utf8)
{
static uint check_mb_big5(const char *start, const char *end)
{
- return ((end - start) > 1 && valid_big5head(*(start)) && valid_big5tail(*(start + 1)) ? 2 : 0);
+ return (valid_big5head(*(start)) && (end - start) > 1 && valid_big5tail(*(start + 1)) ? 2 : 0);
}
static uint check_mb_cp932(const char *start, const char *end)
{
- return (((end > start) + 1) && valid_cp932head((uint)start[0]) &&
- valid_cp932tail((uint)start[1])) ? 2 : 0;
+ return (valid_cp932head((zend_uchar)start[0]) && (end - start > 1) &&
+ valid_cp932tail((zend_uchar)start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_cp932(uint cp932)
{
- return (valid_cp932head(cp932)) ? 2 : 1;
+ return (valid_cp932head((zend_uchar)cp932)) ? 2 : 1;
}
/* }}} */
static uint check_mb_eucjpms(const char *start, const char *end)
{
- if (*((uint *)start) < 0x80) {
+ if (*((zend_uchar *)start) < 0x80) {
return 0; /* invalid eucjpms character */
}
if (valid_eucjpms(start[0]) && (end - start) > 1 && valid_eucjpms(start[1])) {
/* {{{ gb2312 functions */
-#define valid_gb2312_head(c) (0xA1 <= (c) && (c) <= 0xF7)
-#define valid_gb2312_tail(c) (0xA1 <= (c) && (c) <= 0xFE)
+#define valid_gb2312_head(c) (0xA1 <= (zend_uchar)(c) && (zend_uchar)(c) <= 0xF7)
+#define valid_gb2312_tail(c) (0xA1 <= (zend_uchar)(c) && (zend_uchar)(c) <= 0xFE)
static uint check_mb_gb2312(const char *start, const char *end)
{
- return (end - start > 1 || valid_gb2312_head((uint)start[0]) ||
+ return (valid_gb2312_head((uint)start[0]) && end - start > 1 &&
valid_gb2312_tail((uint)start[1])) ? 2 : 0;
}
/* {{{ gbk functions */
-#define valid_gbk_head(c) ((uint)(c) >> 8)
-#define valid_gbk_tail(c) ((uint)(c) & 0xFF)
+#define valid_gbk_head(c) (0x81<=(zend_uchar)(c) && (zend_uchar)(c)<=0xFE)
+#define valid_gbk_tail(c) ((0x40<=(zend_uchar)(c) && (zend_uchar)(c)<=0x7E) || (0x80<=(zend_uchar)(c) && (zend_uchar)(c)<=0xFE))
static uint check_mb_gbk(const char *start, const char *end)
{
- if (end - start <= 1) {
- return 0; /* invalid length */
- }
- return (valid_gbk_head(start[0]) && valid_gbk_tail(start[1])) ? 2 : 0;
+ return (valid_gbk_head(start[0]) && (end) - (start) > 1 && valid_gbk_tail(start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_gbk(uint gbk)
}
/* }}} */
+
/* {{{ sjis functions */
#define valid_sjis_head(c) ((0x81 <= (c) && (c) <= 0x9F) && \
(0xE0 <= (c) && (c) <= 0xFC))
static uint check_mb_sjis(const char *start, const char *end)
{
- if (end - start <= 1) {
- return 0;
- }
- return (valid_sjis_head((uint)start[0]) && valid_sjis_tail((uint)start[1])) ? 2 : 0;
+ return (valid_sjis_head((zend_uchar)start[0]) && (end - start) > 1 && valid_sjis_tail((zend_uchar)start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_sjis(uint sjis)
{
- return (valid_sjis_head((uint)sjis)) ? 2 : 1;
+ return (valid_sjis_head((zend_uchar)sjis)) ? 2 : 1;
}
/* }}} */
static uint check_mb_ujis(const char *start, const char *end)
{
- if ((uint)start[0] < 0x80) {
+ if (*(uchar*)start < 0x80) {
return 0; /* invalid ujis character */
}
if (valid_ujis(*(start)) && valid_ujis(*((start)+1))) {
if (valid_ujis_ss2(*(start)) && valid_ujis_kata(*((start)+1))) {
return 2;
}
- if (valid_ujis_ss3(*(start)) && (end-start) > 2 && valid_ujis(*((start)+1))
- && valid_ujis(*((start)+2))) {
+ if (valid_ujis_ss3(*(start)) && (end-start) > 2 && valid_ujis(*((start)+1)) && valid_ujis(*((start)+2))) {
return 3;
}
return 0;
static uint mysqlnd_mbcharlen_ujis(uint ujis)
{
- if (((ujis & 0xFF) >= 0xA1 && (ujis & 0xFF) <= 0xFE) ||
- ((ujis & 0xFF) == 0x8E)) {
- return 2;
- }
- if ((ujis & 0xFF) == 0x8F) {
- return 3;
- }
- return 1;
+ return (valid_ujis(ujis)? 2: valid_ujis_ss2(ujis)? 2: valid_ujis_ss3(ujis)? 3: 1);
}
/* }}} */
{ 13, "sjis", "sjis_japanese_ci", 1, 2, 0, mysqlnd_mbcharlen_sjis, check_mb_sjis},
{ 16, "hebrew", "hebrew_general_ci", 1, 1, 0, NULL, NULL},
{ 18, "tis620", "tis620_thai_ci", 1, 1, 0, NULL, NULL},
- { 19, "euckr", "euckr_korean_ci", 1, 2, 0, mysqlnd_mbcharlen_euckr, check_mb_eucjpms},
+ { 19, "euckr", "euckr_korean_ci", 1, 2, 0, mysqlnd_mbcharlen_euckr, check_mb_euckr},
{ 22, "koi8u", "koi8u_general_ci", 1, 1, 0, NULL, NULL},
{ 24, "gb2312", "gb2312_chinese_ci", 1, 2, 0, mysqlnd_mbcharlen_gb2312, check_mb_gb2312},
{ 25, "greek", "greek_general_ci", 1, 1, 0, NULL, NULL},
{ 28, "gbk", "gbk_chinese_ci", 1, 2, 0, mysqlnd_mbcharlen_gbk, check_mb_gbk},
{ 30, "latin5", "latin5_turkish_ci", 1, 1, 0, NULL, NULL},
{ 32, "armscii8", "armscii8_general_ci", 1, 1, 0, NULL, NULL},
- { 33, "utf8", "utf8_general_ci", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
+ { 33, "utf8", "utf8_general_ci", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 35, "ucs2", "ucs2_general_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 36, "cp866", "cp866_general_ci", 1, 1, 0, NULL, NULL},
{ 37, "keybcs2", "keybcs2_general_ci", 1, 1, 0, NULL, NULL},
{ 63, "binary", "binary", 1, 1, 0, NULL, NULL},
{ 92, "geostd8", "geostd8_general_ci", 1, 1, 0, NULL, NULL},
{ 95, "cp932", "cp932_japanese_ci", 1, 2, 1, mysqlnd_mbcharlen_cp932, check_mb_cp932},
- { 97, "eucjpms", "eucjpms_japanese_ci", 1, 3, 0, mysqlnd_mbcharlen_eucjpms, },
+ { 97, "eucjpms", "eucjpms_japanese_ci", 1, 3, 0, mysqlnd_mbcharlen_eucjpms, check_mb_eucjpms},
{ 2, "latin2", "latin2_czech_cs", 1, 1, 0, NULL, NULL},
{ 5, "latin1", "latin1_german_ci", 1, 1, 0, NULL, NULL},
{ 14, "cp1251", "cp1251_bulgarian_ci", 1, 1, 0, NULL, NULL},
{ 81, "cp852", "cp852_bin", 1, 1, 0, NULL, NULL},
{ 82, "swe7", "swe7_bin", 1, 1, 0, NULL, NULL},
{ 93, "geostd8", "geostd8_bin", 1, 1, 0, NULL, NULL},
- { 83, "utf8", "utf8_bin", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
+ { 83, "utf8", "utf8_bin", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 84, "big5", "big5_bin", 1, 2, 0, mysqlnd_mbcharlen_big5, check_mb_big5},
{ 85, "euckr", "euckr_bin", 1, 2, 0, mysqlnd_mbcharlen_euckr, check_mb_euckr},
{ 86, "gb2312", "gb2312_bin", 1, 2, 0, mysqlnd_mbcharlen_gb2312, check_mb_gb2312},
{ 144, "ucs2", "ucs2_persian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 145, "ucs2", "ucs2_esperanto_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 146, "ucs2", "ucs2_hungarian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
- { 192, "utf8", "utf8_general_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 193, "utf8", "utf8_icelandic_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 194, "utf8", "utf8_latvian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 195, "utf8", "utf8_romanian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 196, "utf8", "utf8_slovenian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 197, "utf8", "utf8_polish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 198, "utf8", "utf8_estonian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 119, "utf8", "utf8_spanish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 200, "utf8", "utf8_swedish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 201, "utf8", "utf8_turkish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 202, "utf8", "utf8_czech_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 203, "utf8", "utf8_danish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8 },
- { 204, "utf8", "utf8_lithunian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8 },
- { 205, "utf8", "utf8_slovak_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 206, "utf8", "utf8_spanish2_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 207, "utf8", "utf8_roman_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 208, "utf8", "utf8_persian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 209, "utf8", "utf8_esperanto_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 210, "utf8", "utf8_hungarian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8},
- { 254, "utf8", "utf8_general_cs", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8 },
+ { 192, "utf8", "utf8_general_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 193, "utf8", "utf8_icelandic_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 194, "utf8", "utf8_latvian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 195, "utf8", "utf8_romanian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 196, "utf8", "utf8_slovenian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 197, "utf8", "utf8_polish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 198, "utf8", "utf8_estonian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 119, "utf8", "utf8_spanish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 200, "utf8", "utf8_swedish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 201, "utf8", "utf8_turkish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 202, "utf8", "utf8_czech_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 203, "utf8", "utf8_danish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid },
+ { 204, "utf8", "utf8_lithunian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid },
+ { 205, "utf8", "utf8_slovak_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 206, "utf8", "utf8_spanish2_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 207, "utf8", "utf8_roman_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 208, "utf8", "utf8_persian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 209, "utf8", "utf8_esperanto_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 210, "utf8", "utf8_hungarian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
+ { 254, "utf8", "utf8_general_cs", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid },
{ 0, NULL, NULL, 0, 0, 0, NULL, NULL}
};
/* }}} */
/* {{{ mysqlnd_cset_escape_quotes */
-PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const cset, char *newstr, const char *escapestr, int escapestr_len)
+PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const cset, char *newstr,
+ const char *escapestr, int escapestr_len TSRMLS_DC)
{
const char *newstr_s = newstr;
const char *newstr_e = newstr + 2 * escapestr_len;
const char *end = escapestr + escapestr_len;
zend_bool escape_overflow = FALSE;
+ DBG_ENTER("mysqlnd_cset_escape_quotes");
+
for (;escapestr < end; escapestr++) {
uint len = 0;
/* check unicode characters */
- if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1 &&
- (len = cset->mb_valid(escapestr, end))) {
+ if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
/* check possible overflow */
if ((newstr + len) > newstr_e) {
escapestr--;
continue;
}
- if (*newstr == '\'') {
+ if (*escapestr == '\'') {
if (newstr + 2 > newstr_e) {
escape_overflow = TRUE;
break;
escape_overflow = TRUE;
break;
}
- *newstr++= *escapestr;
+ *newstr++ = *escapestr;
}
}
*newstr = '\0';
if (escape_overflow) {
- return (ulong)~0;
+ DBG_RETURN((ulong)~0);
}
- return (ulong)(newstr - newstr_s);
+ DBG_RETURN((ulong)(newstr - newstr_s));
}
/* }}} */
/* {{{ mysqlnd_cset_escape_slashes */
-PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr, const char *escapestr, int escapestr_len)
+PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr,
+ const char *escapestr, int escapestr_len TSRMLS_DC)
{
const char *newstr_s = newstr;
const char *newstr_e = newstr + 2 * escapestr_len;
const char *end = escapestr + escapestr_len;
zend_bool escape_overflow = FALSE;
+
+ DBG_ENTER("mysqlnd_cset_escape_slashes");
for (;escapestr < end; escapestr++) {
char esc = '\0';
uint len = 0;
/* check unicode characters */
- if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1 &&
- (len = cset->mb_valid(escapestr, end))) {
-
+ if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
/* check possible overflow */
if ((newstr + len) > newstr_e) {
escape_overflow = TRUE;
escapestr--;
continue;
}
- if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1 &&
- (len = cset->mb_valid(escapestr, end))) {
+ if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
esc = *escapestr;
} else {
switch (*escapestr) {
*newstr = '\0';
if (escape_overflow) {
- return (ulong)~0;
+ DBG_RETURN((ulong)~0);
}
- return (ulong)(newstr - newstr_s);
+ DBG_RETURN((ulong)(newstr - newstr_s));
}
/* }}} */
*/
PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char *newstr,
- const char *escapestr, int escapestr_len);
+ const char *escapestr, int escapestr_len TSRMLS_DC);
PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr,
- const char *escapestr, int escapestr_len);
+ const char *escapestr, int escapestr_len TSRMLS_DC);
/*
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 6 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Georg Richter <georg@mysql.com> |
+ | Andrey Hristov <andrey@mysql.com> |
+ | Ulf Wendel <uwendel@mysql.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#include "php.h"
+#include "mysqlnd.h"
+#include "mysqlnd_priv.h"
+#include "mysqlnd_debug.h"
+#include "mysqlnd_wireprotocol.h"
+#include "mysqlnd_palloc.h"
+#include "mysqlnd_statistics.h"
+#include "zend_builtin_functions.h"
+
+
+static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace";
+
+#ifdef ZTS
+#define MYSQLND_ZTS(self) TSRMLS_D = (self)->TSRMLS_C
+#else
+#define MYSQLND_ZTS(self)
+#endif
+
+#define MYSQLND_DEBUG_DUMP_TIME 1
+#define MYSQLND_DEBUG_DUMP_TRACE 2
+#define MYSQLND_DEBUG_DUMP_PID 4
+#define MYSQLND_DEBUG_DUMP_LINE 8
+#define MYSQLND_DEBUG_DUMP_FILE 16
+#define MYSQLND_DEBUG_DUMP_LEVEL 32
+#define MYSQLND_DEBUG_APPEND 64
+#define MYSQLND_DEBUG_FLUSH 128
+#define MYSQLND_DEBUG_TRACE_MEMORY_CALLS 256
+
+static char * mysqlnd_emalloc_name = "_mysqlnd_emalloc";
+static char * mysqlnd_pemalloc_name = "_mysqlnd_pemalloc";
+static char * mysqlnd_ecalloc_name = "_mysqlnd_ecalloc";
+static char * mysqlnd_pecalloc_name = "_mysqlnd_pecalloc";
+static char * mysqlnd_erealloc_name = "_mysqlnd_erealloc";
+static char * mysqlnd_perealloc_name= "_mysqlnd_perealloc";
+static char * mysqlnd_efree_name = "_mysqlnd_efree";
+static char * mysqlnd_pefree_name = "_mysqlnd_pefree";
+static char * mysqlnd_malloc_name = "_mysqlnd_malloc";
+static char * mysqlnd_calloc_name = "_mysqlnd_calloc";
+static char * mysqlnd_realloc_name = "_mysqlnd_realloc";
+static char * mysqlnd_free_name = "_mysqlnd_free";
+
+/* {{{ mysqlnd_debug::open */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen)
+{
+ MYSQLND_ZTS(self);
+
+ if (!self->file_name) {
+ return FAIL;
+ }
+
+ self->stream = php_stream_open_wrapper(self->file_name,
+ reopen == TRUE || self->flags & MYSQLND_DEBUG_APPEND? "ab":"wb",
+ REPORT_ERRORS, NULL);
+ return self->stream? PASS:FAIL;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_debug::log */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_debug, log)(MYSQLND_DEBUG * self,
+ unsigned int line, const char * const file,
+ unsigned int level, const char * type, const char * message)
+{
+ char pipe_buffer[512];
+ MYSQLND_ZTS(self);
+ enum_func_status ret;
+ int i;
+ char * message_line;
+ size_t message_line_len;
+ unsigned int flags = self->flags;
+ char pid_buffer[10], time_buffer[30], file_buffer[200],
+ line_buffer[6], level_buffer[7];
+
+ if (!self->stream) {
+ if (FAIL == self->m->open(self, FALSE)) {
+ return FAIL;
+ }
+ }
+
+ if (level == -1) {
+ level = zend_stack_count(&self->call_stack);
+ }
+ i = MIN(level, sizeof(pipe_buffer) / 2 - 1);
+ pipe_buffer[i*2] = '\0';
+ for (;i > 0;i--) {
+ pipe_buffer[i*2 - 1] = ' ';
+ pipe_buffer[i*2 - 2] = '|';
+ }
+
+
+ if (flags & MYSQLND_DEBUG_DUMP_PID) {
+ snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
+ pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_TIME) {
+ /* The following from FF's DBUG library, which is in the public domain */
+#if defined(PHP_WIN32)
+ /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
+ in system ticks, 10 ms intervals. See my_getsystime.c for high res */
+ SYSTEMTIME loc_t;
+ GetLocalTime(&loc_t);
+ snprintf(time_buffer, sizeof(time_buffer) - 1,
+ /* "%04d-%02d-%02d " */
+ "%02d:%02d:%02d.%06d ",
+ /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
+ loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
+ time_buffer[sizeof(time_buffer) - 1 ] = '\0';
+#else
+ struct timeval tv;
+ struct tm *tm_p;
+ if (gettimeofday(&tv, NULL) != -1) {
+ if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
+ snprintf(time_buffer, sizeof(time_buffer) - 1,
+ /* "%04d-%02d-%02d " */
+ "%02d:%02d:%02d.%06d ",
+ /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
+ tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
+ (int) (tv.tv_usec));
+ time_buffer[sizeof(time_buffer) - 1 ] = '\0';
+ }
+ }
+#endif
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_FILE) {
+ snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
+ file_buffer[sizeof(file_buffer) - 1 ] = '\0';
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_LINE) {
+ snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
+ line_buffer[sizeof(line_buffer) - 1 ] = '\0';
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
+ snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
+ level_buffer[sizeof(level_buffer) - 1 ] = '\0';
+ }
+
+ message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
+ flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
+ pipe_buffer, type? type:"", message);
+
+ ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
+ efree(message_line);
+ if (flags & MYSQLND_DEBUG_FLUSH) {
+ self->m->close(self);
+ self->m->open(self, TRUE);
+ }
+ return ret;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_debug::log_va */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self,
+ unsigned int line, const char * const file,
+ unsigned int level, const char * type,
+ const char *format, ...)
+{
+ char pipe_buffer[512];
+ MYSQLND_ZTS(self);
+ int i;
+ enum_func_status ret;
+ char * message_line, *buffer;
+ size_t message_line_len;
+ va_list args;
+ unsigned int flags = self->flags;
+ char pid_buffer[10], time_buffer[30], file_buffer[200],
+ line_buffer[6], level_buffer[7];
+
+ if (!self->stream) {
+ if (FAIL == self->m->open(self, FALSE)) {
+ return FAIL;
+ }
+ }
+
+ if (level == -1) {
+ level = zend_stack_count(&self->call_stack);
+ }
+ i = MIN(level, sizeof(pipe_buffer) / 2 - 1);
+ pipe_buffer[i*2] = '\0';
+ for (;i > 0;i--) {
+ pipe_buffer[i*2 - 1] = ' ';
+ pipe_buffer[i*2 - 2] = '|';
+ }
+
+
+ if (flags & MYSQLND_DEBUG_DUMP_PID) {
+ snprintf(pid_buffer, sizeof(pid_buffer) - 1, "%5u: ", self->pid);
+ pid_buffer[sizeof(pid_buffer) - 1 ] = '\0';
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_TIME) {
+ /* The following from FF's DBUG library, which is in the public domain */
+#if defined(PHP_WIN32)
+ /* FIXME This doesn't give microseconds as in Unix case, and the resolution is
+ in system ticks, 10 ms intervals. See my_getsystime.c for high res */
+ SYSTEMTIME loc_t;
+ GetLocalTime(&loc_t);
+ snprintf(time_buffer, sizeof(time_buffer) - 1,
+ /* "%04d-%02d-%02d " */
+ "%02d:%02d:%02d.%06d ",
+ /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
+ loc_t.wHour, loc_t.wMinute, loc_t.wSecond, loc_t.wMilliseconds);
+ time_buffer[sizeof(time_buffer) - 1 ] = '\0';
+#else
+ struct timeval tv;
+ struct tm *tm_p;
+ if (gettimeofday(&tv, NULL) != -1) {
+ if ((tm_p= localtime((const time_t *)&tv.tv_sec))) {
+ snprintf(time_buffer, sizeof(time_buffer) - 1,
+ /* "%04d-%02d-%02d " */
+ "%02d:%02d:%02d.%06d ",
+ /*tm_p->tm_year + 1900, tm_p->tm_mon + 1, tm_p->tm_mday,*/
+ tm_p->tm_hour, tm_p->tm_min, tm_p->tm_sec,
+ (int) (tv.tv_usec));
+ time_buffer[sizeof(time_buffer) - 1 ] = '\0';
+ }
+ }
+#endif
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_FILE) {
+ snprintf(file_buffer, sizeof(file_buffer) - 1, "%14s: ", file);
+ file_buffer[sizeof(file_buffer) - 1 ] = '\0';
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_LINE) {
+ snprintf(line_buffer, sizeof(line_buffer) - 1, "%5u: ", line);
+ line_buffer[sizeof(line_buffer) - 1 ] = '\0';
+ }
+ if (flags & MYSQLND_DEBUG_DUMP_LEVEL) {
+ snprintf(level_buffer, sizeof(level_buffer) - 1, "%4u: ", level);
+ level_buffer[sizeof(level_buffer) - 1 ] = '\0';
+ }
+
+
+ va_start(args, format);
+ vspprintf(&buffer, 0, format, args);
+ va_end(args);
+
+ message_line_len = spprintf(&message_line, 0, "%s%s%s%s%s%s%s%s\n",
+ flags & MYSQLND_DEBUG_DUMP_PID? pid_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_TIME? time_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_FILE? file_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_LINE? line_buffer:"",
+ flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"",
+ pipe_buffer, type? type:"", buffer);
+ efree(buffer);
+
+ ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL;
+ efree(message_line);
+
+ if (flags & MYSQLND_DEBUG_FLUSH) {
+ self->m->close(self);
+ self->m->open(self, TRUE);
+ }
+ return ret;
+}
+/* }}} */
+
+
+/* FALSE - The DBG_ calls won't be traced, TRUE - will be traced */
+/* {{{ mysqlnd_res_meta::func_enter */
+static zend_bool
+MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self,
+ unsigned int line, const char * const file,
+ char * func_name, size_t func_name_len)
+{
+ if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
+ return FALSE;
+ }
+ if (zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
+ return FALSE;
+ }
+
+ if ((self->flags & MYSQLND_DEBUG_TRACE_MEMORY_CALLS) == 0 &&
+ (func_name == mysqlnd_emalloc_name || func_name == mysqlnd_pemalloc_name ||
+ func_name == mysqlnd_ecalloc_name || func_name == mysqlnd_pecalloc_name ||
+ func_name == mysqlnd_erealloc_name || func_name == mysqlnd_perealloc_name ||
+ func_name == mysqlnd_efree_name || func_name == mysqlnd_pefree_name ||
+ func_name == mysqlnd_efree_name || func_name == mysqlnd_pefree_name ||
+ func_name == mysqlnd_malloc_name || func_name == mysqlnd_calloc_name ||
+ func_name == mysqlnd_realloc_name || func_name == mysqlnd_free_name ||
+ func_name == mysqlnd_palloc_zval_ptr_dtor_name || func_name == mysqlnd_palloc_get_zval_name ||
+ func_name == mysqlnd_read_header_name || func_name == mysqlnd_read_body_name)) {
+ zend_stack_push(&self->call_stack, "", sizeof(""));
+ return FALSE;
+ }
+
+ zend_stack_push(&self->call_stack, func_name, func_name_len + 1);
+
+ if (zend_hash_num_elements(&self->not_filtered_functions) &&
+ 0 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
+ {
+ return FALSE;
+ }
+
+ self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, ">%s", func_name);
+ return TRUE;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_res_meta::func_leave */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line,
+ const char * const file)
+{
+ char *func_name;
+
+ if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) {
+ return PASS;
+ }
+ if (zend_stack_count(&self->call_stack) >= self->nest_level_limit) {
+ return PASS;
+ }
+
+ zend_stack_top(&self->call_stack, (void **)&func_name);
+
+ if (func_name[0] == '\0') {
+ ; /* don't log that function */
+ } else if (!zend_hash_num_elements(&self->not_filtered_functions) ||
+ 1 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1))
+ {
+ self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", func_name);
+ }
+
+ return zend_stack_del_top(&self->call_stack) == SUCCESS? PASS:FAIL;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_res_meta::close */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_debug, close)(MYSQLND_DEBUG * self)
+{
+ MYSQLND_ZTS(self);
+ if (self->stream) {
+ php_stream_free(self->stream, PHP_STREAM_FREE_CLOSE);
+ self->stream = NULL;
+ }
+ return PASS;
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_res_meta::free */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * self)
+{
+ if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
+ efree(self->file_name);
+ self->file_name = NULL;
+ }
+ zend_stack_destroy(&self->call_stack);
+ zend_hash_destroy(&self->not_filtered_functions);
+ efree(self);
+ return PASS;
+}
+/* }}} */
+
+enum mysqlnd_debug_parser_state
+{
+ PARSER_WAIT_MODIFIER,
+ PARSER_WAIT_COLON,
+ PARSER_WAIT_VALUE
+};
+
+
+/* {{{ mysqlnd_res_meta::set_mode */
+static void
+MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const mode)
+{
+ size_t mode_len = strlen(mode), i;
+ enum mysqlnd_debug_parser_state state = PARSER_WAIT_MODIFIER;
+
+ self->flags = 0;
+ self->nest_level_limit = 0;
+ if (self->file_name && self->file_name != mysqlnd_debug_default_trace_file) {
+ efree(self->file_name);
+ self->file_name = NULL;
+ }
+ if (zend_hash_num_elements(&self->not_filtered_functions)) {
+ zend_hash_destroy(&self->not_filtered_functions);
+ zend_hash_init(&self->not_filtered_functions, 0, NULL, NULL, 0);
+ }
+
+ for (i = 0; i < mode_len; i++) {
+ switch (mode[i]) {
+ case 'O':
+ case 'A':
+ self->flags |= MYSQLND_DEBUG_FLUSH;
+ case 'a':
+ case 'o':
+ if (mode[i] == 'a' || mode[i] == 'A') {
+ self->flags |= MYSQLND_DEBUG_APPEND;
+ }
+ if (i + 1 < mode_len && mode[i+1] == ',') {
+ unsigned int j = i + 2;
+ while (j < mode_len) {
+ if (mode[j] == ':') {
+ break;
+ }
+ j++;
+ }
+ if (j > i + 2) {
+ self->file_name = estrndup(mode + i + 2, j - i - 2);
+ }
+ i = j;
+ } else {
+ self->file_name = (char *) mysqlnd_debug_default_trace_file;
+ }
+ state = PARSER_WAIT_COLON;
+ break;
+ case ':':
+#if 0
+ if (state != PARSER_WAIT_COLON) {
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Consecutive semicolons at position %u", i);
+ }
+#endif
+ state = PARSER_WAIT_MODIFIER;
+ break;
+ case 'f': /* limit output to these functions */
+ if (i + 1 < mode_len && mode[i+1] == ',') {
+ unsigned int j = i + 2;
+ i++;
+ while (j < mode_len) {
+ if (mode[j] == ':') {
+ /* function names with :: */
+ if ((j + 1 < mode_len) && mode[j+1] == ':') {
+ j += 2;
+ continue;
+ }
+ }
+ if (mode[j] == ',' || mode[j] == ':') {
+ if (j > i + 2) {
+ char func_name[1024];
+ size_t func_name_len = MIN(sizeof(func_name) - 1, j - i - 1);
+ memcpy(func_name, mode + i + 1, func_name_len);
+ func_name[func_name_len] = '\0';
+
+ zend_hash_add_empty_element(&self->not_filtered_functions,
+ func_name, func_name_len + 1);
+ i = j;
+ }
+ if (mode[j] == ':') {
+ break;
+ }
+ }
+ j++;
+ }
+ i = j;
+ } else {
+#if 0
+ php_error_docref(NULL TSRMLS_CC, E_WARNING,
+ "Expected list of functions for '%c' found none", mode[i]);
+#endif
+ }
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'D':
+ case 'd':
+ case 'g':
+ case 'p':
+ /* unsupported */
+ if ((i + 1) < mode_len && mode[i+1] == ',') {
+ i+= 2;
+ while (i < mode_len) {
+ if (mode[i++] == ':') {
+ break;
+ }
+ }
+ }
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'F':
+ self->flags |= MYSQLND_DEBUG_DUMP_FILE;
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'i':
+ self->flags |= MYSQLND_DEBUG_DUMP_PID;
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'L':
+ self->flags |= MYSQLND_DEBUG_DUMP_LINE;
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'n':
+ self->flags |= MYSQLND_DEBUG_DUMP_LEVEL;
+ state = PARSER_WAIT_COLON;
+ break;
+ case 't':
+ if (mode[i+1] == ',') {
+ unsigned int j = i + 2;
+ while (j < mode_len) {
+ if (mode[j] == ':') {
+ break;
+ }
+ j++;
+ }
+ if (j > i + 2) {
+ char *value_str = estrndup(mode + i + 2, j - i - 2);
+ self->nest_level_limit = atoi(value_str);
+ efree(value_str);
+ }
+ i = j;
+ } else {
+ self->nest_level_limit = 200; /* default value for FF DBUG */
+ }
+ self->flags |= MYSQLND_DEBUG_DUMP_TRACE;
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'T':
+ self->flags |= MYSQLND_DEBUG_DUMP_TIME;
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'N':
+ case 'P':
+ case 'r':
+ case 'S':
+ state = PARSER_WAIT_COLON;
+ break;
+ case 'm': /* mysqlnd extension - trace memory functions */
+ self->flags |= MYSQLND_DEBUG_TRACE_MEMORY_CALLS;
+ state = PARSER_WAIT_COLON;
+ break;
+ default:
+ if (state == PARSER_WAIT_MODIFIER) {
+#if 0
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unrecognized format '%c'", mode[i]);
+#endif
+ if (i+1 < mode_len && mode[i+1] == ',') {
+ i+= 2;
+ while (i < mode_len) {
+ if (mode[i] == ':') {
+ break;
+ }
+ i++;
+ }
+ }
+ state = PARSER_WAIT_COLON;
+ } else if (state == PARSER_WAIT_COLON) {
+#if 0
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Colon expected, '%c' found", mode[i]);
+#endif
+ }
+ break;
+ }
+ }
+}
+/* }}} */
+
+
+MYSQLND_CLASS_METHODS_START(mysqlnd_debug)
+ MYSQLND_METHOD(mysqlnd_debug, open),
+ MYSQLND_METHOD(mysqlnd_debug, set_mode),
+ MYSQLND_METHOD(mysqlnd_debug, log),
+ MYSQLND_METHOD(mysqlnd_debug, log_va),
+ MYSQLND_METHOD(mysqlnd_debug, func_enter),
+ MYSQLND_METHOD(mysqlnd_debug, func_leave),
+ MYSQLND_METHOD(mysqlnd_debug, close),
+ MYSQLND_METHOD(mysqlnd_debug, free),
+MYSQLND_CLASS_METHODS_END;
+
+
+
+/* {{{ mysqlnd_debug_init */
+MYSQLND_DEBUG *mysqlnd_debug_init(TSRMLS_D)
+{
+ MYSQLND_DEBUG *ret = ecalloc(1, sizeof(MYSQLND_DEBUG));
+#ifdef ZTS
+ ret->TSRMLS_C = TSRMLS_C;
+#endif
+ ret->nest_level_limit = 0;
+ ret->pid = getpid();
+ zend_stack_init(&ret->call_stack);
+ zend_hash_init(&ret->not_filtered_functions, 0, NULL, NULL, 0);
+
+ ret->m = & mysqlnd_mysqlnd_debug_methods;
+
+ return ret;
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_debug */
+void _mysqlnd_debug(const char *mode TSRMLS_DC)
+{
+#ifdef PHP_DEBUG
+ MYSQLND_DEBUG *dbg = MYSQLND_G(dbg);
+ if (!dbg) {
+ MYSQLND_G(dbg) = dbg = mysqlnd_debug_init(TSRMLS_C);
+ if (!dbg) {
+ return;
+ }
+ }
+
+ dbg->m->close(dbg);
+ dbg->m->set_mode(dbg, mode);
+ while (zend_stack_count(&dbg->call_stack)) {
+ zend_stack_del_top(&dbg->call_stack);
+ }
+#endif
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_emalloc */
+void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_emalloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
+ ret = emalloc(size);
+ DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
+ DBG_INF_FMT("size=%lu ptr=%p", size, ret);
+
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(STAT_MEM_EMALLOC_COUNT, 1, STAT_MEM_EMALLOC_AMMOUNT, size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_pemalloc */
+void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_pemalloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ if (persistent == FALSE) {
+ DBG_INF_FMT("before: %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+
+ ret = pemalloc(size, persistent);
+ DBG_INF_FMT("size=%lu ptr=%p persistent=%d", size, ret, persistent);
+
+ if (persistent == FALSE) {
+ DBG_INF_FMT("after : %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+
+ if (MYSQLND_G(collect_memory_statistics)) {
+ enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_MALLOC_COUNT:STAT_MEM_EMALLOC_COUNT;
+ enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_MALLOC_AMMOUNT:STAT_MEM_EMALLOC_AMMOUNT;
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(s1, 1, s2, size);
+ }
+
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_ecalloc */
+void * _mysqlnd_ecalloc(uint nmemb, size_t size MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_ecalloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
+
+ ret = ecalloc(nmemb, size);
+
+ DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
+ DBG_INF_FMT("size=%lu ptr=%p", size, ret);
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(STAT_MEM_ECALLOC_COUNT, 1, STAT_MEM_ECALLOC_AMMOUNT, size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_pecalloc */
+void * _mysqlnd_pecalloc(uint nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_pecalloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ if (persistent == FALSE) {
+ DBG_INF_FMT("before: %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+
+ ret = pecalloc(nmemb, size, persistent);
+ DBG_INF_FMT("size=%lu ptr=%p", size, ret);
+
+ if (persistent == FALSE) {
+ DBG_INF_FMT("after : %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+
+ if (MYSQLND_G(collect_memory_statistics)) {
+ enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_CALLOC_COUNT:STAT_MEM_ECALLOC_COUNT;
+ enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_CALLOC_AMMOUNT:STAT_MEM_ECALLOC_AMMOUNT;
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(s1, 1, s2, size);
+ }
+
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_erealloc */
+void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_erealloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("ptr=%p new_size=%lu", ptr, new_size);
+ DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
+
+ ret = erealloc(ptr, new_size);
+
+ DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
+ DBG_INF_FMT("new_ptr=%p", ret);
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(STAT_MEM_EREALLOC_COUNT, 1, STAT_MEM_EREALLOC_AMMOUNT, new_size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_perealloc */
+void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_perealloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("ptr=%p new_size=%lu persist=%d", ptr, new_size, persistent);
+ if (persistent == FALSE) {
+ DBG_INF_FMT("before: %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+
+ ret = perealloc(ptr, new_size, persistent);
+
+ DBG_INF_FMT("new_ptr=%p", ret);
+
+ if (persistent == FALSE) {
+ DBG_INF_FMT("after : %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+ MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_EREALLOC_COUNT:STAT_MEM_REALLOC_COUNT);
+ if (MYSQLND_G(collect_memory_statistics)) {
+ enum mysqlnd_collected_stats s1 = persistent? STAT_MEM_REALLOC_COUNT:STAT_MEM_EREALLOC_COUNT;
+ enum mysqlnd_collected_stats s2 = persistent? STAT_MEM_REALLOC_AMMOUNT:STAT_MEM_EREALLOC_AMMOUNT;
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(s1, 1, s2, new_size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_efree */
+void _mysqlnd_efree(void *ptr MYSQLND_MEM_D)
+{
+ DBG_ENTER(mysqlnd_efree_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("ptr=%p", ptr);
+ DBG_INF_FMT("before: %lu", zend_memory_usage(FALSE TSRMLS_CC));
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_MEM_EFREE_COUNT);
+
+ efree(ptr);
+
+ DBG_INF_FMT("after : %lu", zend_memory_usage(FALSE TSRMLS_CC));
+ DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_pefree */
+void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D)
+{
+ DBG_ENTER(mysqlnd_pefree_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("ptr=%p persistent=%d", ptr, persistent);
+ if (persistent == FALSE) {
+ DBG_INF_FMT("before: %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+
+ pefree(ptr, persistent);
+
+ if (persistent == FALSE) {
+ DBG_INF_FMT("after : %lu", zend_memory_usage(persistent TSRMLS_CC));
+ }
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC(persistent? STAT_MEM_FREE_COUNT:STAT_MEM_EFREE_COUNT);
+ }
+ DBG_VOID_RETURN;
+}
+
+
+/* {{{ _mysqlnd_malloc */
+void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_malloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+
+ ret = malloc(size);
+
+ DBG_INF_FMT("size=%lu ptr=%p", size, ret);
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(STAT_MEM_MALLOC_COUNT, 1, STAT_MEM_MALLOC_AMMOUNT, size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_calloc */
+void * _mysqlnd_calloc(uint nmemb, size_t size MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_calloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+
+ ret = calloc(nmemb, size);
+
+ DBG_INF_FMT("size=%lu ptr=%p", size, ret);
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(STAT_MEM_CALLOC_COUNT, 1, STAT_MEM_CALLOC_AMMOUNT, size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_realloc */
+void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D)
+{
+ void *ret;
+ DBG_ENTER(mysqlnd_realloc_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("ptr=%p new_size=%lu ", new_size, ptr);
+ DBG_INF_FMT("before: %lu", zend_memory_usage(TRUE TSRMLS_CC));
+
+ ret = realloc(ptr, new_size);
+
+ DBG_INF_FMT("new_ptr=%p", ret);
+
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(STAT_MEM_REALLOC_COUNT, 1, STAT_MEM_REALLOC_AMMOUNT, new_size);
+ }
+ DBG_RETURN(ret);
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_free */
+void _mysqlnd_free(void *ptr MYSQLND_MEM_D)
+{
+ DBG_ENTER(mysqlnd_free_name);
+ DBG_INF_FMT("file=%-15s line=%4d", strrchr(__zend_filename, PHP_DIR_SEPARATOR) + 1, __zend_lineno);
+ DBG_INF_FMT("ptr=%p", ptr);
+
+ free(ptr);
+
+ if (MYSQLND_G(collect_memory_statistics)) {
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_MEM_FREE_COUNT);
+ }
+ DBG_VOID_RETURN;
+}
+/* }}} */
+
+
+
+
+/* Follows code borrowed from zend_builtin_functions.c because the functions there are static */
+
+#if PHP_MAJOR_VERSION >= 6
+/* {{{ gettraceasstring() macros */
+#define TRACE_APPEND_CHR(chr) \
+ *str = (char*)erealloc(*str, *len + 1 + 1); \
+ (*str)[(*len)++] = chr
+
+#define TRACE_APPEND_STRL(val, vallen) \
+ { \
+ int l = vallen; \
+ *str = (char*)erealloc(*str, *len + l + 1); \
+ memcpy((*str) + *len, val, l); \
+ *len += l; \
+ }
+
+#define TRACE_APPEND_USTRL(val, vallen) \
+ { \
+ zval tmp, copy; \
+ int use_copy; \
+ ZVAL_UNICODEL(&tmp, val, vallen, 1); \
+ zend_make_printable_zval(&tmp, ©, &use_copy); \
+ TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+ zval_dtor(©); \
+ zval_dtor(&tmp); \
+ }
+
+#define TRACE_APPEND_ZVAL(zv) \
+ if (Z_TYPE_P((zv)) == IS_UNICODE) { \
+ zval copy; \
+ int use_copy; \
+ zend_make_printable_zval((zv), ©, &use_copy); \
+ TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+ zval_dtor(©); \
+ } else { \
+ TRACE_APPEND_STRL(Z_STRVAL_P((zv)), Z_STRLEN_P((zv))); \
+ }
+
+#define TRACE_APPEND_STR(val) \
+ TRACE_APPEND_STRL(val, sizeof(val)-1)
+
+#define TRACE_APPEND_KEY(key) \
+ if (zend_ascii_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
+ if (Z_TYPE_PP(tmp) == IS_UNICODE) { \
+ zval copy; \
+ int use_copy; \
+ zend_make_printable_zval(*tmp, ©, &use_copy); \
+ TRACE_APPEND_STRL(Z_STRVAL(copy), Z_STRLEN(copy)); \
+ zval_dtor(©); \
+ } else { \
+ TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
+ } \
+ }
+/* }}} */
+
+/* {{{ mysqlnd_build_trace_args */
+static int mysqlnd_build_trace_args(zval **arg, int num_args, va_list args, zend_hash_key *hash_key)
+{
+ char **str;
+ int *len;
+
+ str = va_arg(args, char**);
+ len = va_arg(args, int*);
+
+ /* the trivial way would be to do:
+ * conver_to_string_ex(arg);
+ * append it and kill the now tmp arg.
+ * but that could cause some E_NOTICE and also damn long lines.
+ */
+
+ switch (Z_TYPE_PP(arg)) {
+ case IS_NULL:
+ TRACE_APPEND_STR("NULL, ");
+ break;
+ case IS_STRING: {
+ int l_added;
+ TRACE_APPEND_CHR('\'');
+ if (Z_STRLEN_PP(arg) > 15) {
+ TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
+ TRACE_APPEND_STR("...', ");
+ l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+ } else {
+ l_added = Z_STRLEN_PP(arg);
+ TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
+ TRACE_APPEND_STR("', ");
+ l_added += 3 + 1;
+ }
+ while (--l_added) {
+ if ((unsigned char)(*str)[*len - l_added] < 32) {
+ (*str)[*len - l_added] = '?';
+ }
+ }
+ break;
+ }
+ case IS_UNICODE: {
+ int l_added;
+ TSRMLS_FETCH();
+
+ /*
+ * We do not want to apply current error mode here, since
+ * zend_make_printable_zval() uses output encoding converter.
+ * Temporarily set output encoding converter to escape offending
+ * chars with \uXXXX notation.
+ */
+ zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, ZEND_CONV_ERROR_ESCAPE_JAVA);
+ TRACE_APPEND_CHR('\'');
+ if (Z_USTRLEN_PP(arg) > 15) {
+ TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), 15);
+ TRACE_APPEND_STR("...', ");
+ l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+ } else {
+ l_added = Z_USTRLEN_PP(arg);
+ TRACE_APPEND_USTRL(Z_USTRVAL_PP(arg), l_added);
+ TRACE_APPEND_STR("', ");
+ l_added += 3 + 1;
+ }
+ /*
+ * Reset output encoding converter error mode.
+ */
+ zend_set_converter_error_mode(ZEND_U_CONVERTER(UG(output_encoding_conv)), ZEND_FROM_UNICODE, UG(from_error_mode));
+ while (--l_added) {
+ if ((unsigned char)(*str)[*len - l_added] < 32) {
+ (*str)[*len - l_added] = '?';
+ }
+ }
+ break;
+ }
+ case IS_BOOL:
+ if (Z_LVAL_PP(arg)) {
+ TRACE_APPEND_STR("true, ");
+ } else {
+ TRACE_APPEND_STR("false, ");
+ }
+ break;
+ case IS_RESOURCE:
+ TRACE_APPEND_STR("Resource id #");
+ /* break; */
+ case IS_LONG: {
+ long lval = Z_LVAL_PP(arg);
+ char s_tmp[MAX_LENGTH_OF_LONG + 1];
+ int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
+ TRACE_APPEND_STRL(s_tmp, l_tmp);
+ TRACE_APPEND_STR(", ");
+ break;
+ }
+ case IS_DOUBLE: {
+ double dval = Z_DVAL_PP(arg);
+ char *s_tmp;
+ int l_tmp;
+ TSRMLS_FETCH();
+
+ s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
+ l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
+ TRACE_APPEND_STRL(s_tmp, l_tmp);
+ /* %G already handles removing trailing zeros from the fractional part, yay */
+ efree(s_tmp);
+ TRACE_APPEND_STR(", ");
+ break;
+ }
+ case IS_ARRAY:
+ TRACE_APPEND_STR("Array, ");
+ break;
+ case IS_OBJECT: {
+ zstr class_name;
+ zend_uint class_name_len;
+ int dup;
+ TSRMLS_FETCH();
+
+ TRACE_APPEND_STR("Object(");
+
+ dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
+
+ if (UG(unicode)) {
+ zval tmp;
+
+ ZVAL_UNICODEL(&tmp, class_name.u, class_name_len, 1);
+ convert_to_string_with_converter(&tmp, ZEND_U_CONVERTER(UG(output_encoding_conv)));
+ TRACE_APPEND_STRL(Z_STRVAL(tmp), Z_STRLEN(tmp));
+ zval_dtor(&tmp);
+ } else {
+ TRACE_APPEND_STRL(class_name.s, class_name_len);
+ }
+ if(!dup) {
+ efree(class_name.v);
+ }
+
+ TRACE_APPEND_STR("), ");
+ break;
+ }
+ default:
+ break;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+
+static int mysqlnd_build_trace_string(zval **frame, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
+{
+ char *s_tmp, **str;
+ int *len, *num;
+ long line;
+ HashTable *ht = Z_ARRVAL_PP(frame);
+ zval **file, **tmp;
+
+ str = va_arg(args, char**);
+ len = va_arg(args, int*);
+ num = va_arg(args, int*);
+
+ s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
+ sprintf(s_tmp, "#%d ", (*num)++);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+ if (zend_ascii_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
+ if (zend_ascii_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
+ line = Z_LVAL_PP(tmp);
+ } else {
+ line = 0;
+ }
+ TRACE_APPEND_ZVAL(*file);
+ s_tmp = emalloc(MAX_LENGTH_OF_LONG + 2 + 1);
+ sprintf(s_tmp, "(%ld): ", line);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+ } else {
+ TRACE_APPEND_STR("[internal function]: ");
+ }
+ TRACE_APPEND_KEY("class");
+ TRACE_APPEND_KEY("type");
+ TRACE_APPEND_KEY("function");
+ TRACE_APPEND_CHR('(');
+ if (zend_ascii_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
+ int last_len = *len;
+ zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp), (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
+ if (last_len != *len) {
+ *len -= 2; /* remove last ', ' */
+ }
+ }
+ TRACE_APPEND_STR(")\n");
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+
+#else /* PHP 5*/
+
+
+/* {{{ gettraceasstring() macros */
+#define TRACE_APPEND_CHR(chr) \
+ *str = (char*)erealloc(*str, *len + 1 + 1); \
+ (*str)[(*len)++] = chr
+
+#define TRACE_APPEND_STRL(val, vallen) \
+ { \
+ int l = vallen; \
+ *str = (char*)erealloc(*str, *len + l + 1); \
+ memcpy((*str) + *len, val, l); \
+ *len += l; \
+ }
+
+#define TRACE_APPEND_STR(val) \
+ TRACE_APPEND_STRL(val, sizeof(val)-1)
+
+#define TRACE_APPEND_KEY(key) \
+ if (zend_hash_find(ht, key, sizeof(key), (void**)&tmp) == SUCCESS) { \
+ TRACE_APPEND_STRL(Z_STRVAL_PP(tmp), Z_STRLEN_PP(tmp)); \
+ }
+
+/* }}} */
+
+
+static int mysqlnd_build_trace_args(zval **arg, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
+{
+ char **str;
+ int *len;
+
+ str = va_arg(args, char**);
+ len = va_arg(args, int*);
+
+ /* the trivial way would be to do:
+ * conver_to_string_ex(arg);
+ * append it and kill the now tmp arg.
+ * but that could cause some E_NOTICE and also damn long lines.
+ */
+
+ switch (Z_TYPE_PP(arg)) {
+ case IS_NULL:
+ TRACE_APPEND_STR("NULL, ");
+ break;
+ case IS_STRING: {
+ int l_added;
+ TRACE_APPEND_CHR('\'');
+ if (Z_STRLEN_PP(arg) > 15) {
+ TRACE_APPEND_STRL(Z_STRVAL_PP(arg), 15);
+ TRACE_APPEND_STR("...', ");
+ l_added = 15 + 6 + 1; /* +1 because of while (--l_added) */
+ } else {
+ l_added = Z_STRLEN_PP(arg);
+ TRACE_APPEND_STRL(Z_STRVAL_PP(arg), l_added);
+ TRACE_APPEND_STR("', ");
+ l_added += 3 + 1;
+ }
+ while (--l_added) {
+ if ((*str)[*len - l_added] < 32) {
+ (*str)[*len - l_added] = '?';
+ }
+ }
+ break;
+ }
+ case IS_BOOL:
+ if (Z_LVAL_PP(arg)) {
+ TRACE_APPEND_STR("true, ");
+ } else {
+ TRACE_APPEND_STR("false, ");
+ }
+ break;
+ case IS_RESOURCE:
+ TRACE_APPEND_STR("Resource id #");
+ /* break; */
+ case IS_LONG: {
+ long lval = Z_LVAL_PP(arg);
+ char s_tmp[MAX_LENGTH_OF_LONG + 1];
+ int l_tmp = zend_sprintf(s_tmp, "%ld", lval); /* SAFE */
+ TRACE_APPEND_STRL(s_tmp, l_tmp);
+ TRACE_APPEND_STR(", ");
+ break;
+ }
+ case IS_DOUBLE: {
+ double dval = Z_DVAL_PP(arg);
+ char *s_tmp;
+ int l_tmp;
+ TSRMLS_FETCH();
+
+ s_tmp = emalloc(MAX_LENGTH_OF_DOUBLE + EG(precision) + 1);
+ l_tmp = zend_sprintf(s_tmp, "%.*G", (int) EG(precision), dval); /* SAFE */
+ TRACE_APPEND_STRL(s_tmp, l_tmp);
+ /* %G already handles removing trailing zeros from the fractional part, yay */
+ efree(s_tmp);
+ TRACE_APPEND_STR(", ");
+ break;
+ }
+ case IS_ARRAY:
+ TRACE_APPEND_STR("Array, ");
+ break;
+ case IS_OBJECT: {
+ char *class_name;
+ zend_uint class_name_len;
+ int dup;
+ TSRMLS_FETCH();
+
+ TRACE_APPEND_STR("Object(");
+
+ dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC);
+
+ TRACE_APPEND_STRL(class_name, class_name_len);
+ if(!dup) {
+ efree(class_name);
+ }
+
+ TRACE_APPEND_STR("), ");
+ break;
+ }
+ default:
+ break;
+ }
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+
+static int mysqlnd_build_trace_string(zval **frame, int num_args, va_list args, zend_hash_key *hash_key) /* {{{ */
+{
+ char *s_tmp, **str;
+ int *len, *num;
+ long line;
+ HashTable *ht = Z_ARRVAL_PP(frame);
+ zval **file, **tmp;
+
+ str = va_arg(args, char**);
+ len = va_arg(args, int*);
+ num = va_arg(args, int*);
+
+ s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 1 + 1);
+ sprintf(s_tmp, "#%d ", (*num)++);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+ if (zend_hash_find(ht, "file", sizeof("file"), (void**)&file) == SUCCESS) {
+ if (zend_hash_find(ht, "line", sizeof("line"), (void**)&tmp) == SUCCESS) {
+ line = Z_LVAL_PP(tmp);
+ } else {
+ line = 0;
+ }
+ s_tmp = emalloc(Z_STRLEN_PP(file) + MAX_LENGTH_OF_LONG + 4 + 1);
+ sprintf(s_tmp, "%s(%ld): ", Z_STRVAL_PP(file), line);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+ } else {
+ TRACE_APPEND_STR("[internal function]: ");
+ }
+ TRACE_APPEND_KEY("class");
+ TRACE_APPEND_KEY("type");
+ TRACE_APPEND_KEY("function");
+ TRACE_APPEND_CHR('(');
+ if (zend_hash_find(ht, "args", sizeof("args"), (void**)&tmp) == SUCCESS) {
+ int last_len = *len;
+ zend_hash_apply_with_arguments(Z_ARRVAL_PP(tmp), (apply_func_args_t)mysqlnd_build_trace_args, 2, str, len);
+ if (last_len != *len) {
+ *len -= 2; /* remove last ', ' */
+ }
+ }
+ TRACE_APPEND_STR(")\n");
+ return ZEND_HASH_APPLY_KEEP;
+}
+/* }}} */
+#endif
+
+
+char * mysqlnd_get_backtrace(TSRMLS_D)
+{
+ zval *trace;
+ char *res = estrdup(""), **str = &res, *s_tmp;
+ int res_len = 0, *len = &res_len, num = 0;
+
+ MAKE_STD_ZVAL(trace);
+ zend_fetch_debug_backtrace(trace, 0, 0 TSRMLS_CC);
+
+ zend_hash_apply_with_arguments(Z_ARRVAL_P(trace), (apply_func_args_t)mysqlnd_build_trace_string, 3, str, len, &num);
+ zval_ptr_dtor(&trace);
+
+ s_tmp = emalloc(1 + MAX_LENGTH_OF_LONG + 7 + 1);
+ sprintf(s_tmp, "#%d {main}", num);
+ TRACE_APPEND_STRL(s_tmp, strlen(s_tmp));
+ efree(s_tmp);
+
+ res[res_len] = '\0';
+
+ return res;
+}
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 6 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Georg Richter <georg@mysql.com> |
+ | Andrey Hristov <andrey@mysql.com> |
+ | Ulf Wendel <uwendel@mysql.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef MYSQLND_DEBUG_H
+#define MYSQLND_DEBUG_H
+
+#include "zend_stack.h"
+
+#define MYSQLND_DEBUG_MEMORY 1
+
+struct st_mysqlnd_debug_methods
+{
+ enum_func_status (*open)(MYSQLND_DEBUG *self, zend_bool reopen);
+ void (*set_mode)(MYSQLND_DEBUG *self, const char * const mode);
+ enum_func_status (*log)(MYSQLND_DEBUG *self, unsigned int line, const char * const file,
+ unsigned int level, const char * type, const char *message);
+ enum_func_status (*log_va)(MYSQLND_DEBUG *self, unsigned int line, const char * const file,
+ unsigned int level, const char * type, const char *format, ...);
+ zend_bool (*func_enter)(MYSQLND_DEBUG *self, unsigned int line, const char * const file,
+ char * func_name, size_t func_name_len);
+ enum_func_status (*func_leave)(MYSQLND_DEBUG *self, unsigned int line, const char * const file);
+ enum_func_status (*close)(MYSQLND_DEBUG *self);
+ enum_func_status (*free)(MYSQLND_DEBUG *self);
+};
+
+struct st_mysqlnd_debug
+{
+ php_stream *stream;
+#ifdef ZTS
+ TSRMLS_D;
+#endif
+ unsigned int flags;
+ unsigned int nest_level_limit;
+ int pid;
+ char * file_name;
+ zend_stack call_stack;
+ HashTable not_filtered_functions;
+ struct st_mysqlnd_debug_methods *m;
+};
+
+
+MYSQLND_DEBUG *mysqlnd_debug_init(TSRMLS_D);
+
+#define MYSQLND_MEM_D TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC
+
+
+void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D);
+void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D);
+void * _mysqlnd_ecalloc(uint nmemb, size_t size MYSQLND_MEM_D);
+void * _mysqlnd_pecalloc(uint nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D);
+void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D);
+void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D);
+void _mysqlnd_efree(void *ptr MYSQLND_MEM_D);
+void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D);
+void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D);
+void * _mysqlnd_calloc(uint nmemb, size_t size MYSQLND_MEM_D);
+void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D);
+void _mysqlnd_free(void *ptr MYSQLND_MEM_D);
+
+char * mysqlnd_get_backtrace(TSRMLS_D);
+
+#if PHP_DEBUG && !defined(PHP_WIN32)
+#define DBG_INF(msg) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "info : ", (msg)); } while (0)
+#define DBG_ERR(msg) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "error: ", (msg)); } while (0)
+#define DBG_INF_FMT(...) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log_va(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "info : ", __VA_ARGS__); } while (0)
+#define DBG_ERR_FMT(...) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log_va(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "error: ", __VA_ARGS__); } while (0)
+
+#define DBG_ENTER(func_name) zend_bool dbg_skip_trace = TRUE; if (MYSQLND_G(dbg)) dbg_skip_trace = !MYSQLND_G(dbg)->m->func_enter(MYSQLND_G(dbg), __LINE__, __FILE__, func_name, strlen(func_name));
+#define DBG_RETURN(value) do { if (MYSQLND_G(dbg)) MYSQLND_G(dbg)->m->func_leave(MYSQLND_G(dbg), __LINE__, __FILE__); return (value); } while (0)
+#define DBG_VOID_RETURN do { if (MYSQLND_G(dbg)) MYSQLND_G(dbg)->m->func_leave(MYSQLND_G(dbg), __LINE__, __FILE__); return; } while (0)
+
+
+
+#else
+#define DBG_INF(msg)
+#define DBG_ERR(msg)
+#define DBG_INF_FMT(...)
+#define DBG_ERR_FMT(...)
+
+#define DBG_ENTER(func_name)
+#define DBG_RETURN(value) return (value)
+#define DBG_VOID_RETURN return;
+
+#endif
+
+
+#if MYSQLND_DEBUG_MEMORY
+
+#define mnd_emalloc(size) _mysqlnd_emalloc((size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_pemalloc(size, pers) _mysqlnd_pemalloc((size), (pers) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_ecalloc(nmemb, size) _mysqlnd_ecalloc((nmemb), (size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_pecalloc(nmemb, size, p) _mysqlnd_pecalloc((nmemb), (size), (p) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_erealloc(ptr, new_size) _mysqlnd_erealloc((ptr), (new_size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_perealloc(ptr, new_size, p) _mysqlnd_perealloc((ptr), (new_size), (p) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_efree(ptr) _mysqlnd_efree((ptr) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_pefree(ptr, pers) _mysqlnd_pefree((ptr), (pers) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_malloc(size) _mysqlnd_malloc((size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_calloc(nmemb, size) _mysqlnd_calloc((nmemb), (size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_realloc(ptr, new_size) _mysqlnd_realloc((ptr), (new_size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+#define mnd_free(ptr) _mysqlnd_free((ptr) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
+
+#else
+
+#define mnd_emalloc(size) emalloc((size))
+#define mnd_pemalloc(size, pers) pemalloc((size), (pers))
+#define mnd_ecalloc(nmemb, size) ecalloc((nmemb), (size))
+#define mnd_pecalloc(nmemb, size, p) pecalloc((nmemb), (size), (p))
+#define mnd_erealloc(ptr, new_size) erealloc((ptr), (new_size))
+#define mnd_perealloc(ptr, new_size, p) perealloc((ptr), (new_size), (p))
+#define mnd_efree(ptr) efree((ptr))
+#define mnd_pefree(ptr, pers) pefree((ptr), (pers))
+#define mnd_malloc(size) malloc((size))
+#define mnd_calloc(nmemb, size) calloc((nmemb), (size))
+#define mnd_realloc(ptr, new_size) realloc((ptr), (new_size))
+#define mnd_free(ptr) free((ptr))
+
+#endif
+
+#endif /* MYSQLND_DEBUG_H */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ * vim600: noet sw=4 ts=4 fdm=marker
+ * vim<600: noet sw=4 ts=4
+ */
MYSQL_REPORT_DATA_TRUNCATION,
MYSQL_OPT_RECONNECT,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
+#if PHP_MAJOR_VERSION >= 6
MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE = 200,
+#endif
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
MYSQLND_OPT_INT_AND_YEAR_AS_INT = 201,
#endif
+ MYSQLND_OPT_NET_CMD_BUFFER_SIZE = 202,
+ MYSQLND_OPT_NET_READ_BUFFER_SIZE = 203,
} enum_mysqlnd_option;
/* see mysqlnd_charset.c for more information */
#define MYSQLND_BINARY_CHARSET_NR 63
+
+/*
+ /-----> CONN_CLOSE <---------------\
+ | ^ \
+ | | \
+ CONN_READY -> CONN_QUERY_SENT -> CONN_FETCHING_DATA
+ ^ |
+ \-------------------------------------/
+*/
+typedef enum mysqlnd_connection_state
+{
+ CONN_ALLOCED = 0,
+ CONN_READY,
+ CONN_QUERY_SENT,
+ CONN_SENDING_LOAD_DATA,
+ CONN_FETCHING_DATA,
+ CONN_NEXT_RESULT_PENDING,
+ CONN_QUIT_SENT, /* object is "destroyed" at this stage */
+} enum_mysqlnd_connection_state;
+
+
+typedef enum mysqlnd_stmt_state
+{
+ MYSQLND_STMT_INITTED = 0,
+ MYSQLND_STMT_PREPARED,
+ MYSQLND_STMT_EXECUTED,
+ MYSQLND_STMT_WAITING_USE_OR_STORE,
+ MYSQLND_STMT_USE_OR_STORE_CALLED,
+ MYSQLND_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */
+} enum_mysqlnd_stmt_state;
+
+
+typedef enum param_bind_flags
+{
+ MYSQLND_PARAM_BIND_BLOB_USED = 1
+} enum_param_bind_flags;
+
+
+/* PS */
+enum mysqlnd_stmt_attr
+{
+ STMT_ATTR_UPDATE_MAX_LENGTH,
+ STMT_ATTR_CURSOR_TYPE,
+ STMT_ATTR_PREFETCH_ROWS
+};
+
+enum myslqnd_cursor_type
+{
+ CURSOR_TYPE_NO_CURSOR= 0,
+ CURSOR_TYPE_READ_ONLY= 1,
+ CURSOR_TYPE_FOR_UPDATE= 2,
+ CURSOR_TYPE_SCROLLABLE= 4
+};
+
+typedef enum mysqlnd_connection_close_type
+{
+ MYSQLND_CLOSE_EXPLICIT = 0,
+ MYSQLND_CLOSE_IMPLICIT,
+ MYSQLND_CLOSE_DISCONNECTED,
+ MYSQLND_CLOSE_LAST /* for checking, should always be last */
+} enum_connection_close_type;
+
+typedef enum mysqlnd_collected_stats
+{
+ STAT_BYTES_SENT,
+ STAT_BYTES_RECEIVED,
+ STAT_PACKETS_SENT,
+ STAT_PACKETS_RECEIVED,
+ STAT_PROTOCOL_OVERHEAD_IN,
+ STAT_PROTOCOL_OVERHEAD_OUT,
+ STAT_RSET_QUERY,
+ STAT_NON_RSET_QUERY,
+ STAT_NO_INDEX_USED,
+ STAT_BAD_INDEX_USED,
+ STAT_BUFFERED_SETS,
+ STAT_UNBUFFERED_SETS,
+ STAT_PS_BUFFERED_SETS,
+ STAT_PS_UNBUFFERED_SETS,
+ STAT_FLUSHED_NORMAL_SETS,
+ STAT_FLUSHED_PS_SETS,
+ STAT_PS_PREPARED_NEVER_EXECUTED,
+ STAT_PS_PREPARED_ONCE_USED,
+ STAT_ROWS_FETCHED_FROM_SERVER_NORMAL,
+ STAT_ROWS_FETCHED_FROM_SERVER_PS,
+ STAT_ROWS_BUFFERED_FROM_CLIENT_NORMAL,
+ STAT_ROWS_BUFFERED_FROM_CLIENT_PS,
+ STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF,
+ STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF,
+ STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF,
+ STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF,
+ STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR,
+ STAT_ROWS_SKIPPED_NORMAL,
+ STAT_ROWS_SKIPPED_PS,
+ STAT_COPY_ON_WRITE_SAVED,
+ STAT_COPY_ON_WRITE_PERFORMED,
+ STAT_CMD_BUFFER_TOO_SMALL,
+ STAT_CONNECT_SUCCESS,
+ STAT_CONNECT_FAILURE,
+ STAT_CONNECT_REUSED,
+ STAT_RECONNECT,
+ STAT_PCONNECT_SUCCESS,
+ STAT_OPENED_CONNECTIONS,
+ STAT_OPENED_PERSISTENT_CONNECTIONS,
+ STAT_CLOSE_EXPLICIT,
+ STAT_CLOSE_IMPLICIT,
+ STAT_CLOSE_DISCONNECT,
+ STAT_CLOSE_IN_MIDDLE,
+ STAT_FREE_RESULT_EXPLICIT,
+ STAT_FREE_RESULT_IMPLICIT,
+ STAT_STMT_CLOSE_EXPLICIT,
+ STAT_STMT_CLOSE_IMPLICIT,
+ STAT_MEM_EMALLOC_COUNT,
+ STAT_MEM_EMALLOC_AMMOUNT,
+ STAT_MEM_ECALLOC_COUNT,
+ STAT_MEM_ECALLOC_AMMOUNT,
+ STAT_MEM_EREALLOC_COUNT,
+ STAT_MEM_EREALLOC_AMMOUNT,
+ STAT_MEM_EFREE_COUNT,
+ STAT_MEM_MALLOC_COUNT,
+ STAT_MEM_MALLOC_AMMOUNT,
+ STAT_MEM_CALLOC_COUNT,
+ STAT_MEM_CALLOC_AMMOUNT,
+ STAT_MEM_REALLOC_COUNT,
+ STAT_MEM_REALLOC_AMMOUNT,
+ STAT_MEM_FREE_COUNT,
+ STAT_LAST /* Should be always the last */
+} enum_mysqlnd_collected_stats;
+
+
+#define MYSQLND_DEFAULT_PREFETCH_ROWS (ulong) 1
+
+
#endif /* MYSQLND_ENUM_N_DEF_H */
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
+#include "mysqlnd_debug.h"
enum_func_status mysqlnd_simple_command_handle_response(MYSQLND *conn,
enum php_mysql_packet_type ok_packet,
if (c) {\
a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\
for (i = b; i < c; i++) {\
- a[i] = emalloc(sizeof(zval *));\
+ a[i] = mnd_emalloc(sizeof(zval *));\
MAKE_STD_ZVAL(*a[i]);\
}\
}
if (a) {\
for (i=b; i < c; i++) {\
zval_ptr_dtor(a[i]);\
- efree(a[i]);\
+ mnd_efree(a[i]);\
}\
- efree(a);\
+ mnd_efree(a);\
}
/* {{{ mysqlnd_local_infile_init */
MYSQLND_INFILE_INFO *info;
php_stream_context *context = NULL;
- *ptr= info= ((MYSQLND_INFILE_INFO *)ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
+ DBG_ENTER("mysqlnd_local_infile_init");
+
+ *ptr= info= ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
/* check open_basedir */
if (PG(open_basedir)) {
if (php_check_open_basedir_ex(filename, 0 TSRMLS_CC) == -1) {
strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
info->error_no = CR_UNKNOWN_ERROR;
- return 1;
+ DBG_RETURN(1);
}
}
if (info->fd == NULL) {
snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
info->error_no = MYSQLND_EE_FILENOTFOUND;
- return 1;
+ DBG_RETURN(1);
}
- return 0;
+ DBG_RETURN(0);
}
/* }}} */
MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
int count;
- /* default processing */
- if (!info->callback) {
- count = (int)php_stream_read(info->fd, buf, buf_len);
+ DBG_ENTER("mysqlnd_local_infile_read");
- if (count < 0) {
- strcpy(info->error_msg, "Error reading file");
- info->error_no = MYSQLND_EE_READ;
- }
-
- return count;
- } else {
- zval ***callback_args;
- zval *retval;
- zval *fp;
- int argc = 4;
- int i;
- long rc;
-
- ALLOC_CALLBACK_ARGS(callback_args, 1, argc);
-
- /* set parameters: filepointer, buffer, buffer_len, errormsg */
-
- MAKE_STD_ZVAL(fp);
- php_stream_to_zval(info->fd, fp);
- callback_args[0] = &fp;
- ZVAL_STRING(*callback_args[1], "", 1);
- ZVAL_LONG(*callback_args[2], buf_len);
- ZVAL_STRING(*callback_args[3], "", 1);
-
- if (call_user_function_ex(EG(function_table),
- NULL,
- info->callback,
- &retval,
- argc,
- callback_args,
- 0,
- NULL TSRMLS_CC) == SUCCESS) {
-
- rc = Z_LVAL_P(retval);
- zval_ptr_dtor(&retval);
-
- if (rc > 0) {
- const char * msg = NULL;
- if (rc >= 0 && rc != Z_STRLEN_P(*callback_args[1])) {
- msg = "Mismatch between the return value of the callback and the content "
- "length of the buffer.";
- php_error_docref(NULL TSRMLS_CC, E_WARNING, msg);
- rc = -1;
- } else if (Z_STRLEN_P(*callback_args[1]) > buf_len) {
- /* check buffer overflow */
- msg = "Too much data returned";
- rc = -1;
- } else {
- memcpy(buf, Z_STRVAL_P(*callback_args[1]), MIN(rc, Z_STRLEN_P(*callback_args[1])));
- }
- if (rc == -1) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, msg);
- strcpy(info->error_msg, msg);
- info->error_no = MYSQLND_EE_READ;
- }
- } else if (rc < 0) {
- strncpy(info->error_msg, Z_STRVAL_P(*callback_args[3]), MYSQLND_ERRMSG_SIZE);
- info->error_no = MYSQLND_EE_READ;
- }
- } else {
- strcpy(info->error_msg, "Can't execute load data local init callback function");
- info->error_no = MYSQLND_EE_READ;
- rc = -1;
- }
-
- efree(fp);
- FREE_CALLBACK_ARGS(callback_args, 1, argc);
- return rc;
+ count = (int)php_stream_read(info->fd, buf, buf_len);
+ if (count < 0) {
+ strcpy(info->error_msg, "Error reading file");
+ info->error_no = CR_UNKNOWN_ERROR;
}
+
+ DBG_RETURN(count);
}
/* }}} */
{
MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
+ DBG_ENTER("mysqlnd_local_infile_error");
+
if (info) {
strncpy(error_buf, info->error_msg, error_buf_len);
-
- return info->error_no;
+ DBG_INF_FMT("have info, %d", info->error_no);
+ DBG_RETURN(info->error_no);
}
strncpy(error_buf, "Unknown error", error_buf_len);
- return CR_UNKNOWN_ERROR;
+ DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
+ DBG_RETURN(CR_UNKNOWN_ERROR);
}
/* }}} */
/* php_stream_close segfaults on NULL */
if (info->fd) {
php_stream_close(info->fd);
+ info->fd = NULL;
}
- efree(info);
+ mnd_efree(info);
}
}
/* }}} */
/* {{{ mysqlnd_local_infile_default */
-PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn, zend_bool free_callback)
+PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn)
{
conn->infile.local_infile_init = mysqlnd_local_infile_init;
conn->infile.local_infile_read = mysqlnd_local_infile_read;
conn->infile.local_infile_error = mysqlnd_local_infile_error;
conn->infile.local_infile_end = mysqlnd_local_infile_end;
- conn->infile.userdata = NULL;
- if (free_callback == TRUE && conn->infile.callback) {
- zval_ptr_dtor(&conn->infile.callback);
- conn->infile.callback = NULL;
- }
}
/* }}} */
size_t ret;
MYSQLND_INFILE infile;
+ DBG_ENTER("mysqlnd_handle_local_infile");
+
if (!(conn->options.flags & CLIENT_LOCAL_FILES)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "LOAD DATA LOCAL INFILE forbidden");
/* write empty packet to server */
goto infile_error;
}
- /* check if we have valid functions */
- if (!conn->infile.local_infile_init || !conn->infile.local_infile_read ||
- !conn->infile.local_infile_error || !conn->infile.local_infile_end) {
- mysqlnd_local_infile_default(conn, FALSE);
- }
-
infile = conn->infile;
/* allocate buffer for reading data */
- buf = (char *)ecalloc(1, buflen);
+ buf = (char *)mnd_ecalloc(1, buflen);
*is_warning = FALSE;
goto infile_error;
}
- /* pass callback handler */
- if (infile.callback) {
- MYSQLND_INFILE_INFO *ptr = (MYSQLND_INFILE_INFO *)info;
- ptr->callback = infile.callback;
- }
-
-
/* read data */
while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE,
buflen - MYSQLND_HEADER_SIZE TSRMLS_CC)) > 0) {
if ((ret = mysqlnd_stream_write_w_header(conn, buf, bufsize TSRMLS_CC)) < 0) {
+ DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
goto infile_error;
}
/* error during read occured */
if (bufsize < 0) {
*is_warning = TRUE;
+ DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
conn->error_info.error_no = infile.local_infile_error(info, conn->error_info.error,
sizeof(conn->error_info.error) TSRMLS_CC);
}
(*conn->infile.local_infile_end)(info TSRMLS_CC);
- efree(buf);
- return result;
+ mnd_efree(buf);
+ DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
+ DBG_RETURN(result);
}
/* }}} */
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_palloc.h"
+#include "mysqlnd_debug.h"
-#define MYSQLND_SILENT
+/* Used in mysqlnd_debug.c */
+char * mysqlnd_palloc_zval_ptr_dtor_name = "mysqlnd_palloc_zval_ptr_dtor";
+char * mysqlnd_palloc_get_zval_name = "mysqlnd_palloc_get_zval";
#ifdef ZTS
#endif
-/* {{{ mysqlnd_palloc_init_cache */
-PHPAPI MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_init_cache(unsigned int cache_size)
+/* {{{ _mysqlnd_palloc_init_cache */
+PHPAPI MYSQLND_ZVAL_PCACHE* _mysqlnd_palloc_init_cache(unsigned int cache_size TSRMLS_DC)
{
MYSQLND_ZVAL_PCACHE *ret = calloc(1, sizeof(MYSQLND_ZVAL_PCACHE));
unsigned int i;
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_init_cache %p]\n", ret);
-#endif
+
+ DBG_ENTER("_mysqlnd_palloc_init_cache");
+ DBG_INF_FMT("cache=%p size=%u", ret, cache_size);
#ifdef ZTS
ret->LOCK_access = tsrm_mutex_alloc();
/* 2. Add to the free list */
*(--ret->free_list.last_added) = &(ret->block[i]);
}
-
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
to the free list after usage. We ZVAL_NULL() them when we allocate them in the
constructor of the cache.
*/
-void mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache)
+void _mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache TSRMLS_DC)
{
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_free_cache %p]\n", cache);
-#endif
+ DBG_ENTER("_mysqlnd_palloc_free_cache");
+ DBG_INF_FMT("cache=%p", cache);
#ifdef ZTS
tsrm_mutex_free(cache->LOCK_access);
#endif
/* Data in pointed by 'block' was cleaned in RSHUTDOWN */
- free(cache->block);
- free(cache->free_list.ptr_line);
- free(cache);
+ mnd_free(cache->block);
+ mnd_free(cache->free_list.ptr_line);
+ mnd_free(cache);
+
+ DBG_VOID_RETURN;
}
/* }}} */
-/* {{{ mysqlnd_palloc_init_thd_cache */
-PHPAPI MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache)
+/* {{{ _mysqlnd_palloc_init_thd_cache */
+PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC)
{
MYSQLND_THD_ZVAL_PCACHE *ret = calloc(1, sizeof(MYSQLND_THD_ZVAL_PCACHE));
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_init_thd_cache %p]\n", ret);
-#endif
+ DBG_ENTER("_mysqlnd_palloc_init_thd_cache");
+ DBG_INF_FMT("ret = %p", ret);
+
ret->parent = mysqlnd_palloc_get_cache_reference(cache);
#ifdef ZTS
/* Backward and forward looping is possible */
ret->gc_list.last_added = ret->gc_list.ptr_line;
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
constructor of the cache.
*/
static
-void mysqlnd_palloc_free_thd_cache(MYSQLND_THD_ZVAL_PCACHE *cache)
+void mysqlnd_palloc_free_thd_cache(MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC)
{
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_free_thd_cache %p]\n", cache);
-#endif
+ DBG_ENTER("mysqlnd_palloc_free_thd_cache");
+ DBG_INF_FMT("cache=%p", cache);
- free(cache->gc_list.ptr_line);
- free(cache);
+ mnd_free(cache->gc_list.ptr_line);
+ mnd_free(cache);
+
+ DBG_VOID_RETURN;
}
/* }}} */
-/* {{{ mysqlnd_palloc_free_thd_cache_reference */
-PHPAPI void mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache)
+/* {{{ _mysqlnd_palloc_free_thd_cache_reference */
+PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC)
{
+ DBG_ENTER("_mysqlnd_palloc_free_thd_cache_reference");
if (*cache) {
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_free_thd_cache_reference %p] refs=%d\n", *cache, (*cache)->references);
-#endif
+ DBG_INF_FMT("cache=%p refs=%d", *cache, (*cache)->references);
--(*cache)->parent->references;
if (--(*cache)->references == 0) {
- mysqlnd_palloc_free_thd_cache(*cache);
+ mysqlnd_palloc_free_thd_cache(*cache TSRMLS_CC);
}
*cache = NULL;
}
+ DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_palloc_get_zval */
-void *mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const thd_cache, zend_bool *allocated)
+void *mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const thd_cache, zend_bool *allocated TSRMLS_DC)
{
void *ret = NULL;
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_get_zval %p] *last_added=%p free_items=%d\n",
+ DBG_ENTER("mysqlnd_palloc_get_zval");
+ DBG_INF_FMT("cache=%p *last_added=%p free_items=%d",
thd_cache, thd_cache? thd_cache->parent->free_list.last_added:NULL,
thd_cache->parent->free_items);
-#endif
if (thd_cache) {
MYSQLND_ZVAL_PCACHE *cache = thd_cache->parent;
ZVAL_ADDREF(&(((mysqlnd_zval *)ret)->zv));
}
- return ret;
+ DBG_INF_FMT("allocated=%d ret=%p", *allocated, ret);
+ DBG_RETURN(ret);
}
/* }}} */
enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC)
{
MYSQLND_ZVAL_PCACHE *cache;
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] parent_block=%p last_in_block=%p *zv=%p type=%d refc=%d\n",
+ DBG_ENTER("mysqlnd_palloc_zval_ptr_dtor");
+ DBG_INF_FMT("cache=%p parent_block=%p last_in_block=%p *zv=%p refc=%d type=%d ",
thd_cache,
thd_cache->parent? thd_cache->parent->block:NULL,
thd_cache->parent? thd_cache->parent->last_in_block:NULL,
- *zv, type, ZVAL_REFCOUNT(*zv));
-#endif
+ *zv, ZVAL_REFCOUNT(*zv), type);
*copy_ctor_called = FALSE;
/* Check whether cache is used and the zval is from the cache */
if (!thd_cache || !(cache = thd_cache->parent) || ((char *)*zv < (char *)thd_cache->parent->block ||
}
}
zval_ptr_dtor(zv);
- return;
+ DBG_VOID_RETURN;
}
/* The zval is from our cache */
UNLOCK_PCACHE(cache);
}
+ DBG_VOID_RETURN;
}
/* }}} */
-/* {{{ mysqlnd_palloc_rinit */
-PHPAPI MYSQLND_THD_ZVAL_PCACHE * mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache)
+/* {{{ _mysqlnd_palloc_rinit */
+PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache TSRMLS_DC)
{
return mysqlnd_palloc_init_thd_cache(cache);
}
/* }}} */
-/* {{{ mysqlnd_palloc_rshutdown */
-PHPAPI void mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache)
+/* {{{ _mysqlnd_palloc_rshutdown */
+PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS_DC)
{
MYSQLND_ZVAL_PCACHE *cache;
mysqlnd_zval **p;
-#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_rshutdown %p]\n", thd_cache);
-#endif
+
+ DBG_ENTER("_mysqlnd_palloc_rshutdown");
+ DBG_INF_FMT("cache=%p", thd_cache);
+
if (!thd_cache || !(cache = thd_cache->parent)) {
return;
}
UNLOCK_PCACHE(cache);
mysqlnd_palloc_free_thd_cache_reference(&thd_cache);
+
+ DBG_VOID_RETURN;
}
/* }}} */
#ifndef MYSQLND_PALLOC_H
#define MYSQLND_PALLOC_H
+/* Used in mysqlnd_debug.c */
+extern char * mysqlnd_palloc_zval_ptr_dtor_name;
+extern char * mysqlnd_palloc_get_zval_name;
+
+
/* Session caching allocator */
struct st_mysqlnd_zval_list {
zval **ptr_line;
#define CR_INVALID_PARAMETER_NO 2034
#define CR_INVALID_BUFFER_USE 2035
-#define MYSQLND_EE_READ 2
-#define MYSQLND_EE_FILENOTFOUND 29
+#define MYSQLND_EE_FILENOTFOUND 7890
#define UNKNOWN_SQLSTATE "HY000"
extern struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
extern const char * mysqlnd_out_of_sync;
+extern const char * mysqlnd_server_gone;
enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC);
void _mysqlnd_init_ps_subsystem();/* This one is private, mysqlnd_library_init() will call it */
-void mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uchar **p,
- size_t *buf_len, unsigned int null_byte_offset);
-
void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row, zend_bool as_unicode,
unsigned int byte_count TSRMLS_DC);
#include "mysqlnd_result.h"
#include "mysqlnd_result_meta.h"
#include "mysqlnd_statistics.h"
+#include "mysqlnd_debug.h"
#define MYSQLND_SILENT
/* Exported by mysqlnd_ps_codec.c */
zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
- zend_bool *free_buffer);
+ zend_bool *free_buffer TSRMLS_DC);
MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC);
unsigned int flags,
zend_bool *fetched_anything TSRMLS_DC);
-void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
+void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
/* {{{ mysqlnd_stmt::store_result */
MYSQLND_RES *result;
zend_bool to_cache = FALSE;
+ DBG_ENTER("mysqlnd_stmt::store_result");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
/* be compliant with libmysql - NULL will turn */
if (!stmt->field_count) {
- return NULL;
+ DBG_RETURN(NULL);
}
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
- return stmt->m->use_result(stmt TSRMLS_CC);
+ MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC);
+ DBG_RETURN(res);
}
-
/* Nothing to store for UPSERT/LOAD DATA*/
if (conn->state != CONN_FETCHING_DATA ||
stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
{
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return NULL;
+ DBG_RETURN(NULL);
}
stmt->default_rset_handler = stmt->m->store_result;
} else {
conn->error_info = result->data->error_info;
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
- efree(stmt->result);
+ mnd_efree(stmt->result);
stmt->result = NULL;
stmt->state = MYSQLND_STMT_PREPARED;
}
- return result;
+ DBG_RETURN(result);
}
/* }}} */
MYSQLND *conn = stmt->conn;
MYSQLND_RES *result;
+ DBG_ENTER("mysqlnd_stmt::get_result");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
/* be compliant with libmysql - NULL will turn */
if (!stmt->field_count) {
- return NULL;
+ DBG_RETURN(NULL);
}
if (stmt->cursor_exists) {
/* Silently convert buffered to unbuffered, for now */
- return stmt->m->use_result(stmt TSRMLS_CC);
+ MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC);
+ DBG_RETURN(res);
}
/* Nothing to store for UPSERT/LOAD DATA*/
- if (conn->state != CONN_FETCHING_DATA ||
- stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
- {
+ if (conn->state != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return NULL;
+ DBG_RETURN(NULL);
}
SET_EMPTY_ERROR(stmt->error_info);
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BUFFERED_SETS);
result = mysqlnd_result_init(stmt->result->field_count,
- mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache));
+ mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache) TSRMLS_CC);
- result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE);
+ result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
/* Not set for SHOW statements at PREPARE stage */
if (stmt->result->conn) {
stmt->state = MYSQLND_STMT_PREPARED;
}
- return result;
+ DBG_RETURN(result);
}
/* }}} */
unsigned int i = 0;
php_mysql_packet_res_field field_packet;
+ DBG_ENTER("mysqlnd_stmt_skip_metadata");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
PACKET_INIT_ALLOCA(field_packet, PROT_RSET_FLD_PACKET);
field_packet.skip_parsing = TRUE;
for (;i < stmt->param_count; i++) {
if (FAIL == PACKET_READ_ALLOCA(field_packet, stmt->conn)) {
PACKET_FREE_ALLOCA(field_packet);
- return FAIL;
+ DBG_RETURN(FAIL);
}
}
PACKET_FREE_ALLOCA(field_packet);
- return PASS;
+
+ DBG_RETURN(PASS);
}
/* }}} */
{
php_mysql_packet_prepare_response prepare_resp;
+ DBG_ENTER("mysqlnd_stmt_read_prepare_response");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
PACKET_INIT_ALLOCA(prepare_resp, PROT_PREPARE_RESP_PACKET);
if (FAIL == PACKET_READ_ALLOCA(prepare_resp, stmt->conn)) {
PACKET_FREE_ALLOCA(prepare_resp);
stmt->param_count = prepare_resp.param_count;
PACKET_FREE_ALLOCA(prepare_resp);
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
php_mysql_packet_eof fields_eof;
enum_func_status ret;
+ DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
PACKET_INIT_ALLOCA(fields_eof, PROT_EOF_PACKET);
if (FAIL == (ret = PACKET_READ_ALLOCA(fields_eof, stmt->conn))) {
if (stmt->result) {
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
- efree(stmt->result);
+ mnd_efree(stmt->result);
memset(stmt, 0, sizeof(MYSQLND_STMT));
stmt->state = MYSQLND_STMT_INITTED;
}
}
PACKET_FREE_ALLOCA(fields_eof);
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
{
MYSQLND_STMT *stmt_to_prepare = stmt;
+ DBG_ENTER("mysqlnd_stmt::prepare");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
SET_ERROR_AFF_ROWS(stmt);
SET_ERROR_AFF_ROWS(stmt->conn);
no metadata at prepare.
*/
if (stmt_to_prepare->field_count) {
- MYSQLND_RES *result = mysqlnd_result_init(stmt_to_prepare->field_count, NULL);
+ MYSQLND_RES *result = mysqlnd_result_init(stmt_to_prepare->field_count, NULL TSRMLS_CC);
/* Allocate the result now as it is needed for the reading of metadata */
stmt_to_prepare->result = result;
memcpy(stmt, stmt_to_prepare, sizeof(MYSQLND_STMT));
/* Now we will have a clean new statement object */
- efree(stmt_to_prepare);
+ mnd_efree(stmt_to_prepare);
}
stmt->state = MYSQLND_STMT_PREPARED;
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
fail:
if (stmt_to_prepare != stmt) {
}
stmt->state = MYSQLND_STMT_INITTED;
- return FAIL;
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
}
/* }}} */
size_t request_len;
zend_bool free_request;
+ DBG_ENTER("mysqlnd_stmt::execute");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
SET_ERROR_AFF_ROWS(stmt);
SET_ERROR_AFF_ROWS(stmt->conn);
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
mysqlnd_out_of_sync);
SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return FAIL;
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
}
if (stmt->param_count && !stmt->param_bind) {
SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
"No data supplied for parameters in prepared statement");
- return FAIL;
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
}
- request = mysqlnd_stmt_execute_generate_request(stmt, &request_len, &free_request);
+ request = mysqlnd_stmt_execute_generate_request(stmt, &request_len, &free_request TSRMLS_CC);
/* support for buffer types should be added here ! */
FALSE TSRMLS_CC);
if (free_request) {
- efree(request);
+ mnd_efree(request);
}
if (ret == FAIL) {
stmt->error_info = conn->error_info;
- return FAIL;
+ DBG_INF("FAIL");
+ DBG_RETURN(FAIL);
}
+ stmt->execute_count++;
ret = mysqlnd_query_read_result_set_header(stmt->conn, stmt TSRMLS_CC);
if (ret == FAIL) {
stmt->state = MYSQLND_STMT_EXECUTED;
if (conn->last_query_type == QUERY_UPSERT) {
stmt->upsert_status = conn->upsert_status;
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
} else if (conn->last_query_type == QUERY_LOAD_LOCAL) {
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
}
stmt->result->type = MYSQLND_RES_PS_BUF;
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.
*/
-#ifndef MYSQLND_SILENT
- php_printf("server_status=%d cursor=%d\n", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
-#endif
+ DBG_INF_FMT("server_status=%d cursor=%d\n", 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->state = 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
*/
/* 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");
}
}
}
- return ret;
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
unsigned int i;
MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
+ DBG_ENTER("mysqlnd_fetch_stmt_row_buffered");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
/* If we haven't read everything */
if (result->data->data_cursor &&
(result->data->data_cursor - result->data->data) < result->data->row_count)
#endif
/* copy the type */
if (stmt->result_bind[i].bound == TRUE) {
+ DBG_INF_FMT("i=%d type=%d", i, Z_TYPE_P(current_row[i]));
if (Z_TYPE_P(current_row[i]) != IS_NULL) {
/*
Copy the value.
}
result->data->data_cursor++;
*fetched_anything = TRUE;
+ /* buffered result sets don't have a connection */
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
+ DBG_INF("row fetched");
} else {
result->data->data_cursor = NULL;
*fetched_anything = FALSE;
-#ifndef MYSQLND_SILENT
- php_printf("NO MORE DATA\n ");
-#endif
+ DBG_INF("no more data");
}
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_stmt_fetch_row_unbuffered */
-enum_func_status
+static enum_func_status
mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flags,
zend_bool *fetched_anything TSRMLS_DC)
{
unsigned int i, field_count = result->field_count;
php_mysql_packet_row *row_packet = result->row_packet;
+ DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
+
if (result->unbuf->eof_reached) {
/* No more rows obviously */
*fetched_anything = FALSE;
- return PASS;
+ DBG_INF("eof reached");
+ DBG_RETURN(PASS);
}
if (result->conn->state != CONN_FETCHING_DATA) {
SET_CLIENT_ERROR(result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
- UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return FAIL;
+ UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
+ DBG_ERR("command out of sync");
+ DBG_RETURN(FAIL);
}
/* Let the row packet fill our buffer and skip additional malloc + memcpy */
row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
if (!row_packet->skip_extraction) {
mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
+ DBG_INF("extracting data");
result->unbuf->last_row_data = row_packet->fields;
result->unbuf->last_row_buffer = row_packet->row_buffer;
row_packet->fields = NULL;
}
}
}
+ MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF);
} else {
+ DBG_INF("skipping extraction");
/*
Data has been allocated and usually mysqlnd_unbuffered_free_last_data()
frees it but we can't call this function as it will cause problems with
the bound variables. Thus we need to do part of what it does or Zend will
report leaks.
*/
- efree(row_packet->row_buffer);
+ mnd_efree(row_packet->row_buffer);
row_packet->row_buffer = NULL;
}
} else if (ret == FAIL) {
result->conn->state = CONN_READY;
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
} else if (row_packet->eof) {
+ DBG_INF("EOF");
/* Mark the connection as usable again */
result->unbuf->eof_reached = TRUE;
result->conn->upsert_status.warning_count = row_packet->warning_count;
*fetched_anything = FALSE;
}
- return ret;
+ DBG_INF_FMT("ret=%s fetched_anything=%d", ret == PASS? "PASS":"FAIL", *fetched_anything);
+ DBG_RETURN(ret);
}
/* }}} */
/* {{{ mysqlnd_stmt::use_result */
-MYSQLND_RES *
+static MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT *stmt TSRMLS_DC)
{
MYSQLND_RES *result;
MYSQLND *conn = stmt->conn;
+ DBG_ENTER("mysqlnd_stmt::use_result");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
if (!stmt->field_count ||
(!stmt->cursor_exists && conn->state != CONN_FETCHING_DATA) ||
(stmt->cursor_exists && conn->state != CONN_READY) ||
(stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
{
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
- UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return NULL;
+ UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
+ DBG_ERR("command out of sync");
+ DBG_RETURN(NULL);
}
SET_EMPTY_ERROR(stmt->error_info);
MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);
result = stmt->result;
- result->type = MYSQLND_RES_PS_UNBUF;
+ result->type = MYSQLND_RES_PS_UNBUF;
result->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
mysqlnd_stmt_fetch_row_unbuffered;
result->m.fetch_lengths = NULL; /* makes no sense */
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
- result->unbuf = ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ DBG_INF_FMT("cursor=%d zval_cache=%p", stmt->cursor_exists, result->zval_cache);
/*
Will be freed in the mysqlnd_internal_free_result_contents() called
by the resource destructor. mysqlnd_fetch_row_unbuffered() expects
/* No multithreading issues as we don't share the connection :) */
- return result;
+ DBG_INF_FMT("%p", result);
+ DBG_RETURN(result);
}
/* }}} */
zend_uchar buf[STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
php_mysql_packet_row *row_packet = result->row_packet;
+ DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
+ DBG_INF_FMT("stmt=%lu flags=%u", stmt->stmt_id, flags);
+
if (!stmt) {
- return FAIL;
+ DBG_ERR("no statement");
+ DBG_RETURN(FAIL);
}
if (stmt->state < MYSQLND_STMT_USER_FETCHING) {
/* Only initted - error */
SET_CLIENT_ERROR(stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
mysqlnd_out_of_sync);
- return FAIL;
+ DBG_ERR("command out of sync");
+ DBG_RETURN(FAIL);
}
SET_EMPTY_ERROR(stmt->error_info);
PROT_LAST /* we will handle the response packet*/,
FALSE TSRMLS_CC)) {
stmt->error_info = stmt->conn->error_info;
- return FAIL;
+ DBG_RETURN(FAIL);
}
row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
stmt->result_bind[i].zv has been already destructed
in mysqlnd_unbuffered_free_last_data()
*/
-
+ DBG_INF_FMT("i=%d type=%d", i, Z_TYPE_P(stmt->result_bind[i].zv));
if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
stmt->result_bind[i].zv->value = data->value;
#ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
/* We asked for one row, the next one should be EOF, eat it */
ret = PACKET_READ(row_packet, result->conn);
if (row_packet->row_buffer) {
- efree(row_packet->row_buffer);
+ mnd_efree(row_packet->row_buffer);
row_packet->row_buffer = NULL;
}
+ MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
} else {
*fetched_anything = FALSE;
stmt->conn->upsert_status.server_status =
row_packet->server_status;
- return ret;
+ DBG_INF_FMT("ret=%s fetched=%d s_status=%d warns=%d eof=%d",
+ ret == PASS? "PASS":"FAIL", *fetched_anything,
+ row_packet->server_status, row_packet->warning_count,
+ result->unbuf->eof_reached);
+ DBG_RETURN(ret);
}
/* }}} */
-/* {{{ mysqlnd_stmt_fetch */
+/* {{{ mysqlnd_stmt::fetch */
PHPAPI enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const stmt,
zend_bool * const fetched_anything TSRMLS_DC)
{
+ enum_func_status ret;
+ DBG_ENTER("mysqlnd_stmt::fetch");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
if (!stmt->result ||
stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
-
- return FAIL;
+
+ DBG_ERR("command out of sync");
+ DBG_RETURN(FAIL);
} else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
/* Execute only once. We have to free the previous contents of user's bound vars */
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
+ DBG_INF_FMT("result_bind=%p separated_once=%d", stmt->result_bind, stmt->result_zvals_separated_once);
/*
The user might have not bound any variables for result.
Do the binding once she does it.
stmt->result_zvals_separated_once = TRUE;
}
- MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT);
-
- return stmt->result->m.fetch_row(stmt->result, (void*)stmt, 0, fetched_anything TSRMLS_CC);
+ ret = stmt->result->m.fetch_row(stmt->result, (void*)stmt, 0, fetched_anything TSRMLS_CC);
+ DBG_RETURN(ret);
}
/* }}} */
MYSQLND * conn = stmt->conn;
zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
+ DBG_ENTER("mysqlnd_stmt::reset");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
if (stmt->stmt_id) {
if (stmt->param_bind) {
unsigned int i;
+ DBG_INF("resetting long data");
/* Reset Long Data */
for (i = 0; i < stmt->param_count; i++) {
if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
clean.
*/
if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
+ DBG_INF("fetching result set header");
stmt->default_rset_handler(stmt TSRMLS_CC);
stmt->state = MYSQLND_STMT_USER_FETCHING;
}
if (stmt->result) {
+ DBG_INF("skipping result");
stmt->result->m.skip_result(stmt->result TSRMLS_CC);
}
/* Now the line should be free, if it wasn't */
stmt->state = MYSQLND_STMT_PREPARED;
}
- return ret;
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
size_t packet_len;
enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
+ DBG_ENTER("mysqlnd_stmt::send_long_data");
+ DBG_INF_FMT("stmt=%lu param_no=%d data_len=%lu", stmt->stmt_id, param_no, length);
+
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);
- return FAIL;
+ DBG_ERR("not prepared");
+ DBG_RETURN(FAIL);
}
if (!stmt->param_bind) {
SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return FAIL;
+ DBG_ERR("command out of sync");
+ DBG_RETURN(FAIL);
}
if (param_no >= stmt->param_count) {
SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
- return FAIL;
+ DBG_ERR("invalid param_no");
+ DBG_RETURN(FAIL);
}
if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {
SET_STMT_ERROR(stmt, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, mysqlnd_not_bound_as_blob);
- return FAIL;
+ DBG_ERR("param_no is not of a blob type");
+ DBG_RETURN(FAIL);
}
/*
if (conn->state == CONN_READY) {
stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
- cmd_buf = emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
+ cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
int4store(cmd_buf, stmt->stmt_id);
int2store(cmd_buf + STMT_ID_LENGTH, param_no);
/* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/
ret = mysqlnd_simple_command(conn, cmd, (char *)cmd_buf, packet_len,
PROT_LAST , FALSE TSRMLS_CC);
- efree(cmd_buf);
+ mnd_efree(cmd_buf);
if (FAIL == ret) {
stmt->error_info = conn->error_info;
}
#endif
}
- return ret;
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
/* {{{ _mysqlnd_stmt_bind_param */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt,
- MYSQLND_PARAM_BIND * const param_bind)
+ MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
{
unsigned int i = 0;
+ DBG_ENTER("mysqlnd_stmt::bind_param");
+ DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
+
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
- return FAIL;
+ DBG_ERR("not prepared");
+ DBG_RETURN(FAIL);
}
SET_EMPTY_ERROR(stmt->error_info);
if (!param_bind) {
SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
"Re-binding (still) not supported");
- return FAIL;
+ DBG_ERR("Re-binding (still) not supported");
+ DBG_RETURN(FAIL);
} else if (stmt->param_bind) {
+ DBG_INF("Binding");
/*
There is already result bound.
Forbid for now re-binding!!
stmt->param_bind[i].zv = NULL;
}
}
- efree(stmt->param_bind);
+ mnd_efree(stmt->param_bind);
}
stmt->param_bind = param_bind;
for (i = 0; i < stmt->param_count; i++) {
/* The client will use stmt_send_long_data */
+ DBG_INF_FMT("%d is of type %d", i, stmt->param_bind[i].type);
if (stmt->param_bind[i].type != MYSQL_TYPE_LONG_BLOB) {
/* Prevent from freeing */
ZVAL_ADDREF(stmt->param_bind[i].zv);
}
stmt->send_types_to_server = 1;
}
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_stmt::bind_result */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const stmt,
- MYSQLND_RESULT_BIND * const result_bind)
+ MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC)
{
uint i = 0;
+ 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);
if (result_bind) {
- efree(result_bind);
+ mnd_efree(result_bind);
}
- return FAIL;
+ DBG_ERR("not prepared");
+ DBG_RETURN(FAIL);
}
if (stmt->field_count) {
if (!result_bind) {
- return FAIL;
+ DBG_ERR("no result bind passed");
+ DBG_RETURN(FAIL);
}
- mysqlnd_stmt_separate_result_bind(stmt);
+ mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
stmt->result_bind = result_bind;
for (i = 0; i < stmt->field_count; i++) {
stmt->result_bind[i].bound = TRUE;
}
} else if (result_bind) {
- efree(result_bind);
+ mnd_efree(result_bind);
}
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_stmt::data_seek */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const stmt, mynd_ulonglong row)
+MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const stmt, mynd_ulonglong row TSRMLS_DC)
{
- return stmt->result? stmt->result->m.seek_data(stmt->result, row) : FAIL;
+ return stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
}
/* }}} */
/* {{{ mysqlnd_stmt::result_metadata */
static MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const stmt)
+MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC)
{
MYSQLND_RES *result;
+ DBG_ENTER("mysqlnd_stmt::result_metadata");
+ DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
+
if (!stmt->field_count || !stmt->conn || !stmt->result ||
!stmt->result->meta)
{
- return NULL;
+ DBG_INF("NULL");
+ DBG_RETURN(NULL);
}
/*
In the meantime we don't need a zval cache reference for this fake
result set, so we don't get one.
*/
- result = mysqlnd_result_init(stmt->field_count, NULL);
+ result = mysqlnd_result_init(stmt->field_count, NULL TSRMLS_CC);
result->type = MYSQLND_RES_NORMAL;
result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
- result->unbuf = ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
result->unbuf->eof_reached = TRUE;
- result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE);
+ result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
- return result;
+ DBG_INF_FMT("result=%p", result);
+ DBG_RETURN(result);
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const stmt,
enum mysqlnd_stmt_attr attr_type,
- const void * const value)
+ const void * const value TSRMLS_DC)
{
unsigned long val = *(unsigned long *) value;
+ DBG_ENTER("mysqlnd_stmt::attr_set");
+ DBG_INF_FMT("stmt=%lu attr_type=%u value=%lu", stmt->stmt_id, attr_type, val);
+
switch (attr_type) {
case STMT_ATTR_UPDATE_MAX_LENGTH:
/*
}
default:
SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
- return FAIL;
+ DBG_RETURN(FAIL);
}
- return PASS;
+ DBG_INF("PASS");
+ DBG_RETURN(PASS);
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, attr_get)(MYSQLND_STMT * const stmt,
enum mysqlnd_stmt_attr attr_type,
- void * const value)
+ void * const value TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_stmt::attr_set");
+ DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
+
switch (attr_type) {
case STMT_ATTR_UPDATE_MAX_LENGTH:
*(zend_bool *) value= stmt->update_max_length;
*(unsigned long *) value= stmt->prefetch_rows;
break;
default:
- return FAIL;
+ DBG_RETURN(FAIL);
}
- return PASS;
+ DBG_INF_FMT("value=%lu", value);
+ DBG_RETURN(PASS);
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_stmt::free_result");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
if (!stmt->result) {
- return PASS;
+ DBG_INF("no result");
+ DBG_RETURN(PASS);
}
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);
/*
Separate the bound variables, which point to the result set, then
destroy the set.
*/
- mysqlnd_stmt_separate_result_bind(stmt);
+ mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
/* Now we can destroy the result set */
stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
/* Line is free! */
stmt->conn->state = CONN_READY;
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_stmt_separate_result_bind */
-void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt)
+void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC)
{
- int i;
+ unsigned int i;
+
+ DBG_ENTER("mysqlnd_stmt_separate_result_bind");
+ DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u",
+ stmt->stmt_id, stmt->result_bind, stmt->field_count);
if (!stmt->result_bind) {
- return;
+ DBG_VOID_RETURN;
}
/*
for (i = 0; i < stmt->field_count; i++) {
/* Let's try with no cache */
if (stmt->result_bind[i].bound == TRUE) {
+ DBG_INF_FMT("%d has refcount=%u", i, ZVAL_REFCOUNT(stmt->result_bind[i].zv));
/*
We have to separate the actual zval value of the bound
variable from our allocated zvals or we will face double-free
}
}
}
- efree(stmt->result_bind);
+ mnd_efree(stmt->result_bind);
stmt->result_bind = NULL;
+
+ DBG_VOID_RETURN;
}
/* }}} */
static
void mysqlnd_internal_free_stmt_content(MYSQLND_STMT *stmt TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_internal_free_stmt_content");
+ DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u",
+ stmt->stmt_id, stmt->param_bind, stmt->param_count);
+
/* Destroy the input bind */
if (stmt->param_bind) {
int i;
}
}
- efree(stmt->param_bind);
+ mnd_efree(stmt->param_bind);
stmt->param_bind = NULL;
}
First separate the bound variables, which point to the result set, then
destroy the set.
*/
- mysqlnd_stmt_separate_result_bind(stmt);
+ mysqlnd_stmt_separate_result_bind(stmt TSRMLS_CC);
/* Not every statement has a result set attached */
if (stmt->result) {
stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
stmt->result = NULL;
}
if (stmt->cmd_buffer.buffer) {
- efree(stmt->cmd_buffer.buffer);
+ mnd_efree(stmt->cmd_buffer.buffer);
stmt->cmd_buffer.buffer = NULL;
}
stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
stmt->conn = NULL;
}
+
+ DBG_VOID_RETURN;
}
/* }}} */
{
MYSQLND * conn = stmt->conn;
zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */];
+ enum_mysqlnd_collected_stats stat = STAT_LAST;
+
+ DBG_ENTER("mysqlnd_stmt::close");
+ DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
SET_EMPTY_ERROR(stmt->error_info);
SET_EMPTY_ERROR(stmt->conn->error_info);
clean.
*/
if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
+ DBG_INF("fetching result set header");
stmt->default_rset_handler(stmt TSRMLS_CC);
stmt->state = MYSQLND_STMT_USER_FETCHING;
}
/* unbuffered set not fetched to the end ? Clean the line */
if (stmt->result) {
+ DBG_INF("skipping result");
stmt->result->m.skip_result(stmt->result TSRMLS_CC);
}
/*
After this point we are allowed to free the result set,
as we have cleaned the line
*/
- if (stmt->stmt_id) {
- MYSQLND_INC_CONN_STATISTIC(NULL, implicit == TRUE? STAT_FREE_RESULT_IMPLICIT:
- STAT_FREE_RESULT_EXPLICIT);
+ if (stmt->stmt_id) {
+ MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_FREE_RESULT_IMPLICIT:
+ STAT_FREE_RESULT_EXPLICIT);
int4store(cmd_buf, stmt->stmt_id);
if (conn->state == CONN_READY &&
PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
FALSE TSRMLS_CC)) {
stmt->error_info = conn->error_info;
- return FAIL;
+ DBG_RETURN(FAIL);
}
}
+ switch (stmt->execute_count) {
+ case 0:
+ stat = STAT_PS_PREPARED_NEVER_EXECUTED;
+ break;
+ case 1:
+ stat = STAT_PS_PREPARED_ONCE_USED;
+ break;
+ default:
+ break;
+ }
+ if (stat != STAT_LAST) {
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
+ }
mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
{
enum_func_status ret;
- MYSQLND_INC_CONN_STATISTIC(NULL, implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
- STAT_STMT_CLOSE_EXPLICIT);
+ DBG_ENTER("mysqlnd_stmt::close");
+ DBG_INF_FMT("stmt=%p", stmt);
+
+ MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
+ STAT_STMT_CLOSE_EXPLICIT);
if (PASS == (ret = stmt->m->close(stmt, implicit TSRMLS_CC))) {
- efree(stmt);
+ mnd_efree(stmt);
}
- return ret;
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
/* {{{ _mysqlnd_stmt_init */
-MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn)
+MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC)
{
- MYSQLND_STMT *stmt = ecalloc(1, sizeof(MYSQLND_STMT));
+ MYSQLND_STMT *stmt = mnd_ecalloc(1, sizeof(MYSQLND_STMT));
+
+ DBG_ENTER("_mysqlnd_stmt_init");
+ DBG_INF_FMT("stmt=%p", stmt);
stmt->m = &mysqlnd_stmt_methods;
stmt->state = MYSQLND_STMT_INITTED;
stmt->cmd_buffer.length = 4096;
- stmt->cmd_buffer.buffer = emalloc(stmt->cmd_buffer.length);
+ stmt->cmd_buffer.buffer = mnd_emalloc(stmt->cmd_buffer.length);
stmt->prefetch_rows = MYSQLND_DEFAULT_PREFETCH_ROWS;
/*
*/
stmt->conn = conn->m->get_reference(conn);
- return stmt;
+ DBG_RETURN(stmt);
}
/* }}} */
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
-
+#include "mysqlnd_debug.h"
#define MYSQLND_SILENT
if (uval > INT_MAX) {
char *tmp, *p;
int j=10;
- tmp= emalloc(11);
+ tmp= mnd_emalloc(11);
p= &tmp[9];
do {
*p-- = (uval % 10) + 48;
if (!as_unicode) {
#endif
ZVAL_STRINGL(zv, to, length, 1);
- efree(to);
+ mnd_efree(to);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
if (!as_unicode) {
#endif
ZVAL_STRINGL(zv, to, length, 1);
- efree(to);
+ mnd_efree(to);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
if (!as_unicode) {
#endif
ZVAL_STRINGL(zv, to, length, 1);
- efree(to);
+ mnd_efree(to);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
/* {{{ mysqlnd_stmt_execute_store_params */
void
mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uchar **p,
- size_t *buf_len, unsigned int null_byte_offset)
+ size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC)
{
unsigned int i = 0;
unsigned left = (*buf_len - (*p - *buf));
unsigned int offset = *p - *buf;
zend_uchar *tmp_buf;
*buf_len = offset + stmt->param_count * 2 + 20;
- tmp_buf = emalloc(*buf_len);
+ tmp_buf = mnd_emalloc(*buf_len);
memcpy(tmp_buf, *buf, offset);
*buf = tmp_buf;
unsigned int offset = *p - *buf;
zend_uchar *tmp_buf;
*buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
- tmp_buf = emalloc(*buf_len);
+ tmp_buf = mnd_emalloc(*buf_len);
memcpy(tmp_buf, *buf, offset);
*buf = tmp_buf;
/* Update our pos pointer */
/* {{{ mysqlnd_stmt_execute_generate_request */
-zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len, zend_bool *free_buffer)
+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;
int1store(p, stmt->send_types_to_server);
p++;
- mysqlnd_stmt_execute_store_params(stmt, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset);
+ 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);
*request_len = (p - cmd_buffer);
#include "mysqlnd_result_meta.h"
#include "mysqlnd_statistics.h"
#include "mysqlnd_charset.h"
+#include "mysqlnd_debug.h"
#include "ext/standard/basic_functions.h"
#define MYSQLND_SILENT
void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC)
{
MYSQLND_RES_UNBUFFERED *unbuf = result->unbuf;
+
+ DBG_ENTER("mysqlnd_unbuffered_free_last_data");
+
if (!unbuf) {
- return;
+ DBG_VOID_RETURN;
}
if (unbuf->last_row_data) {
efree(unbuf->last_row_buffer);
unbuf->last_row_buffer = NULL;
}
+
+ DBG_VOID_RETURN;
}
/* }}} */
unsigned int field_count = result->field_count;
unsigned int row;
+ DBG_ENTER("mysqlnd_free_buffered_data");
+ DBG_INF_FMT("Freeing "MYSQLND_LLU_SPEC" row(s)", result->data->row_count);
+
+ DBG_INF_FMT("before: real_usage=%lu usage=%lu", zend_memory_usage(TRUE TSRMLS_CC), zend_memory_usage(FALSE TSRMLS_CC));
for (row = 0; row < result->data->row_count; row++) {
unsigned int col;
zval **current_row = current_row = set->data[row];
zend_bool copy_ctor_called;
mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), zval_cache,
result->type, ©_ctor_called TSRMLS_CC);
- MYSQLND_INC_CONN_STATISTIC(NULL, copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED:
- STAT_COPY_ON_WRITE_SAVED);
+#if MYSQLND_DEBUG_MEMORY
+ DBG_INF_FMT("Copy_ctor_called=%d", copy_ctor_called);
+#endif
+ MYSQLND_INC_GLOBAL_STATISTIC(copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED:
+ STAT_COPY_ON_WRITE_SAVED);
}
+#if MYSQLND_DEBUG_MEMORY
+ DBG_INF("Freeing current_row & current_buffer");
+#endif
pefree(current_row, set->persistent);
pefree(current_buffer, set->persistent);
}
+ DBG_INF("Freeing data & row_buffer");
pefree(set->data, set->persistent);
pefree(set->row_buffers, set->persistent);
set->data = NULL;
if (set->qcache) {
mysqlnd_qcache_free_cache_reference(&set->qcache);
}
+ DBG_INF("Freeing set");
pefree(set, set->persistent);
+
+ DBG_INF_FMT("after: real_usage=%lu usage=%lu", zend_memory_usage(TRUE TSRMLS_CC), zend_memory_usage(FALSE TSRMLS_CC));
+ DBG_VOID_RETURN;
}
/* }}} */
void
MYSQLND_METHOD(mysqlnd_res, free_result_buffers)(MYSQLND_RES *result TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_res::free_result_buffers");
+ DBG_INF_FMT("%s", result->unbuf? "unbuffered":(result->data? "buffered":"unknown"));
if (result->unbuf) {
mysqlnd_unbuffered_free_last_data(result TSRMLS_CC);
efree(result->lengths);
result->lengths = NULL;
}
+
+ DBG_VOID_RETURN;
}
/* }}} */
static
void mysqlnd_internal_free_result_contents(MYSQLND_RES *result TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_internal_free_result_contents");
+
result->m.free_result_buffers(result TSRMLS_CC);
if (result->row_packet) {
+ DBG_INF("Freeing packet");
PACKET_FREE(result->row_packet);
result->row_packet = NULL;
}
}
if (result->zval_cache) {
+ DBG_INF("Freeing zval cache reference");
mysqlnd_palloc_free_thd_cache_reference(&result->zval_cache);
result->zval_cache = NULL;
}
+
+ DBG_VOID_RETURN;
}
/* }}} */
static
void mysqlnd_internal_free_result(MYSQLND_RES *result TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_internal_free_result");
/*
result->conn is an address if this is an unbuffered query.
In this case, decrement the reference counter in the connection
result->m.free_result_contents(result TSRMLS_CC);
efree(result);
+
+ DBG_VOID_RETURN;
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_res, read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_res::read_result_metadata");
+
/*
Make it safe to call it repeatedly for PS -
better free and allocate a new because the number of field might change
result->meta = NULL;
}
- result->meta = mysqlnd_result_meta_init(result->field_count);
+ result->meta = mysqlnd_result_meta_init(result->field_count TSRMLS_CC);
/* 1. Read all fields metadata */
/* It's safe to reread without freeing */
if (FAIL == result->meta->m->read_metadata(result->meta, conn TSRMLS_CC)) {
result->m.free_result_contents(result TSRMLS_CC);
- return FAIL;
+ DBG_RETURN(FAIL);
}
/*
If PS, then no result set follows.
*/
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
enum_func_status ret;
php_mysql_packet_rset_header rset_header;
+ DBG_ENTER("mysqlnd_query_read_result_set_header");
+ DBG_INF_FMT("stmt=%d", stmt? stmt->stmt_id:0);
+
ret = FAIL;
PACKET_INIT_ALLOCA(rset_header, PROT_RSET_HEADER_PACKET);
do {
switch (rset_header.field_count) {
case MYSQLND_NULL_LENGTH: { /* LOAD DATA LOCAL INFILE */
zend_bool is_warning;
+ DBG_INF("LOAD DATA");
conn->last_query_type = QUERY_LOAD_LOCAL;
conn->state = CONN_SENDING_LOAD_DATA;
ret = mysqlnd_handle_local_infile(conn, rset_header.info_or_local_file, &is_warning TSRMLS_CC);
break;
}
case 0: /* UPSERT */
+ DBG_INF("UPSERT");
conn->last_query_type = QUERY_UPSERT;
conn->field_count = rset_header.field_count;
conn->upsert_status.warning_count = rset_header.warning_count;
default:{ /* Result set */
php_mysql_packet_eof fields_eof;
MYSQLND_RES *result;
- uint stat = -1;
+ enum_mysqlnd_collected_stats stat = STAT_LAST;
+ DBG_INF("Result set pending");
SET_EMPTY_MESSAGE(conn->last_message, conn->last_message_len, conn->persistent);
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_RSET_QUERY);
result =
conn->current_result=
mysqlnd_result_init(rset_header.field_count,
- mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache));
+ mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache)
+ TSRMLS_CC);
} else {
if (!stmt->result) {
+ DBG_INF("This is 'SHOW'/'EXPLAIN'-like query.");
/*
This is 'SHOW'/'EXPLAIN'-like query. Current implementation of
prepared statements can't send result set metadata for these queries
result =
stmt->result =
mysqlnd_result_init(rset_header.field_count,
- mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache));
+ mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache)
+ TSRMLS_CC);
} else {
/*
Update result set metadata if it for some reason changed between
efree(conn->current_result);
conn->current_result = NULL;
}
+ DBG_ERR("Error ocurred while reading metadata");
break;
}
/* Check for SERVER_STATUS_MORE_RESULTS if needed */
PACKET_INIT_ALLOCA(fields_eof, PROT_EOF_PACKET);
if (FAIL == (ret = PACKET_READ_ALLOCA(fields_eof, conn))) {
+ DBG_ERR("Error ocurred while reading the EOF packet");
result->m.free_result_contents(result TSRMLS_CC);
efree(result);
if (!stmt) {
stmt->state = MYSQLND_STMT_INITTED;
}
} else {
+ DBG_INF_FMT("warns=%u status=%u", fields_eof.warning_count, fields_eof.server_status);
conn->upsert_status.warning_count = fields_eof.warning_count;
conn->upsert_status.server_status = fields_eof.server_status;
if (fields_eof.server_status & MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED) {
} else if (fields_eof.server_status & MYSQLND_SERVER_QUERY_NO_INDEX_USED) {
stat = STAT_NO_INDEX_USED;
}
- if (stat != -1) {
+ if (stat != STAT_LAST) {
+ char *backtrace = mysqlnd_get_backtrace(TSRMLS_C);
+#if A0
+ php_log_err(backtrace TSRMLS_CC);
+#endif
+ efree(backtrace);
MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
}
}
}
} while (0);
PACKET_FREE_ALLOCA(rset_header);
- return ret;
+
+ DBG_INF(ret == PASS? "PASS":"FAIL");
+ DBG_RETURN(ret);
}
/* }}} */
php_mysql_packet_row *row_packet = result->row_packet;
unsigned long *lengths = result->lengths;
+ DBG_ENTER("mysqlnd_fetch_row_unbuffered");
+ DBG_INF_FMT("flags=%d", flags);
+
if (result->unbuf->eof_reached) {
/* No more rows obviously */
*fetched_anything = FALSE;
- return PASS;
+ DBG_RETURN(PASS);
}
if (result->conn->state != CONN_FETCHING_DATA) {
SET_CLIENT_ERROR(result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
- return FAIL;
+ DBG_RETURN(FAIL);
}
- /* Let the row packet fill our buffer and skip additional malloc + memcpy */
+ /* Let the row packet fill our buffer and skip additional mnd_malloc + memcpy */
row_packet->skip_extraction = row? FALSE:TRUE;
/*
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
- MYSQLND_INC_CONN_STATISTIC(&result->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT);
+ MYSQLND_INC_CONN_STATISTIC(&result->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF);
if (!row_packet->skip_extraction) {
HashTable *row_ht = Z_ARRVAL_P(row);
}
} else if (ret == FAIL) {
if (row_packet->error_info.error_no) {
- result->conn->error_info = row_packet->error_info;
+ result->conn->error_info = row_packet->error_info;
+ DBG_ERR_FMT("errorno=%d error=%s", row_packet->error_info.error_no, row_packet->error_info.error);
}
*fetched_anything = FALSE;
result->conn->state = CONN_READY;
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);
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;
*fetched_anything = FALSE;
}
- return PASS;
+ DBG_INF_FMT("ret=%s fetched=%d", ret == PASS? "PASS":"FAIL", *fetched_anything);
+ DBG_RETURN(PASS);
}
/* }}} */
MYSQLND_RES *
MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_res::use_result");
+ DBG_INF_FMT("ps=%d", ps);
+
result->type = MYSQLND_RES_NORMAL;
result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
result->m.fetch_lengths = mysqlnd_fetch_lengths_unbuffered;
- result->unbuf = ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
+ result->unbuf = mnd_ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
/*
Will be freed in the mysqlnd_internal_free_result_contents() called
result->row_packet->fields_metadata = result->meta->fields;
result->row_packet->bit_fields_count = result->meta->bit_fields_count;
result->row_packet->bit_fields_total_len = result->meta->bit_fields_total_len;
- result->lengths = ecalloc(result->field_count, sizeof(unsigned long));
+ result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
/* No multithreading issues as we don't share the connection :) */
- return result;
+ DBG_RETURN(result);
}
/* }}} */
unsigned int i;
zval *row = (zval *) param;
+ DBG_ENTER("mysqlnd_fetch_row_buffered");
+ DBG_INF_FMT("flags=%u row=%p", flags, row);
+
/* If we haven't read everything */
if (result->data->data_cursor &&
(result->data->data_cursor - result->data->data) < result->data->row_count)
}
result->data->data_cursor++;
*fetched_anything = TRUE;
+ MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF);
} else {
result->data->data_cursor = NULL;
*fetched_anything = FALSE;
-#ifndef MYSQLND_SILENT
- php_printf("NO MORE DATA\n ");
-#endif
+ DBG_INF("EOF reached");
}
- return PASS;
+ DBG_INF_FMT("ret=PASS fetched=%d", *fetched_anything);
+ DBG_RETURN(PASS);
}
/* }}} */
unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET, free_rows;
MYSQLND_RES_BUFFERED *set;
+ DBG_ENTER("mysqlnd_store_result_fetch_data");
+ DBG_INF_FMT("conn=%llu binary_proto=%d update_max_len=%d to_cache=%d",
+ conn->thread_id, binary_protocol, update_max_length, to_cache);
+
free_rows = next_extend;
- result->data = set = pecalloc(1, sizeof(MYSQLND_RES_BUFFERED), to_cache);
- set->data = pemalloc(STORE_RESULT_PREALLOCATED_SET * sizeof(zval **), to_cache);
- set->row_buffers= pemalloc(STORE_RESULT_PREALLOCATED_SET * sizeof(zend_uchar *), to_cache);
+ result->data = set = mnd_pecalloc(1, sizeof(MYSQLND_RES_BUFFERED), to_cache);
+ set->data = mnd_pemalloc(STORE_RESULT_PREALLOCATED_SET * sizeof(zval **), to_cache);
+ set->row_buffers= mnd_pemalloc(STORE_RESULT_PREALLOCATED_SET * sizeof(zend_uchar *), to_cache);
set->persistent = to_cache;
set->qcache = to_cache? mysqlnd_qcache_get_cache_reference(conn->qcache):NULL;
set->references = 1;
if (!free_rows) {
mynd_ulonglong total_rows = free_rows = next_extend = next_extend * 5 / 3; /* extend with 33% */
total_rows += set->row_count;
- set->data = perealloc(set->data, total_rows * sizeof(zval **), set->persistent);
+ set->data = mnd_perealloc(set->data, total_rows * sizeof(zval **), set->persistent);
- set->row_buffers = perealloc(set->row_buffers,
+ set->row_buffers = mnd_perealloc(set->row_buffers,
total_rows * sizeof(zend_uchar *), set->persistent);
}
free_rows--;
transfered above.
*/
}
- MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT,
+ 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);
/* Finally clean */
}
/* save some memory */
if (free_rows) {
- set->data = perealloc(set->data,
+ set->data = mnd_perealloc(set->data,
(size_t) set->row_count * sizeof(zval **),
set->persistent);
- set->row_buffers = perealloc(set->row_buffers,
+ set->row_buffers = mnd_perealloc(set->row_buffers,
(size_t) set->row_count * sizeof(zend_uchar *),
set->persistent);
}
}
PACKET_FREE_ALLOCA(row_packet);
- return ret;
+ DBG_INF_FMT("ret=%s row_count=%u warns=%u status=%u", ret == PASS? "PASS":"FAIL",
+ set->row_count, conn->upsert_status.warning_count, conn->upsert_status.server_status);
+ DBG_RETURN(ret);
}
/* }}} */
enum_func_status ret;
zend_bool to_cache = FALSE;
+ DBG_ENTER("mysqlnd_res::store_result");
+ DBG_INF_FMT("conn=%d ps_protocol=%d", conn->thread_id, ps_protocol);
+
result->conn = NULL; /* store result does not reference the connection */
result->type = MYSQLND_RES_NORMAL;
result->m.fetch_row = result->m.fetch_row_normal_buffered;
conn->state = CONN_FETCHING_DATA;
- result->lengths = ecalloc(result->field_count, sizeof(unsigned long));
+ result->lengths = mnd_ecalloc(result->field_count, sizeof(unsigned long));
ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
ps_protocol, TRUE, to_cache TSRMLS_CC);
result = NULL;
}
- return result;
+ DBG_RETURN(result);
}
/* }}} */
{
zend_bool fetched_anything;
+ DBG_ENTER("mysqlnd_res::skip_result");
/*
Unbuffered sets
A PS could be prepared - there is metadata and thus a stmt->result but the
if (!result->data && result->conn && result->unbuf &&
!result->unbuf->eof_reached && result->m.fetch_row)
{
+ DBG_INF("skipping result");
/* We have to fetch all data to clean the line */
MYSQLND_INC_CONN_STATISTIC(&result->conn->stats,
result->type == MYSQLND_RES_NORMAL? STAT_FLUSHED_NORMAL_SETS:
/* do nothing */;
}
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
static enum_func_status
MYSQLND_METHOD(mysqlnd_res, free_result)(MYSQLND_RES *result, zend_bool implicit TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_res::free_result");
+ DBG_INF_FMT("implicit=%d", implicit);
+
result->m.skip_result(result TSRMLS_CC);
MYSQLND_INC_CONN_STATISTIC(result->conn? &result->conn->stats : NULL,
- implicit == TRUE? STAT_FREE_RESULT_EXPLICIT:
- STAT_FREE_RESULT_IMPLICIT);
+ implicit == TRUE? STAT_FREE_RESULT_IMPLICIT:
+ STAT_FREE_RESULT_EXPLICIT);
result->m.free_result_internal(result TSRMLS_CC);
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
-/* {{{ _mysqlnd_data_seek */
+/* {{{ mysqlnd_res::data_seek */
static enum_func_status
-MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES *result, mynd_ulonglong row)
+MYSQLND_METHOD(mysqlnd_res, data_seek)(MYSQLND_RES *result, mynd_ulonglong row TSRMLS_DC)
{
+ DBG_ENTER("mysqlnd_res::data_seek");
+ DBG_INF_FMT("row=%lu", row);
+
if (!result->data) {
return FAIL;
}
result->data->data_cursor = result->data->data + row;
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_res::fetch_field */
static MYSQLND_FIELD *
-MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result)
+MYSQLND_METHOD(mysqlnd_res, fetch_field)(MYSQLND_RES * const result TSRMLS_DC)
{
- return result->meta? result->meta->m->fetch_field(result->meta):NULL;
+ DBG_ENTER("mysqlnd_res::fetch_field");
+ DBG_RETURN(result->meta? result->meta->m->fetch_field(result->meta TSRMLS_CC):NULL);
}
/* }}} */
/* {{{ mysqlnd_res::fetch_field_direct */
static MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res, fetch_field_direct)(const MYSQLND_RES * const result,
- MYSQLND_FIELD_OFFSET fieldnr)
+ MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
{
- return result->meta? result->meta->m->fetch_field_direct(result->meta, fieldnr):NULL;
+ DBG_ENTER("mysqlnd_res::fetch_field_direct");
+ DBG_RETURN(result->meta? result->meta->m->fetch_field_direct(result->meta, fieldnr TSRMLS_CC):NULL);
}
/* }}} */
{
zend_bool fetched_anything;
+ DBG_ENTER("mysqlnd_res::fetch_into");
+ DBG_INF_FMT("flags=%u mysqlnd_extension=%d", flags, extension);
+
if (!result->m.fetch_row) {
- RETURN_NULL();
+ RETVAL_NULL();
+ DBG_VOID_RETURN;
}
/*
Hint Zend how many elements we will have in the hash. Thus it won't
mysqlnd_array_init(return_value, mysqlnd_num_fields(result) * 2);
if (FAIL == result->m.fetch_row(result, (void *)return_value, flags, &fetched_anything TSRMLS_CC)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading a row");
- RETURN_FALSE;
+ RETVAL_FALSE;
} else if (fetched_anything == FALSE) {
zval_dtor(return_value);
switch (extension) {
case MYSQLND_MYSQLI:
- RETURN_NULL();
+ RETVAL_NULL();
break;
case MYSQLND_MYSQL:
- RETURN_FALSE;
+ RETVAL_FALSE;
break;
default:exit(0);
}
return_value is IS_NULL for no more data and an array for data. Thus it's ok
to return here.
*/
+ DBG_VOID_RETURN;
}
/* }}} */
zval *row;
ulong i = 0;
+ DBG_ENTER("mysqlnd_res::fetch_all");
+ DBG_INF_FMT("flags=%u", flags);
+
/* mysqlnd_res::fetch_all works with buffered resultsets only */
if (result->conn || !result->data ||
!result->data->row_count || !result->data->data_cursor ||
result->data->data_cursor >= result->data->data + result->data->row_count)
{
- RETURN_NULL();
+ RETVAL_NULL();
+ DBG_VOID_RETURN;
}
mysqlnd_array_init(return_value, (uint) result->data->row_count);
mysqlnd_fetch_into(result, flags, row, MYSQLND_MYSQLI);
add_index_zval(return_value, i++, row);
}
+
+ DBG_VOID_RETURN;
}
/* }}} */
zval **entry;
uint i = 0;
+ DBG_ENTER("mysqlnd_res::fetch_field_data");
+ DBG_INF_FMT("offset=%u", offset);
+
if (!result->m.fetch_row) {
- RETURN_NULL();
+ RETVAL_NULL();
+ DBG_VOID_RETURN;
}
/*
Hint Zend how many elements we will have in the hash. Thus it won't
mysqlnd_fetch_into(result, MYSQLND_FETCH_NUM, &row, MYSQLND_MYSQL);
if (Z_TYPE(row) != IS_ARRAY) {
zval_dtor(&row);
- RETURN_NULL();
+ RETVAL_NULL();
+ DBG_VOID_RETURN;
}
zend_hash_internal_pointer_reset(Z_ARRVAL(row));
while (i++ < offset) {
zval_copy_ctor(return_value);
ZVAL_REFCOUNT(return_value) = 1;
zval_dtor(&row);
+
+ DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_result_init */
-MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache)
+MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC)
{
- MYSQLND_RES *ret = ecalloc(1, sizeof(MYSQLND_RES));
+ MYSQLND_RES *ret = mnd_ecalloc(1, sizeof(MYSQLND_RES));
+
+ DBG_ENTER("mysqlnd_result_init");
+ DBG_INF_FMT("field_count=%u cache=%p", field_count, cache);
ret->field_count = field_count;
ret->zval_cache = cache;
ret->m.fetch_row_normal_buffered = mysqlnd_fetch_row_buffered;
ret->m.fetch_row_normal_unbuffered = mysqlnd_fetch_row_unbuffered;
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
#ifndef MYSQLND_RESULT_H
#define MYSQLND_RESULT_H
-MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache);
+MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC);
void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC);
#include "mysqlnd_priv.h"
#include "mysqlnd_result.h"
#include "mysqlnd_wireprotocol.h"
+#include "mysqlnd_debug.h"
#include "ext/standard/basic_functions.h"
/* {{{ php_mysqlnd_free_field_metadata */
static
-void php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent)
+void php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent TSRMLS_DC)
{
if (meta) {
if (meta->root) {
- pefree(meta->root, persistent);
+ mnd_pefree(meta->root, persistent);
meta->root = NULL;
}
if (meta->def) {
- pefree(meta->def, persistent);
+ mnd_pefree(meta->def, persistent);
meta->def = NULL;
}
}
int i = 0;
php_mysql_packet_res_field field_packet;
+ DBG_ENTER("mysqlnd_res_meta::read_metadata");
+
PACKET_INIT_ALLOCA(field_packet, PROT_RSET_FLD_PACKET);
for (;i < meta->field_count; i++) {
long idx;
if (meta->fields[i].root) {
/* We re-read metadata for PS */
- efree(meta->fields[i].root);
+ mnd_efree(meta->fields[i].root);
meta->fields[i].root = NULL;
}
field_packet.metadata = &(meta->fields[i]);
if (FAIL == PACKET_READ_ALLOCA(field_packet, conn)) {
PACKET_FREE_ALLOCA(field_packet);
- return FAIL;
+ DBG_RETURN(FAIL);
+ }
+ if (field_packet.stupid_list_fields_eof == TRUE) {
+ break;
}
if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) {
+ DBG_ERR_FMT("Unknown type %d sent by the server. Please send a report to the developers",
+ meta->fields[i].type);
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Unknown type %d sent by the server. "
"Please send a report to the developers",
meta->fields[i].type);
PACKET_FREE_ALLOCA(field_packet);
- return FAIL;
+ DBG_RETURN(FAIL);
}
if (meta->fields[i].type == MYSQL_TYPE_BIT) {
size_t field_len;
+ DBG_INF("BIT");
++meta->bit_fields_count;
/* .length is in bits */
field_len = meta->fields[i].length / 8;
mysqlnd_unicode_is_key_numeric(ustr, ulen + 1, &idx)))
{
meta->zend_hash_keys[i].key = idx;
- efree(ustr);
+ mnd_efree(ustr);
} else {
meta->zend_hash_keys[i].ustr.u = ustr;
meta->zend_hash_keys[i].ulen = ulen;
}
PACKET_FREE_ALLOCA(field_packet);
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
int i;
MYSQLND_FIELD *fields;
+ DBG_ENTER("mysqlnd_res_meta::free");
+ DBG_INF_FMT("persistent=%d", persistent);
+
if ((fields = meta->fields)) {
+ DBG_INF("Freeing fields metadata");
i = meta->field_count;
while (i--) {
- php_mysqlnd_free_field_metadata(fields++, persistent);
+ php_mysqlnd_free_field_metadata(fields++, persistent TSRMLS_CC);
}
- pefree(meta->fields, persistent);
+ mnd_pefree(meta->fields, persistent);
meta->fields = NULL;
}
if (meta->zend_hash_keys) {
+ DBG_INF("Freeing zend_hash_keys");
#if PHP_MAJOR_VERSION >= 6
if (UG(unicode)) {
for (i = 0; i < meta->field_count; i++) {
if (meta->zend_hash_keys[i].ustr.v) {
- pefree(meta->zend_hash_keys[i].ustr.v, persistent);
+ mnd_pefree(meta->zend_hash_keys[i].ustr.v, persistent);
}
}
}
#endif
- pefree(meta->zend_hash_keys, persistent);
+ mnd_pefree(meta->zend_hash_keys, persistent);
meta->zend_hash_keys = NULL;
}
- pefree(meta, persistent);
+ DBG_INF("Freeing metadata structure");
+ mnd_pefree(meta, persistent);
+
+ DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_res::clone_metadata */
static MYSQLND_RES_METADATA *
MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * const meta,
- zend_bool persistent)
+ zend_bool persistent TSRMLS_DC)
{
unsigned int i;
/* +1 is to have empty marker at the end */
- MYSQLND_RES_METADATA *new_meta = pemalloc(sizeof(MYSQLND_RES_METADATA), persistent);
- MYSQLND_FIELD *new_fields = pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
+ MYSQLND_RES_METADATA *new_meta = mnd_pemalloc(sizeof(MYSQLND_RES_METADATA), persistent);
+ MYSQLND_FIELD *new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
MYSQLND_FIELD *orig_fields = meta->fields;
size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);
- new_meta->zend_hash_keys = pemalloc(len, persistent);
+ DBG_ENTER("mysqlnd_res_meta::clone_metadata");
+ DBG_INF_FMT("persistent=%d", persistent);
+
+ new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
memcpy(new_meta->zend_hash_keys, meta->zend_hash_keys, len);
new_meta->m = meta->m;
memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
for (i = 0; i < meta->field_count; i++) {
/* First copy the root, then field by field adjust the pointers */
- new_fields[i].root = pemalloc(orig_fields[i].root_len, persistent);
+ new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);
memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);
if (orig_fields[i].name && orig_fields[i].name != mysqlnd_empty_string) {
}
/* def is not on the root, if allocated at all */
if (orig_fields[i].def) {
- new_fields[i].def = pemalloc(orig_fields[i].def_length + 1, persistent);
+ new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
/* copy the trailing \0 too */
memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
}
new_meta->fields = new_fields;
- return new_meta;
+ DBG_RETURN(new_meta);
}
/* }}} */
/* {{{ mysqlnd_res_meta::fetch_field */
static MYSQLND_FIELD *
-MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta)
+MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
{
- if (meta->current_field >= meta->field_count)
- return NULL;
- return &meta->fields[meta->current_field++];
+ DBG_ENTER("mysqlnd_res_meta::fetch_field");
+ if (meta->current_field >= meta->field_count) {
+ DBG_RETURN(NULL);
+ }
+ DBG_RETURN(&meta->fields[meta->current_field++]);
}
/* }}} */
/* {{{ mysqlnd_res_meta::fetch_field_direct */
static MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta,
- MYSQLND_FIELD_OFFSET fieldnr)
+ MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
{
- return &meta->fields[fieldnr];
+ DBG_ENTER("mysqlnd_res_meta::fetch_field_direct");
+ DBG_INF_FMT("fieldnr=%d", fieldnr);
+ DBG_RETURN(&meta->fields[fieldnr]);
}
/* }}} */
/* {{{ mysqlnd_result_meta_init */
-MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count)
+MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count TSRMLS_DC)
{
MYSQLND_RES_METADATA *ret;
+ DBG_ENTER("mysqlnd_result_meta_init");
+
/* +1 is to have empty marker at the end */
- ret = ecalloc(1, sizeof(MYSQLND_RES_METADATA));
+ ret = mnd_ecalloc(1, sizeof(MYSQLND_RES_METADATA));
ret->field_count = field_count;
ret->fields = ecalloc(field_count + 1, sizeof(MYSQLND_FIELD));
ret->zend_hash_keys = ecalloc(field_count, sizeof(struct mysqlnd_field_hash_key));
ret->m = & mysqlnd_mysqlnd_res_meta_methods;
- return ret;
+ DBG_INF_FMT("meta=%p", ret);
+ DBG_RETURN(ret);
}
#define MYSQLND_RESULT_META_H
-MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count);
+MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count TSRMLS_DC);
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_statistics.h"
-
-
-typedef struct st_mysqlnd_string
-{
- char *s;
- size_t l;
-} MYSQLND_STRING;
+#include "mysqlnd_debug.h"
#define STR_W_LEN(str) str, (sizeof(str) - 1)
/* {{{ mysqlnd_stats_values_names
*/
-static
const MYSQLND_STRING mysqlnd_stats_values_names[STAT_LAST] =
{
{ STR_W_LEN("bytes_sent") },
{ STR_W_LEN("ps_unbuffered_sets") },
{ STR_W_LEN("flushed_normal_sets") },
{ STR_W_LEN("flushed_ps_sets") },
- { STR_W_LEN("rows_fetched_from_server") },
- { STR_W_LEN("rows_fetched_from_client") },
- { STR_W_LEN("rows_skipped") },
+ { STR_W_LEN("ps_prepared_never_executed") },
+ { STR_W_LEN("ps_prepared_once_executed") },
+ { STR_W_LEN("rows_fetched_from_server_normal") },
+ { STR_W_LEN("rows_fetched_from_server_ps") },
+ { STR_W_LEN("rows_buffered_from_client_normal") },
+ { STR_W_LEN("rows_buffered_from_client_ps") },
+ { STR_W_LEN("rows_fetched_from_client_normal_buffered") },
+ { STR_W_LEN("rows_fetched_from_client_normal_unbuffered") },
+ { STR_W_LEN("rows_fetched_from_client_ps_buffered") },
+ { STR_W_LEN("rows_fetched_from_client_ps_unbuffered") },
+ { STR_W_LEN("rows_fetched_from_client_ps_cursor") },
+ { STR_W_LEN("rows_skipped_normal") },
+ { STR_W_LEN("rows_skipped_ps") },
{ STR_W_LEN("copy_on_write_saved") },
{ STR_W_LEN("copy_on_write_performed") },
{ STR_W_LEN("command_buffer_too_small") },
{ STR_W_LEN("connect_success") },
{ STR_W_LEN("connect_failure") },
{ STR_W_LEN("connection_reused") },
+ { STR_W_LEN("reconnect") },
+ { STR_W_LEN("pconnect_success") },
+ { STR_W_LEN("active_connections") },
+ { STR_W_LEN("active_persistent_connections") },
{ STR_W_LEN("explicit_close") },
{ STR_W_LEN("implicit_close") },
{ STR_W_LEN("disconnect_close") },
{ STR_W_LEN("implicit_free_result") },
{ STR_W_LEN("explicit_stmt_close") },
{ STR_W_LEN("implicit_stmt_close") },
+ { STR_W_LEN("mem_emalloc_count") },
+ { STR_W_LEN("mem_emalloc_ammount") },
+ { STR_W_LEN("mem_ecalloc_count") },
+ { STR_W_LEN("mem_ecalloc_ammount") },
+ { STR_W_LEN("mem_erealloc_count") },
+ { STR_W_LEN("mem_erealloc_ammount") },
+ { STR_W_LEN("mem_efree_count") },
+ { STR_W_LEN("mem_malloc_count") },
+ { STR_W_LEN("mem_malloc_ammount") },
+ { STR_W_LEN("mem_calloc_count") },
+ { STR_W_LEN("mem_calloc_ammount") },
+ { STR_W_LEN("mem_realloc_calloc") },
+ { STR_W_LEN("mem_realloc_ammount") },
+ { STR_W_LEN("mem_free_count") }
};
/* }}} */
+/* {{{ mysqlnd_fill_stats_hash */
void
mysqlnd_fill_stats_hash(const MYSQLND_STATS * const stats, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
{
}
}
}
+/* }}} */
/* {{{ _mysqlnd_get_client_stats */
PHPAPI void _mysqlnd_get_client_stats(zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
{
MYSQLND_STATS stats, *stats_ptr = mysqlnd_global_stats;
-
+ DBG_ENTER("_mysqlnd_get_client_stats");
if (!stats_ptr) {
memset(&stats, 0, sizeof(stats));
stats_ptr = &stats;
}
mysqlnd_fill_stats_hash(stats_ptr, return_value TSRMLS_CC ZEND_FILE_LINE_CC);
+ DBG_VOID_RETURN;
}
+/* }}} */
/*
extern MYSQLND_STATS *mysqlnd_global_stats;
+typedef struct st_mysqlnd_string
+{
+ char *s;
+ size_t l;
+} MYSQLND_STRING;
+
+extern const MYSQLND_STRING mysqlnd_stats_values_names[];
+
#ifdef ZTS
+#define MYSQLND_INC_GLOBAL_STATISTIC(statistic) \
+ { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
+ tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
+ mysqlnd_global_stats->values[(statistic)]++; \
+ tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
+ }\
+ }
+
+#define MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(statistic1, value1, statistic2, value2) \
+ { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global stats increase w value [%s] [%s]", mysqlnd_stats_values_names[statistic1], mysqlnd_stats_values_names[statistic2]); \
+ tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
+ mysqlnd_global_stats->values[(statistic1)] += (value1); \
+ mysqlnd_global_stats->values[(statistic2)] += (value2); \
+ tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
+ }\
+ }
+
+#define MYSQLND_DEC_CONN_STATISTIC(conn_stats, statistic) \
+ { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global&conn stat decrease [%s]", mysqlnd_stats_values_names[statistic]); \
+ tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
+ mysqlnd_global_stats->values[(statistic)]--; \
+ tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
+ if ((conn_stats)) { \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic)]--; \
+ } \
+ }\
+ }
+
#define MYSQLND_INC_CONN_STATISTIC(conn_stats, statistic) \
{ \
- if (mysqlnd_global_stats) { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global&Conn stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
- mysqlnd_global_stats->values[statistic]++; \
+ mysqlnd_global_stats->values[(statistic)]++; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
- ((MYSQLND_STATS *) conn_stats)->values[statistic]++; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic)]++; \
} \
}\
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn_stats, statistic, value) \
{ \
- if (mysqlnd_global_stats) {\
- my_uint64 v = (value); \
- \
+ if (MYSQLND_G(collect_statistics)) { \
+ my_uint64 v = (my_uint64) (value); \
+ DBG_INF_FMT("Global&Conn stat increase w value [%s]", mysqlnd_stats_values_names[statistic]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
- mysqlnd_global_stats->values[statistic] += v; \
+ mysqlnd_global_stats->values[(statistic)] += v; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
- ((MYSQLND_STATS *) conn_stats)->values[statistic]+= v; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic)]+= v; \
} \
}\
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats, statistic1, value1, statistic2, value2, statistic3, value3) \
{ \
- if (mysqlnd_global_stats) { \
- my_uint64 v1 = (value1); \
- my_uint64 v2 = (value2); \
- my_uint64 v3 = (value3); \
+ if (MYSQLND_G(collect_statistics)) { \
+ my_uint64 v1 = (my_uint64) (value1); \
+ my_uint64 v2 = (my_uint64) (value2); \
+ my_uint64 v3 = (my_uint64) (value3); \
\
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
- mysqlnd_global_stats->values[statistic1]+= v1; \
- mysqlnd_global_stats->values[statistic2]+= v2; \
- mysqlnd_global_stats->values[statistic3]+= v3; \
+ mysqlnd_global_stats->values[(statistic1)]+= v1; \
+ mysqlnd_global_stats->values[(statistic2)]+= v2; \
+ mysqlnd_global_stats->values[(statistic3)]+= v3; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
- ((MYSQLND_STATS *) conn_stats)->values[statistic1]+= v1; \
- ((MYSQLND_STATS *) conn_stats)->values[statistic2]+= v2; \
- ((MYSQLND_STATS *) conn_stats)->values[statistic3]+= v3; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic1)]+= v1; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic2)]+= v2; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic3)]+= v3; \
} \
} \
}
#else /* NON-ZTS */
+#define MYSQLND_INC_GLOBAL_STATISTIC(statistic) \
+ { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
+ mysqlnd_global_stats->values[(statistic)]++; \
+ } \
+ }
+
+#define MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(statistic1, value1, statistic2, value2) \
+ { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global stats increase w value [%s] [%s]", \
+ mysqlnd_stats_values_names[statistic1], mysqlnd_stats_values_names[statistic2]); \
+ mysqlnd_global_stats->values[(statistic1)] += (value1); \
+ mysqlnd_global_stats->values[(statistic2)] += (value2); \
+ }\
+ }
+
+
+#define MYSQLND_DEC_CONN_STATISTIC(conn_stats, statistic) \
+ { \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global&Conn stat decrease [%s]", mysqlnd_stats_values_names[statistic]); \
+ mysqlnd_global_stats->values[(statistic)]--; \
+ if ((conn_stats)) { \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic)]--; \
+ } \
+ } \
+ }
+
#define MYSQLND_INC_CONN_STATISTIC(conn_stats, statistic) \
{ \
- if (mysqlnd_global_stats) { \
- mysqlnd_global_stats->values[statistic]++; \
+ if (MYSQLND_G(collect_statistics)) { \
+ DBG_INF_FMT("Global&Conn stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
+ mysqlnd_global_stats->values[(statistic)]++; \
if ((conn_stats)) { \
- ((MYSQLND_STATS *) conn_stats)->values[statistic]++; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic)]++; \
} \
} \
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn_stats, statistic, value) \
{ \
- my_uint64 v = (value); \
- \
- if (mysqlnd_global_stats) { \
- mysqlnd_global_stats->values[statistic]+= v; \
+ my_uint64 v = (my_uint64) (value); \
+ DBG_INF_FMT("Global&Conn stats increase w value [%s]", mysqlnd_stats_values_names[statistic]); \
+ if (MYSQLND_G(collect_statistics)) { \
+ mysqlnd_global_stats->values[(statistic)] += v; \
if ((conn_stats)) { \
- ((MYSQLND_STATS *) conn_stats)->values[statistic]+= v; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic)] += v; \
} \
} \
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats, statistic1, value1, statistic2, value2, statistic3, value3) \
{ \
- if (mysqlnd_global_stats) { \
- my_uint64 v1 = (value1); \
- my_uint64 v2 = (value2); \
- my_uint64 v3 = (value3); \
+ if (MYSQLND_G(collect_statistics)) { \
+ my_uint64 v1 = (my_uint64) (value1); \
+ my_uint64 v2 = (my_uint64) (value2); \
+ my_uint64 v3 = (my_uint64) (value3); \
\
- mysqlnd_global_stats->values[statistic1]+= v1; \
- mysqlnd_global_stats->values[statistic2]+= v2; \
- mysqlnd_global_stats->values[statistic3]+= v3; \
+ mysqlnd_global_stats->values[(statistic1)]+= v1; \
+ mysqlnd_global_stats->values[(statistic2)]+= v2; \
+ mysqlnd_global_stats->values[(statistic3)]+= v3; \
if ((conn_stats)) { \
- ((MYSQLND_STATS *) conn_stats)->values[statistic1]+= v1; \
- ((MYSQLND_STATS *) conn_stats)->values[statistic2]+= v2; \
- ((MYSQLND_STATS *) conn_stats)->values[statistic3]+= v3; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic1)]+= v1; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic2)]+= v2; \
+ ((MYSQLND_STATS *) conn_stats)->values[(statistic3)]+= v3; \
} \
} \
}
--- /dev/null
+/*
+ +----------------------------------------------------------------------+
+ | PHP Version 6 |
+ +----------------------------------------------------------------------+
+ | Copyright (c) 2006-2007 The PHP Group |
+ +----------------------------------------------------------------------+
+ | This source file is subject to version 3.01 of the PHP license, |
+ | that is bundled with this package in the file LICENSE, and is |
+ | available through the world-wide-web at the following url: |
+ | http://www.php.net/license/3_01.txt |
+ | If you did not receive a copy of the PHP license and are unable to |
+ | obtain it through the world-wide-web, please send a note to |
+ | license@php.net so we can mail you a copy immediately. |
+ +----------------------------------------------------------------------+
+ | Authors: Georg Richter <georg@mysql.com> |
+ | Andrey Hristov <andrey@mysql.com> |
+ | Ulf Wendel <uwendel@mysql.com> |
+ +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifndef MYSQLND_STRUCTS_H
+#define MYSQLND_STRUCTS_H
+
+typedef struct st_mysqlnd_cmd_buffer
+{
+ zend_uchar *buffer;
+ size_t length;
+} MYSQLND_CMD_BUFFER;
+
+
+typedef struct st_mysqlnd_field
+{
+ char *name; /* Name of column */
+ char *org_name; /* Original column name, if an alias */
+ char *table; /* Table of column if column was a field */
+ char *org_table; /* Org table name, if table was an alias */
+ char *db; /* Database for table */
+ char *catalog; /* Catalog for table */
+ char *def; /* Default value (set by mysql_list_fields) */
+ unsigned long length; /* Width of column (create length) */
+ unsigned long max_length; /* Max width for selected set */
+ unsigned int name_length;
+ unsigned int org_name_length;
+ unsigned int table_length;
+ unsigned int org_table_length;
+ unsigned int db_length;
+ unsigned int catalog_length;
+ unsigned int def_length;
+ unsigned int flags; /* Diverse flags */
+ unsigned int decimals; /* Number of decimals in field */
+ unsigned int charsetnr; /* Character set */
+ enum mysqlnd_field_types type; /* Type of field. See mysql_com.h for types */
+ char *root;
+ size_t root_len;
+} MYSQLND_FIELD;
+
+
+
+typedef struct st_mysqlnd_upsert_result
+{
+ unsigned int warning_count;
+ unsigned int server_status;
+ unsigned long long affected_rows;
+ unsigned long long last_insert_id;
+} mysqlnd_upsert_status;
+
+
+typedef struct st_mysqlnd_error_info
+{
+ char error[MYSQLND_ERRMSG_SIZE+1];
+ char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
+ unsigned int error_no;
+} mysqlnd_error_info;
+
+
+typedef struct st_mysqlnd_zval_pcache MYSQLND_ZVAL_PCACHE;
+typedef struct st_mysqlnd_thread_zval_pcache MYSQLND_THD_ZVAL_PCACHE;
+typedef struct st_mysqlnd_qcache MYSQLND_QCACHE;
+
+
+typedef struct st_mysqlnd_infile_info
+{
+ php_stream *fd;
+ int error_no;
+ char error_msg[MYSQLND_ERRMSG_SIZE + 1];
+ const char *filename;
+} MYSQLND_INFILE_INFO;
+
+
+/* character set information */
+typedef struct st_mysqlnd_charset
+{
+ uint nr;
+ char *name;
+ char *collation;
+ uint char_minlen;
+ uint char_maxlen;
+ uint dangerous_for_escape_backslash;
+ uint (*mb_charlen)(uint c);
+ uint (*mb_valid)(const char *start, const char *end);
+} MYSQLND_CHARSET;
+
+
+/* local infile handler */
+typedef struct st_mysqlnd_infile
+{
+ int (*local_infile_init)(void **ptr, char *filename, void **userdata TSRMLS_DC);
+ int (*local_infile_read)(void *ptr, char *buf, uint buf_len TSRMLS_DC);
+ int (*local_infile_error)(void *ptr, char *error_msg, uint error_msg_len TSRMLS_DC);
+ void (*local_infile_end)(void *ptr TSRMLS_DC);
+ zval *callback;
+ void *userdata;
+} MYSQLND_INFILE;
+
+typedef struct st_mysqlnd_option
+{
+ /* timeouts */
+ uint timeout_connect;
+ uint timeout_read;
+ uint timeout_write;
+
+ ulong flags;
+
+ /* init commands - we need to send them to server directly after connect */
+ uint num_commands;
+ char **init_commands;
+
+ /* configuration file information */
+ char *cfg_file;
+ char *cfg_section;
+
+ /* SSL information */
+ char *ssl_key;
+ char *ssl_cert;
+ char *ssl_ca;
+ char *ssl_capath;
+ char *ssl_cipher;
+ zend_bool use_ssl;
+
+ char *charset_name;
+ /* maximum allowed packet size for communication */
+ ulong max_allowed_packet;
+
+ zend_bool numeric_and_datetime_as_unicode;
+#ifdef MYSQLND_STRING_TO_INT_CONVERSION
+ zend_bool int_and_year_as_int;
+#endif
+ unsigned int net_read_buffer_size;
+} MYSQLND_OPTION;
+
+
+typedef struct st_mysqlnd_connection MYSQLND;
+typedef struct st_mysqlnd_res MYSQLND_RES;
+typedef char** MYSQLND_ROW; /* return data as array of strings */
+typedef struct st_mysqlnd_stmt MYSQLND_STMT;
+typedef unsigned int MYSQLND_FIELD_OFFSET;
+
+typedef struct st_mysqlnd_param_bind MYSQLND_PARAM_BIND;
+
+typedef struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND;
+
+typedef struct st_mysqlnd_result_metadata MYSQLND_RES_METADATA;
+typedef struct st_mysqlnd_buffered_result MYSQLND_RES_BUFFERED;
+typedef struct st_mysqlnd_unbuffered_result MYSQLND_RES_UNBUFFERED;
+
+typedef struct st_mysqlnd_debug MYSQLND_DEBUG;
+
+
+typedef MYSQLND_RES* (*mysqlnd_stmt_use_or_store_func)(MYSQLND_STMT * const TSRMLS_DC);
+typedef enum_func_status (*mysqlnd_fetch_row_func)(MYSQLND_RES *result,
+ void *param,
+ unsigned int flags,
+ zend_bool *fetched_anything
+ TSRMLS_DC);
+
+typedef struct st_mysqlnd_stats
+{
+ my_uint64 values[STAT_LAST];
+#ifdef ZTS
+ MUTEX_T LOCK_access;
+#endif
+} MYSQLND_STATS;
+
+
+typedef struct st_mysqlnd_net
+{
+ php_stream *stream;
+ /* sequence for simple checking of correct packets */
+ zend_uchar packet_no;
+
+#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
+ zend_uchar last_command;
+#endif
+
+ /* cmd buffer */
+ MYSQLND_CMD_BUFFER cmd_buffer;
+} MYSQLND_NET;
+
+
+struct st_mysqlnd_conn_methods
+{
+ ulong (*escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, int escapestr_len TSRMLS_DC);
+ enum_func_status (*set_charset)(MYSQLND * const conn, const char * const charset TSRMLS_DC);
+ enum_func_status (*query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC);
+ MYSQLND_RES * (*use_result)(MYSQLND * const conn TSRMLS_DC);
+ MYSQLND_RES * (*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);
+
+ MYSQLND_STMT * (*stmt_init)(MYSQLND * const conn TSRMLS_DC);
+
+ enum_func_status (*shutdown_server)(MYSQLND * const conn, unsigned long level TSRMLS_DC);
+ enum_func_status (*refresh_server)(MYSQLND * const conn, unsigned long options TSRMLS_DC);
+
+ enum_func_status (*ping)(MYSQLND * const conn TSRMLS_DC);
+ enum_func_status (*kill_connection)(MYSQLND *conn, unsigned int pid TSRMLS_DC);
+ enum_func_status (*select_db)(MYSQLND * const conn, const char * const db, unsigned int db_len TSRMLS_DC);
+ enum_func_status (*server_dump_debug_information)(MYSQLND * const conn TSRMLS_DC);
+ enum_func_status (*change_user)(MYSQLND * const conn, const char * user, const char * passwd, const char * db TSRMLS_DC);
+
+ unsigned int (*get_error_no)(const MYSQLND * const conn);
+ const char * (*get_error_str)(const MYSQLND * const conn);
+ const char * (*get_sqlstate)(const MYSQLND * const conn);
+ mynd_ulonglong (*get_thread_id)(const MYSQLND * const conn);
+ void (*get_statistics)(const MYSQLND * const conn, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
+
+ unsigned long (*get_server_version)(const MYSQLND * const conn);
+ const char * (*get_server_information)(const MYSQLND * const conn);
+ enum_func_status (*get_server_statistics)(MYSQLND *conn, char **message, unsigned int * message_len TSRMLS_DC);
+ const char * (*get_host_information)(const MYSQLND * const conn);
+ unsigned int (*get_protocol_information)(const MYSQLND * const conn);
+ const char * (*get_last_message)(const MYSQLND * const conn);
+ const char * (*charset_name)(const MYSQLND * const conn);
+ MYSQLND_RES * (*list_fields)(MYSQLND *conn, const char *table, const char *achtung_wild TSRMLS_DC);
+ MYSQLND_RES * (*list_method)(MYSQLND *conn, const char *query, const char *achtung_wild, char *par1 TSRMLS_DC);
+
+ mynd_ulonglong (*get_last_insert_id)(const MYSQLND * const conn);
+ mynd_ulonglong (*get_affected_rows)(const MYSQLND * const conn);
+ unsigned int (*get_warning_count)(const MYSQLND * const conn);
+
+ unsigned int (*get_field_count)(const MYSQLND * const conn);
+
+ enum_func_status (*set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC);
+ enum_func_status (*set_client_option)(MYSQLND * const conn, enum_mysqlnd_option option, const char * const value TSRMLS_DC);
+ void (*free_contents)(MYSQLND *conn TSRMLS_DC); /* private */
+ 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);
+ enum_func_status (*free_reference)(MYSQLND * const conn TSRMLS_DC);
+};
+
+
+struct st_mysqlnd_res_methods
+{
+ mysqlnd_fetch_row_func fetch_row;
+ mysqlnd_fetch_row_func fetch_row_normal_buffered; /* private */
+ mysqlnd_fetch_row_func fetch_row_normal_unbuffered; /* private */
+
+ MYSQLND_RES * (*use_result)(MYSQLND_RES * const result, zend_bool ps_protocol TSRMLS_DC);
+ MYSQLND_RES * (*store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps TSRMLS_DC);
+ void (*fetch_into)(MYSQLND_RES *result, unsigned int flags, zval *return_value, enum_mysqlnd_extension ext TSRMLS_DC ZEND_FILE_LINE_DC);
+ void (*fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
+ void (*fetch_field_data)(MYSQLND_RES *result, unsigned int offset, zval *return_value TSRMLS_DC);
+ mynd_ulonglong (*num_rows)(const MYSQLND_RES * const result);
+ unsigned int (*num_fields)(const MYSQLND_RES * const result);
+ enum_func_status (*skip_result)(MYSQLND_RES * const result TSRMLS_DC);
+ enum_func_status (*seek_data)(MYSQLND_RES * result, mynd_ulonglong row TSRMLS_DC);
+ MYSQLND_FIELD_OFFSET (*seek_field)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET field_offset);
+ MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES * const result);
+ MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES * const result TSRMLS_DC);
+ MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC);
+
+ enum_func_status (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC);
+ unsigned long * (*fetch_lengths)(MYSQLND_RES * const result);
+ void (*free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
+ enum_func_status (*free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
+ void (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
+ void (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
+};
+
+
+struct st_mysqlnd_res_meta_methods
+{
+ MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC);
+ MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC);
+ MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES_METADATA * const meta);
+ enum_func_status (*read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND *conn TSRMLS_DC);
+ MYSQLND_RES_METADATA * (*clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent TSRMLS_DC);
+ void (*free_metadata)(MYSQLND_RES_METADATA *meta, zend_bool persistent TSRMLS_DC);
+};
+
+
+struct st_mysqlnd_stmt_methods
+{
+ enum_func_status (*prepare)(MYSQLND_STMT * const stmt, const char * const query, unsigned int query_len TSRMLS_DC);
+ enum_func_status (*execute)(MYSQLND_STMT * const stmt TSRMLS_DC);
+ MYSQLND_RES * (*use_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
+ MYSQLND_RES * (*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
+ MYSQLND_RES * (*get_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, mynd_ulonglong 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 (*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);
+
+ enum_func_status (*bind_param)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC);
+ enum_func_status (*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const 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);
+ MYSQLND_RES * (*get_parameter_metadata)(MYSQLND_STMT * const stmt);
+ MYSQLND_RES * (*get_result_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC);
+
+ mynd_ulonglong (*get_last_insert_id)(const MYSQLND_STMT * const stmt);
+ mynd_ulonglong (*get_affected_rows)(const MYSQLND_STMT * const stmt);
+ mynd_ulonglong (*get_num_rows)(const MYSQLND_STMT * const stmt);
+
+ unsigned int (*get_param_count)(const MYSQLND_STMT * const stmt);
+ unsigned int (*get_field_count)(const MYSQLND_STMT * const stmt);
+ unsigned int (*get_warning_count)(const MYSQLND_STMT * const stmt);
+
+ unsigned int (*get_error_no)(const MYSQLND_STMT * const stmt);
+ 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 (*set_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, const void * const value TSRMLS_DC);
+};
+
+
+struct st_mysqlnd_connection
+{
+/* Operation related */
+ MYSQLND_NET net;
+
+/* Information related */
+ char *host;
+ char *unix_socket;
+ char *user;
+ char *passwd;
+ unsigned int *passwd_len;
+ char *scheme;
+ unsigned long long thread_id;
+ char *server_version;
+ char *host_info;
+ unsigned char *scramble;
+ const MYSQLND_CHARSET *charset;
+ const MYSQLND_CHARSET *greet_charset;
+ MYSQLND_INFILE infile;
+ unsigned int protocol_version;
+ unsigned long max_packet_size;
+ unsigned int port;
+ unsigned long client_flag;
+ unsigned long server_capabilities;
+
+ int tmp_int;
+
+
+ /* For UPSERT queries */
+ mysqlnd_upsert_status upsert_status;
+ char *last_message;
+ unsigned int last_message_len;
+
+ /* If error packet, we use these */
+ mysqlnd_error_info error_info;
+
+ /*
+ To prevent queries during unbuffered fetches. Also to
+ mark the connection as destroyed for garbage collection.
+ */
+ enum mysqlnd_connection_state state;
+ enum_mysqlnd_query_type last_query_type;
+ /* Temporary storage between query and (use|store)_result() call */
+ MYSQLND_RES *current_result;
+
+ /*
+ How many result sets reference this connection.
+ It won't be freed until this number reaches 0.
+ The last one, please close the door! :-)
+ The result set objects can determine by inspecting
+ 'quit_sent' whether the connection is still valid.
+ */
+ unsigned int refcount;
+
+ /* Temporal storage for mysql_query */
+ unsigned int field_count;
+
+ /* persistent connection */
+ zend_bool persistent;
+
+ /* options */
+ MYSQLND_OPTION options;
+
+ /* zval cache */
+ MYSQLND_THD_ZVAL_PCACHE *zval_cache;
+
+ /* qcache */
+ MYSQLND_QCACHE *qcache;
+
+ /* stats */
+ MYSQLND_STATS stats;
+
+ struct st_mysqlnd_conn_methods *m;
+};
+
+typedef struct st_php_mysql_packet_row php_mysql_packet_row;
+
+
+struct mysqlnd_field_hash_key
+{
+ zend_bool is_numeric;
+ unsigned long key;
+#if PHP_MAJOR_VERSION >= 6
+ zstr ustr;
+ unsigned int ulen;
+#endif
+};
+
+
+struct st_mysqlnd_result_metadata
+{
+ MYSQLND_FIELD *fields;
+ struct mysqlnd_field_hash_key *zend_hash_keys;
+ unsigned int current_field;
+ unsigned int field_count;
+ /* We need this to make fast allocs in rowp_read */
+ unsigned int bit_fields_count;
+ size_t bit_fields_total_len; /* trailing \0 not counted */
+
+ struct st_mysqlnd_res_meta_methods *m;
+};
+
+
+struct st_mysqlnd_buffered_result
+{
+ zval ***data;
+ zval ***data_cursor;
+ zend_uchar **row_buffers;
+ mynd_ulonglong row_count;
+ zend_bool persistent;
+
+ MYSQLND_QCACHE *qcache;
+ unsigned int references;
+
+ zend_bool async_invalid;
+ mysqlnd_error_info error_info;
+};
+
+
+struct st_mysqlnd_unbuffered_result
+{
+ /* For unbuffered (both normal and PS) */
+ zval **last_row_data;
+ zend_uchar *last_row_buffer;
+
+ mynd_ulonglong row_count;
+ zend_bool eof_reached;
+};
+
+
+struct st_mysqlnd_res
+{
+ struct st_mysqlnd_res_methods m;
+
+ MYSQLND *conn;
+ enum_mysqlnd_res_type type;
+ unsigned int field_count;
+
+ /* For metadata functions */
+ MYSQLND_RES_METADATA *meta;
+
+ /* To be used with store_result() - both normal and PS */
+ MYSQLND_RES_BUFFERED *data;
+
+ MYSQLND_RES_UNBUFFERED *unbuf;
+
+ /*
+ Column lengths of current row - both buffered and unbuffered.
+ For buffered results it duplicates the data found in **data
+ */
+ unsigned long *lengths;
+
+ php_mysql_packet_row *row_packet; /* Unused for PS */
+
+ /* zval cache */
+ MYSQLND_THD_ZVAL_PCACHE *zval_cache;
+};
+
+
+struct st_mysqlnd_param_bind
+{
+ zval *zv;
+ zend_uchar type;
+ enum_param_bind_flags flags;
+};
+
+struct st_mysqlnd_result_bind
+{
+ zval *zv;
+ zend_uchar original_type;
+ zend_bool bound;
+};
+
+
+struct st_mysqlnd_stmt
+{
+ MYSQLND *conn;
+ unsigned long stmt_id;
+ unsigned long flags;/* cursor is set here */
+ enum_mysqlnd_stmt_state state;
+ unsigned int warning_count;
+ MYSQLND_RES *result;
+ unsigned int field_count;
+ unsigned int param_count;
+ unsigned char send_types_to_server;
+ MYSQLND_PARAM_BIND *param_bind;
+ MYSQLND_RESULT_BIND *result_bind;
+ zend_bool result_zvals_separated_once;
+
+ mysqlnd_upsert_status upsert_status;
+
+ mysqlnd_error_info error_info;
+
+ zend_bool update_max_length;
+ unsigned long prefetch_rows;
+
+ zend_bool cursor_exists;
+ mysqlnd_stmt_use_or_store_func default_rset_handler;
+
+ MYSQLND_CMD_BUFFER cmd_buffer;
+ unsigned int execute_count;/* count how many times the stmt was executed */
+
+ struct st_mysqlnd_stmt_methods *m;
+};
+
+#endif /* MYSQLND_STRUCTS_H */
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_statistics.h"
#include "mysqlnd_palloc.h"
+#include "mysqlnd_debug.h"
#include "ext/standard/sha1.h"
#include "php_network.h"
+#include "zend_ini.h"
+
#ifndef PHP_WIN32
#include <netinet/tcp.h>
#else
-
+#include <winsock.h>
#endif
+
#define USE_CORK 0
-#define MYSQLND_SILENT
+#define MYSQLND_SILENT 1
+
#define MYSQLND_DUMP_HEADER_N_BODY2
#define MYSQLND_DUMP_HEADER_N_BODY_FULL2
#define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type) \
{ \
if (FAIL == mysqlnd_read_header((conn), &((packet)->header) TSRMLS_CC)) {\
- return FAIL;\
+ conn->state = CONN_QUIT_SENT; \
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
+ DBG_ERR_FMT("Can't read %s's header", (packet_type)); \
+ DBG_RETURN(FAIL);\
}\
if ((buf_size) < (packet)->header.size) { \
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Packet buffer wasn't big enough" \
- "%u bytes will be unread", (packet)->header.size - (buf_size));\
+ DBG_ERR_FMT("Packet buffer wasn't big enough %u bytes will be unread", \
+ (packet)->header.size - (buf_size)); \
}\
if (!mysqlnd_read_body((conn), (buf), \
MIN((buf_size), (packet)->header.size) TSRMLS_CC)) { \
- php_error(E_WARNING, "Empty %s packet body", (packet_type));\
- return FAIL; \
+ conn->state = CONN_QUIT_SENT; \
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
+ DBG_ERR_FMT("Empty %s packet body", (packet_type)); \
+ DBG_RETURN(FAIL);\
} \
}
char * const mysqlnd_empty_string = "";
+/* Used in mysqlnd_debug.c */
+char * mysqlnd_read_header_name = "mysqlnd_read_header";
+char * mysqlnd_read_body_name = "mysqlnd_read_body";
+
/* {{{ mysqlnd_command_to_text
*/
int opt = PHP_STREAM_OPTION_BLOCKING;
int was_blocked = net->stream->ops->set_option(net->stream, opt, 0, NULL TSRMLS_CC);
+ DBG_ENTER("php_mysqlnd_consume_uneaten_data");
+
if (PHP_STREAM_OPTION_RETURN_ERR != was_blocked) {
/* Do a read of 1 byte */
int bytes_consumed;
}
if (bytes_consumed) {
+ DBG_ERR_FMT("Skipped %u bytes. Last command %s hasn't consumed all the output from the server",
+ bytes_consumed, mysqlnd_command_to_text[net->last_command]);
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Skipped %u bytes. Last command %s hasn't "
- "consumed all the output from the server",
- bytes_consumed, mysqlnd_command_to_text[net->last_command]);
+ "consumed all the output from the server. PID=%d",
+ bytes_consumed, mysqlnd_command_to_text[net->last_command], getpid());
}
}
net->last_command = cmd;
- return skipped_bytes;
+ DBG_RETURN(skipped_bytes);
}
#endif
/* }}} */
+
/* {{{ php_mysqlnd_read_error_from_line */
static
enum_func_status php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len,
char *error, int error_buf_len,
- unsigned int *error_no, char *sqlstate)
+ unsigned int *error_no, char *sqlstate TSRMLS_DC)
{
zend_uchar *p = buf;
int error_msg_len= 0;
+
+ DBG_ENTER("php_mysqlnd_read_error_from_line");
+
if (buf_len > 2) {
*error_no = uint2korr(p);
p+= 2;
}
sqlstate[MYSQLND_SQLSTATE_LENGTH] = '\0';
error[error_msg_len]= '\0';
- return FAIL;
+
+ DBG_RETURN(FAIL);
}
/* }}} */
/* {{{ mysqlnd_set_sock_no_delay */
int mysqlnd_set_sock_no_delay(php_stream *stream)
{
+
int socketd = ((php_netstream_data_t*)stream->abstract)->socket;
int ret = SUCCESS;
int flag = 1;
int result = setsockopt(socketd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int));
+ TSRMLS_FETCH();
+
+ DBG_ENTER("mysqlnd_set_sock_no_delay");
+
if (result == -1) {
ret = FAILURE;
}
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC)
{
zend_uchar safe_buf[((MYSQLND_HEADER_SIZE) + (sizeof(zend_uchar)) - 1) / (sizeof(zend_uchar))];
- zend_uchar *safe_storage = (char *) &safe_buf;
+ zend_uchar *safe_storage = safe_buf;
MYSQLND_NET *net = &conn->net;
size_t old_chunk_size = net->stream->chunk_size;
size_t ret, left = count, packets_sent = 1;
zend_uchar *p = (zend_uchar *) buf;
+ DBG_ENTER("mysqlnd_stream_write_w_header");
+ DBG_INF_FMT("conn=%llu count=%lu", conn->thread_id, count);
+
net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE;
while (left > MYSQLND_MAX_PACKET_SIZE) {
ret = php_stream_write(net->stream, (char *)p, left + MYSQLND_HEADER_SIZE);
RESTORE_HEADER_SIZE(p, safe_storage);
+ if (!ret) {
+ DBG_ERR_FMT("Can't %u send bytes", count);
+ conn->state = CONN_QUIT_SENT;
+ SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
+ }
+
MYSQLND_INC_CONN_STATISTIC_W_VALUE3(&conn->stats,
STAT_BYTES_SENT, count + packets_sent * MYSQLND_HEADER_SIZE,
STAT_PROTOCOL_OVERHEAD_OUT, packets_sent * MYSQLND_HEADER_SIZE,
net->stream->chunk_size = old_chunk_size;
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
zend_bool command_sent = FALSE;
int corked = 1;
+ DBG_ENTER("mysqlnd_stream_write_w_command");
+
net->stream->chunk_size = MYSQLND_MAX_PACKET_SIZE;
setsockopt(((php_netstream_data_t*)net->stream->abstract)->socket,
net->stream->chunk_size = old_chunk_size;
- return ret;
+ DBG_RETURN(ret);
}
#endif
/* }}} */
char *p = buffer;
int to_read = MYSQLND_HEADER_SIZE, ret;
+ DBG_ENTER(mysqlnd_read_header_name);
+
do {
if (!(ret= php_stream_read(net->stream, p, to_read))) {
- php_error(E_WARNING, "Error while reading header from socket");
+ DBG_ERR_FMT("Error while reading header from socket");
return FAIL;
}
p += ret;
*/
net->packet_no++;
#ifdef MYSQLND_DUMP_HEADER_N_BODY
- php_printf("\nHEADER: packet_no=%d size=%3d\n", header->packet_no, header->size);
+ DBG_ERR_FMT("HEADER: packet_no=%d size=%3d", header->packet_no, header->size);
#endif
- return PASS;
+ DBG_RETURN(PASS);
}
- php_error(E_WARNING, "Packets out of order. Expected %d received %d. Packet size=%d",
- net->packet_no, header->packet_no, header->size);
- return FAIL;
+#if !MYSQLND_SILENT
+ DBG_ERR_FMT("Packets out of order. Expected %d received %d. Packet size=%d",
+ net->packet_no, header->packet_no, header->size);
+#endif
+ php_error(E_WARNING, "Packets out of order. Expected %d received %d. Packet size=%d. PID=%d",
+ net->packet_no, header->packet_no, header->size, getpid());
+ DBG_RETURN(FAIL);
}
/* }}} */
{
size_t ret;
char *p = (char *)buf;
-#ifdef MYSQLND_DUMP_HEADER_N_BODY
int iter = 0;
-#endif
MYSQLND_NET *net = &conn->net;
+ size_t old_chunk_size = net->stream->chunk_size;
+ DBG_ENTER(mysqlnd_read_body_name);
+ DBG_INF_FMT("chunk_size=%d", net->stream->chunk_size);
+
+ net->stream->chunk_size = MIN(size, conn->options.net_read_buffer_size);
do {
size -= (ret = php_stream_read(net->stream, p, size));
-#ifdef MYSQLND_DUMP_HEADER_N_BODY
if (size || iter++) {
- php_printf("read=%d buf=%p p=%p chunk_size=%d left=%d\n",
+ DBG_INF_FMT("read=%d buf=%p p=%p chunk_size=%d left=%d",
ret, buf, p , net->stream->chunk_size, size);
}
-#endif
p += ret;
} while (size > 0);
MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_BYTES_RECEIVED, p - (char*)buf);
+ net->stream->chunk_size = old_chunk_size;
#ifdef MYSQLND_DUMP_HEADER_N_BODY_FULL
{
int i;
- php_printf("\tBODY: requested=%d last_read=%3d\n\t", p - (char*)buf, ret);
- for (i = 0 ; i < p - (char*)buf; i++) printf("[%c]", *(char *)(&(buf[i]))); php_printf("\n\t");
- for (i = 0 ; i < p - (char*)buf; i++) printf("%.2X ", (int)*((char*)&(buf[i])));php_printf("\n-=-=-=-=-\n");
+ DBG_INF_FMT("BODY: requested=%d last_read=%3d", p - (char*)buf, ret);
+ for (i = 0 ; i < p - (char*)buf; i++) {
+ if (i && (i % 30 == 0)) {
+ printf("\n\t\t");
+ }
+ printf("[%c] ", *(char *)(&(buf[i])));
+ }
+ for (i = 0 ; i < p - (char*)buf; i++) {
+ if (i && (i % 30 == 0)) {
+ printf("\n\t\t");
+ }
+ printf("%.2X ", (int)*((char*)&(buf[i])));
+ }
+ php_printf("\n\t\t\t-=-=-=-=-\n");
}
#endif
- return p - (char*)buf;
+ DBG_RETURN(p - (char*)buf);
}
/* }}} */
zend_uchar *begin = buf;
php_mysql_packet_greet *packet= (php_mysql_packet_greet *) _packet;
+ DBG_ENTER("php_mysqlnd_greet_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "greeting");
packet->protocol_version = uint1korr(p);
if (packet->protocol_version == 0xFF) {
php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
packet->error, sizeof(packet->error),
- &packet->error_no, packet->sqlstate);
+ &packet->error_no, packet->sqlstate
+ TSRMLS_CC);
/*
The server doesn't send sqlstate in the greet packet.
It's a bug#26426 , so we have to set it correctly ourselves.
if (packet->error_no == 1040) {
memcpy(packet->sqlstate, "08004", MYSQLND_SQLSTATE_LENGTH);
}
- return PASS;
-
+ DBG_RETURN(PASS);
}
packet->server_version = pestrdup((char *)p, conn->persistent);
packet->pre41 = TRUE;
}
if (p - begin > packet->header.size) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet %d bytes shorter than expected",
- 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",
+ p - begin - packet->header.size, getpid());
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_greet_free_mem */
static
-void php_mysqlnd_greet_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_greet_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_greet *p= (php_mysql_packet_greet *) _packet;
if (p->server_version) {
- efree(p->server_version);
+ mnd_efree(p->server_version);
p->server_version = NULL;
}
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
int len;
register php_mysql_packet_auth *packet= (php_mysql_packet_auth *) _packet;
+ DBG_ENTER("php_mysqlnd_auth_write");
+
packet->client_flags |= MYSQLND_CAPABILITIES;
if (packet->db) {
/* Handle CLIENT_CONNECT_WITH_DB */
/* no \0 for no DB */
- return mysqlnd_stream_write_w_header(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC);
+ DBG_RETURN(mysqlnd_stream_write_w_header(conn, buffer, p - buffer - MYSQLND_HEADER_SIZE TSRMLS_CC));
}
/* }}} */
/* {{{ php_mysqlnd_auth_free_mem */
static
-void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
if (!alloca) {
- efree((php_mysql_packet_auth *) _packet);
+ mnd_efree((php_mysql_packet_auth *) _packet);
}
}
/* }}} */
int i;
register php_mysql_packet_ok *packet= (php_mysql_packet_ok *) _packet;
+ DBG_ENTER("php_mysqlnd_ok_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "OK");
/* Should be always 0x0 or 0xFF for error */
if (0xFF == packet->field_count) {
php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
packet->error, sizeof(packet->error),
- &packet->error_no, packet->sqlstate);
- return PASS;
+ &packet->error_no, packet->sqlstate
+ TSRMLS_CC);
+ DBG_RETURN(PASS);
}
/* Everything was fine! */
packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
packet->message = NULL;
}
-#ifndef MYSQLND_SILENT
- php_printf("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%d warnings=%d\n",
- packet->affected_rows, packet->last_insert_id, packet->server_status,
- packet->warning_count);
-#endif
+ 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);
+
if (p - begin > packet->header.size) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "OK packet %d bytes shorter than expected",
- p - begin - packet->header.size);
+ DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin - packet->header.size);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "OK packet %d bytes shorter than expected. PID=%d",
+ p - begin - packet->header.size, getpid());
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_ok_free_mem */
static
-void php_mysqlnd_ok_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_ok_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_ok *p= (php_mysql_packet_ok *) _packet;
if (p->message) {
- efree(p->message);
+ mnd_efree(p->message);
p->message = NULL;
}
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
zend_uchar *p= buf;
zend_uchar *begin = buf;
+ DBG_ENTER("php_mysqlnd_eof_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "EOF");
/* Should be always 0xFE */
if (0xFF == packet->field_count) {
php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
packet->error, sizeof(packet->error),
- &packet->error_no, packet->sqlstate);
- return PASS;
+ &packet->error_no, packet->sqlstate
+ TSRMLS_CC);
+ DBG_RETURN(PASS);
}
/*
}
if (p - begin > packet->header.size) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet %d bytes shorter than expected",
- p - begin - packet->header.size);
+ DBG_ERR_FMT("EOF packet %d bytes shorter than expected", p - begin - packet->header.size);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "EOF packet %d bytes shorter than expected. PID=%d",
+ p - begin - packet->header.size, getpid());
}
-#ifndef MYSQLND_SILENT
- php_printf("EOF packet: server_status=%d warnings=%d\n",
- packet->server_status, packet->warning_count);
-#endif
+ DBG_INF_FMT("EOF packet: status=%d warnings=%d", packet->server_status, packet->warning_count);
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_eof_free_mem */
static
-void php_mysqlnd_eof_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_eof_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
if (!alloca) {
- efree(_packet);
+ mnd_efree(_packet);
}
}
/* }}} */
/* Let's have some space, which we can use, if not enough, we will allocate new buffer */
php_mysql_packet_command *packet= (php_mysql_packet_command *) _packet;
MYSQLND_NET *net = &conn->net;
+ unsigned int error_reporting = EG(error_reporting);
+ size_t written;
+ DBG_ENTER("php_mysqlnd_cmd_write");
/*
Reset packet_no, or we will get bad handshake!
Every command starts a new TX and packet numbers are reset to 0.
*/
net->packet_no = 0;
+ if (error_reporting) {
+ EG(error_reporting) = 0;
+ }
+
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
php_mysqlnd_consume_uneaten_data(conn, packet->command TSRMLS_CC);
#endif
char buffer[MYSQLND_HEADER_SIZE + 1];
int1store(buffer + MYSQLND_HEADER_SIZE, packet->command);
- return mysqlnd_stream_write_w_header(conn, buffer, 1 TSRMLS_CC);
+ written = mysqlnd_stream_write_w_header(conn, buffer, 1 TSRMLS_CC);
} else {
#if USE_CORK && defined(TCP_CORK)
- return mysqlnd_stream_write_w_command(conn, packet->command, packet->argument, packet->arg_len TSRMLS_CC);
+ written = mysqlnd_stream_write_w_command(conn, packet->command, packet->argument,
+ packet->arg_len TSRMLS_CC));
#else
size_t tmp_len = packet->arg_len + 1 + MYSQLND_HEADER_SIZE, ret;
zend_uchar *tmp, *p;
- tmp = (tmp_len > net->cmd_buffer.length)? emalloc(tmp_len):net->cmd_buffer.buffer;
+ tmp = (tmp_len > net->cmd_buffer.length)? mnd_emalloc(tmp_len):net->cmd_buffer.buffer;
p = tmp + MYSQLND_HEADER_SIZE; /* skip the header */
int1store(p, packet->command);
ret = mysqlnd_stream_write_w_header(conn, (char *)tmp, tmp_len - MYSQLND_HEADER_SIZE TSRMLS_CC);
if (tmp != net->cmd_buffer.buffer) {
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CMD_BUFFER_TOO_SMALL);
- efree(tmp);
+ mnd_efree(tmp);
}
- return ret;
+ written = ret;
#endif
}
+ if (error_reporting) {
+ /* restore error reporting */
+ EG(error_reporting) = error_reporting;
+ }
+ DBG_RETURN(written);
}
/* }}} */
/* {{{ php_mysqlnd_cmd_free_mem */
static
-void php_mysqlnd_cmd_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_cmd_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
if (!alloca) {
- efree((php_mysql_packet_command *) _packet);
+ mnd_efree((php_mysql_packet_command *) _packet);
}
}
/* }}} */
size_t len;
php_mysql_packet_rset_header *packet= (php_mysql_packet_rset_header *) _packet;
+ DBG_ENTER("php_mysqlnd_rset_header_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "resultset header");
/*
p++;
php_mysqlnd_read_error_from_line(p, packet->header.size - 1,
packet->error_info.error, sizeof(packet->error_info.error),
- &packet->error_info.error_no, packet->error_info.sqlstate);
- return PASS;
+ &packet->error_info.error_no, packet->error_info.sqlstate
+ TSRMLS_CC);
+ DBG_RETURN(PASS);
}
packet->field_count= php_mysqlnd_net_field_length(&p);
Thus, the name is size - 1. And we add 1 for a trailing \0.
*/
len = packet->header.size - 1;
- packet->info_or_local_file = pemalloc(len + 1, conn->persistent);
+ packet->info_or_local_file = mnd_pemalloc(len + 1, conn->persistent);
memcpy(packet->info_or_local_file, p, len);
packet->info_or_local_file[len] = '\0';
packet->info_or_local_file_len = len;
p+=2;
/* Check for additional textual data */
if (packet->header.size > (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
- packet->info_or_local_file = pemalloc(len + 1, conn->persistent);
+ packet->info_or_local_file = mnd_pemalloc(len + 1, conn->persistent);
memcpy(packet->info_or_local_file, p, len);
packet->info_or_local_file[len] = '\0';
packet->info_or_local_file_len = len;
break;
}
if (p - begin > packet->header.size) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet %d bytes shorter than expected",
- 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",
+ p - begin - packet->header.size, getpid());
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_rset_header_free_mem */
static
-void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_rset_header *p= (php_mysql_packet_rset_header *) _packet;
if (p->info_or_local_file) {
- efree(p->info_or_local_file);
+ mnd_efree(p->info_or_local_file);
p->info_or_local_file = NULL;
}
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
MYSQLND_FIELD *meta;
unsigned int i, field_count = sizeof(rset_field_offsets)/sizeof(size_t);
+ DBG_ENTER("php_mysqlnd_rset_field_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_len, "field");
if (packet->skip_parsing) {
- return PASS;
+ DBG_RETURN(PASS);
+ }
+ if (*p == 0xFE && packet->header.size < 8) {
+ /* Premature EOF. That should be COM_FIELD_LIST */
+ DBG_INF("Premature EOF. That should be COM_FIELD_LIST");
+ packet->stupid_list_fields_eof = TRUE;
+ DBG_RETURN(PASS);
}
meta = packet->metadata;
for (i = 0; i < field_count; i += 2) {
- switch ((len = php_mysqlnd_net_field_length(&p))) {
+ len = php_mysqlnd_net_field_length(&p);
+ switch ((len)) {
case 0:
*(char **)(((char*)meta) + rset_field_offsets[i]) = mysqlnd_empty_string;
*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
case MYSQLND_NULL_LENGTH:
goto faulty_fake;
default:
- *(char **)(((char *)meta) + rset_field_offsets[i]) = p;
+ *(char **)(((char *)meta) + rset_field_offsets[i]) = (char *)p;
*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
p += len;
total_len += len + 1;
}
- /* def could be empty, thus don't allocate on the root */
- if (packet->header.size > (p - buf) && (len = php_mysqlnd_net_field_length(&p))) {
- meta->def = emalloc(len + 1);
+ /*
+ def could be empty, thus don't allocate on the root.
+ NULL_LENGTH (0xFB) comes from COM_FIELD_LIST when the default value is NULL.
+ Otherwise the string is length encoded.
+ */
+ if (packet->header.size > (p - buf) &&
+ (len = php_mysqlnd_net_field_length(&p)) &&
+ len != MYSQLND_NULL_LENGTH)
+ {
+ DBG_INF_FMT("Def found, length %lu", len);
+ meta->def = mnd_emalloc(len + 1);
memcpy(meta->def, p, len);
meta->def[len] = '\0';
meta->def_length = len;
}
if (p - begin > packet->header.size) {
+ DBG_ERR_FMT("Result set 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", p - begin - packet->header.size);
+ "shorter than expected. PID=%d", p - begin - packet->header.size, getpid());
}
- root_ptr = meta->root = emalloc(total_len);
+ root_ptr = meta->root = mnd_emalloc(total_len);
meta->root_len = total_len;
/* Now do allocs */
if (meta->catalog && meta->catalog != mysqlnd_empty_string) {
*(root_ptr +=len) = '\0';
root_ptr++;
}
-
-#ifndef MYSQLND_SILENT
- php_printf("\tFIELD=[%s.%s.%s]\n", meta->db? meta->db:"*NA*",
- meta->table? meta->table:"*NA*",
- meta->name? meta->name:"*NA*");
-#endif
-
- return PASS;
+/*
+ DBG_INF_FMT("FIELD=[%s.%s.%s]", meta->db? meta->db:"*NA*", meta->table? meta->table:"*NA*",
+ meta->name? meta->name:"*NA*");
+*/
+ DBG_RETURN(PASS);
faulty_fake:
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol error. Server sent NULL_LENGTH.",
+ 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");
- return FAIL;
+ DBG_RETURN(FAIL);
}
/* }}} */
/* {{{ php_mysqlnd_rset_field_free_mem */
static
-void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_res_field *p= (php_mysql_packet_res_field *) _packet;
/* p->metadata was passed to us as temporal buffer */
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
mysqlnd_packet_header header;
zend_uchar *new_buf = NULL, *p = *buf;
zend_bool first_iteration = TRUE;
- MYSQLND_NET *net = &conn->net;
+
+ DBG_ENTER("php_mysqlnd_read_row_ex");
/*
To ease the process the server splits everything in packets up to 2^24 - 1.
We need a trailing \0 for the last string, in case of text-mode,
to be able to implement read-only variables. Thus, we add + 1.
*/
- p = new_buf = pemalloc(*data_size + 1, persistent_alloc);
- net->stream->chunk_size = header.size;
+ p = new_buf = mnd_pemalloc(*data_size + 1, persistent_alloc);
} else if (!first_iteration) {
/* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
if (!header.size) {
We need a trailing \0 for the last string, in case of text-mode,
to be able to implement read-only variables.
*/
- new_buf = perealloc(new_buf, *data_size + 1, persistent_alloc);
+ new_buf = mnd_perealloc(new_buf, *data_size + 1, persistent_alloc);
/* The position could have changed, recalculate */
p = new_buf + (*data_size - header.size);
}
if (!mysqlnd_read_body(conn, p, header.size TSRMLS_CC)) {
- php_error(E_WARNING, "Empty row packet body");
+ DBG_ERR("Empty row packet body");
+ php_error(E_WARNING, "Empty row packet body. PID=%d", getpid());
ret = FAIL;
break;
}
*buf = new_buf;
}
*data_size -= prealloc_more_bytes;
- return ret;
+ DBG_RETURN(ret);
}
zend_bool allocated;
void *obj;
+ DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
+
end_field = (current_field = start_field = packet->fields) + packet->field_count;
for (i = 0; current_field < end_field; current_field++, i++) {
#if 1
- obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated);
+ obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated TSRMLS_CC);
if (allocated) {
*current_field = (zval *) obj;
} else {
}
/* Normal queries: The buffer has one more byte at the end, because we need it */
packet->row_buffer[data_size] = '\0';
+
+ DBG_VOID_RETURN;
}
/* }}} */
zend_bool as_int = conn->options.int_and_year_as_int;
#endif
+ DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
+
end_field = (current_field = start_field = packet->fields) + packet->field_count;
for (i = 0; current_field < end_field; current_field++, i++) {
/* Don't reverse the order. It is significant!*/
/* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */
unsigned long len = php_mysqlnd_net_field_length(&p);
- obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated);
+ obj = mysqlnd_palloc_get_zval(conn->zval_cache, &allocated TSRMLS_CC);
if (allocated) {
*current_field = (zval *) obj;
} else {
ZVAL_NULL(*current_field);
last_field_was_string = FALSE;
} else {
+#if PHP_MAJOR_VERSION >= 6 || defined(MYSQLND_STRING_TO_INT_CONVERSION)
struct st_mysqlnd_perm_bind perm_bind =
mysqlnd_ps_fetch_functions[packet->fields_metadata[i].type];
+#endif
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
if (as_int && perm_bind.php_type == IS_LONG &&
} else
#endif
{
- ZVAL_STRINGL(*current_field, start, bit_area - start - 1, 0);
+ ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
+ }
+ if (allocated == FALSE) {
+ ((mysqlnd_zval *) obj)->point_type = MYSQLND_POINTS_INT_BUFFER;
}
} else if (Z_TYPE_PP(current_field) == IS_STRING){
memcpy(bit_area, Z_STRVAL_PP(current_field), Z_STRLEN_PP(current_field));
} else
#endif
{
- ZVAL_STRINGL(*current_field, start, bit_area - start - 1, 0);
+ ZVAL_STRINGL(*current_field, (char *) start, bit_area - start - 1, 0);
+ }
+ if (allocated == FALSE) {
+ ((mysqlnd_zval *) obj)->point_type = MYSQLND_POINTS_INT_BUFFER;
}
}
/*
IS_UNICODE should not be specially handled. In unicode mode
- the buffers are not pointed - everything is copied.
+ the buffers are not referenced - everything is copied.
*/
} else
#if PHP_MAJOR_VERSION < 6
/* Normal queries: The buffer has one more byte at the end, because we need it */
packet->row_buffer[data_size] = '\0';
}
+
+ DBG_VOID_RETURN;
}
/* }}} */
php_mysql_packet_row *packet= (php_mysql_packet_row *) _packet;
size_t post_alloc_for_bit_fields = 0;
+ DBG_ENTER("php_mysqlnd_rowp_read");
+
if (!packet->binary_protocol && packet->bit_fields_count) {
/* For every field we need terminating \0 */
post_alloc_for_bit_fields =
packet->error_info.error,
sizeof(packet->error_info.error),
&packet->error_info.error_no,
- packet->error_info.sqlstate);
+ packet->error_info.sqlstate
+ TSRMLS_CC);
} else if (*p == 0xFE && data_size < 8) { /* EOF */
packet->eof = TRUE;
p++;
/* Seems we have 3 bytes reserved for future use */
}
} else {
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_ROWS_FETCHED_FROM_SERVER);
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats,
+ packet->binary_protocol? STAT_ROWS_FETCHED_FROM_SERVER_PS:
+ STAT_ROWS_FETCHED_FROM_SERVER_NORMAL);
packet->eof = FALSE;
/* packet->field_count is set by the user of the packet */
if (!packet->skip_extraction) {
if (!packet->fields) {
+ DBG_INF("Allocating packet->fields");
/*
old-API will probably set packet->fields to NULL every time, though for
unbuffered sets it makes not much sense as the zvals in this buffer matter,
but mostly like old-API unbuffered and thus will populate this array with
value.
*/
- packet->fields = (zval **) pemalloc(packet->field_count * sizeof(zval *),
+ packet->fields = (zval **) mnd_pemalloc(packet->field_count * sizeof(zval *),
packet->persistent_alloc);
}
php_mysqlnd_rowp_read_text_protocol(packet, conn, p, data_size TSRMLS_CC);
}
} else {
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_ROWS_SKIPPED);
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats,
+ packet->binary_protocol? STAT_ROWS_SKIPPED_PS:
+ STAT_ROWS_SKIPPED_NORMAL);
}
}
end:
net->stream->chunk_size = old_chunk_size;
- return ret;
+ DBG_RETURN(ret);
}
/* }}} */
/* {{{ php_mysqlnd_rowp_free_mem */
static
-void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_row *p= (php_mysql_packet_row *) _packet;
if (p->row_buffer) {
- pefree(p->row_buffer, p->persistent_alloc);
+ mnd_pefree(p->row_buffer, p->persistent_alloc);
p->row_buffer = NULL;
}
/*
not free the array. As it is passed to us, we should not clean it ourselves.
*/
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
zend_uchar buf[1024];
php_mysql_packet_stats *packet= (php_mysql_packet_stats *) _packet;
+ DBG_ENTER("php_mysqlnd_stats_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "statistics");
- packet->message = pemalloc(packet->header.size + 1, conn->persistent);
+ packet->message = mnd_pemalloc(packet->header.size + 1, conn->persistent);
memcpy(packet->message, buf, packet->header.size);
packet->message[packet->header.size] = '\0';
packet->message_len = packet->header.size;
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_stats_free_mem */
static
-void php_mysqlnd_stats_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_stats_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_stats *p= (php_mysql_packet_stats *) _packet;
if (p->message) {
- efree(p->message);
+ mnd_efree(p->message);
p->message = NULL;
}
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
unsigned int data_size;
php_mysql_packet_prepare_response *packet= (php_mysql_packet_prepare_response *) _packet;
+ DBG_ENTER("php_mysqlnd_prepare_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "prepare");
data_size = packet->header.size;
packet->error_info.error,
sizeof(packet->error_info.error),
&packet->error_info.error_no,
- packet->error_info.sqlstate);
- return PASS;
+ packet->error_info.sqlstate
+ TSRMLS_CC);
+ DBG_RETURN(PASS);
}
if (data_size != PREPARE_RESPONSE_SIZE_41 &&
data_size != PREPARE_RESPONSE_SIZE_50 &&
!(data_size > PREPARE_RESPONSE_SIZE_50)) {
- php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %d", data_size);
- return FAIL;
+ DBG_ERR_FMT("Wrong COM_STMT_PREPARE response size. Received %d", data_size);
+ php_error(E_WARNING, "Wrong COM_STMT_PREPARE response size. Received %d. PID=%d", data_size, getpid());
+ DBG_RETURN(FAIL);
}
packet->stmt_id = uint4korr(p);
/* 0x0 filler sent by the server for 5.0+ clients */
p++;
- packet->warning_count= uint2korr(p);
+ packet->warning_count = uint2korr(p);
}
-#ifndef MYSQLND_SILENT
- php_printf("\tPrepare packet read: stmt_id=%d fields=%d params=%d\n",
+ DBG_INF_FMT("Prepare packet read: stmt_id=%d fields=%d params=%d",
packet->stmt_id, packet->field_count, packet->param_count);
-#endif
if (p - begin > packet->header.size) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "PREPARE packet %d bytes shorter than expected",
- p - begin - packet->header.size);
+ DBG_ERR_FMT("PREPARE packet %d bytes shorter than expected", p - begin - packet->header.size);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "PREPARE packet %d bytes shorter than expected. PID=%d",
+ p - begin - packet->header.size, getpid());
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_prepare_free_mem */
static
-void php_mysqlnd_prepare_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_prepare_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
php_mysql_packet_prepare_response *p= (php_mysql_packet_prepare_response *) _packet;
if (!alloca) {
- efree(p);
+ mnd_efree(p);
}
}
/* }}} */
zend_uchar *begin = buf;
php_mysql_packet_chg_user_resp *packet= (php_mysql_packet_chg_user_resp *) _packet;
+ DBG_ENTER("php_mysqlnd_chg_user_read");
+
PACKET_READ_HEADER_AND_BODY(packet, conn, buf, sizeof(buf), "change user response ");
/*
if (packet->header.size == 1 && buf[0] == 0xFE &&
packet->server_capabilities & CLIENT_SECURE_CONNECTION) {
/* We don't handle 3.23 authentication */
- return FAIL;
+ DBG_RETURN(FAIL);
}
if (0xFF == packet->field_count) {
packet->error_info.error,
sizeof(packet->error_info.error),
&packet->error_info.error_no,
- packet->error_info.sqlstate);
+ packet->error_info.sqlstate
+ TSRMLS_CC);
}
if (p - begin > packet->header.size) {
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "CHANGE_USER packet %d bytes shorter than expected",
- p - begin - packet->header.size);
+ DBG_ERR_FMT("CHANGE_USER packet %d bytes shorter than expected", p - begin - packet->header.size);
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "CHANGE_USER packet %d bytes shorter than expected. PID=%d",
+ p - begin - packet->header.size, getpid());
}
- return PASS;
+ DBG_RETURN(PASS);
}
/* }}} */
/* {{{ php_mysqlnd_chg_user_free_mem */
static
-void php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool alloca)
+void php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
{
if (!alloca) {
- efree(_packet);
+ mnd_efree(_packet);
}
}
/* }}} */
typedef zend_ushort mysqlnd_2b;
typedef zend_uint mysqlnd_4b;
+/* Used in mysqlnd_debug.c */
+extern char * mysqlnd_read_header_name;
+extern char * mysqlnd_read_body_name;
+
/* Packet handling */
#define PACKET_INIT(packet, enum_type, c_type) \
#define PACKET_READ(packet, conn) ((packet)->header.m->read_from_net((packet), (conn) TSRMLS_CC))
#define PACKET_FREE(packet) \
do { \
- ((packet)->header.m->free_mem((packet), FALSE)); \
+ ((packet)->header.m->free_mem((packet), FALSE TSRMLS_CC)); \
} while (0);
#define PACKET_INIT_ALLOCA(packet, enum_type) \
}
#define PACKET_WRITE_ALLOCA(packet, conn) PACKET_WRITE(&(packet), (conn))
#define PACKET_READ_ALLOCA(packet, conn) PACKET_READ(&(packet), (conn))
-#define PACKET_FREE_ALLOCA(packet) (packet.header.m->free_mem(&(packet), TRUE))
+#define PACKET_FREE_ALLOCA(packet) (packet.header.m->free_mem(&(packet), TRUE TSRMLS_CC))
/* Enums */
enum php_mysql_packet_type
size_t struct_size;
enum_func_status (*read_from_net)(void *packet, MYSQLND *conn TSRMLS_DC);
size_t (*write_to_net)(void *packet, MYSQLND *conn TSRMLS_DC);
- void (*free_mem)(void *packet, zend_bool alloca);
+ void (*free_mem)(void *packet, zend_bool alloca TSRMLS_DC);
} mysqlnd_packet_methods;
extern mysqlnd_packet_methods packet_methods[];
MYSQLND_FIELD *metadata;
/* For table definitions, empty for result sets */
zend_bool skip_parsing;
+ zend_bool stupid_list_fields_eof;
} php_mysql_packet_res_field;