diff options
Diffstat (limited to 'ext/mysqli')
-rw-r--r-- | ext/mysqli/config.m4 | 37 | ||||
-rw-r--r-- | ext/mysqli/config.w32 | 38 | ||||
-rw-r--r-- | ext/mysqli/mysqli.c | 356 | ||||
-rw-r--r-- | ext/mysqli/mysqli_api.c | 1043 | ||||
-rw-r--r-- | ext/mysqli/mysqli_driver.c | 16 | ||||
-rw-r--r-- | ext/mysqli/mysqli_embedded.c | 2 | ||||
-rw-r--r-- | ext/mysqli/mysqli_exception.c | 2 | ||||
-rw-r--r-- | ext/mysqli/mysqli_fe.c | 71 | ||||
-rw-r--r-- | ext/mysqli/mysqli_libmysql.h | 36 | ||||
-rw-r--r-- | ext/mysqli/mysqli_mysqlnd.h | 41 | ||||
-rw-r--r-- | ext/mysqli/mysqli_nonapi.c | 429 | ||||
-rw-r--r-- | ext/mysqli/mysqli_prop.c | 19 | ||||
-rw-r--r-- | ext/mysqli/mysqli_repl.c | 2 | ||||
-rw-r--r-- | ext/mysqli/mysqli_report.c | 9 | ||||
-rw-r--r-- | ext/mysqli/mysqli_warning.c | 162 | ||||
-rw-r--r-- | ext/mysqli/php_mysqli.h | 343 | ||||
-rw-r--r-- | ext/mysqli/php_mysqli_structs.h | 396 |
17 files changed, 2027 insertions, 975 deletions
diff --git a/ext/mysqli/config.m4 b/ext/mysqli/config.m4 index 19bc252bb0..7302e66c42 100644 --- a/ext/mysqli/config.m4 +++ b/ext/mysqli/config.m4 @@ -3,18 +3,17 @@ dnl $Id$ dnl config.m4 for extension mysqli PHP_ARG_WITH(mysqli, for MySQLi support, -[ --with-mysqli[=FILE] Include MySQLi support. FILE is the optional pathname - to mysql_config [mysql_config]]) +[ --with-mysqli[=FILE] Include MySQLi support. FILE is the optional pathname to mysql_config [mysql_config]. + If mysqlnd is passed as FILE, the MySQL native driver will be used]) PHP_ARG_ENABLE(embedded_mysqli, whether to enable embedded MySQLi support, [ --enable-embedded-mysqli MYSQLi: Enable embedded support], no, no) -if test "$PHP_MYSQLI" != "no"; then +if test "$PHP_MYSQLI" = "mysqlnd"; then + dnl This needs to be set in any extension which wishes to use mysqlnd + PHP_MYSQLND_ENABLED=yes -dnl there are no mysql libs currently bundled with PHP.. --Jani -dnl if test "$PHP_MYSQL" = "yes"; then -dnl AC_MSG_ERROR([--with-mysql (using bundled libs) can not be used together with --with-mysqli.]) -dnl fi +elif test "$PHP_MYSQLI" != "no"; then if test "$PHP_MYSQLI" = "yes"; then MYSQL_CONFIG=`$php_shtool path mysql_config` @@ -26,6 +25,8 @@ dnl fi if test "$PHP_EMBEDDED_MYSQLI" = "yes"; then AC_DEFINE(HAVE_EMBEDDED_MYSQLI, 1, [embedded MySQL support enabled]) MYSQL_LIB_CFG='--libmysqld-libs' + dnl mysqlnd doesn't support embedded, so we have to add some extra stuff + mysqli_extra_sources="mysqli_embedded.c" elif test "$enable_maintainer_zts" = "yes"; then MYSQL_LIB_CFG='--libs_r' MYSQL_LIB_NAME='mysqlclient_r' @@ -48,17 +49,29 @@ dnl fi [ PHP_EVAL_INCLINE($MYSQLI_INCLINE) PHP_EVAL_LIBLINE($MYSQLI_LIBLINE, MYSQLI_SHARED_LIBADD) - AC_DEFINE(HAVE_MYSQLILIB,1,[ ]) - PHP_CHECK_LIBRARY($MYSQL_LIB_NAME, mysql_stmt_field_count, + AC_DEFINE(HAVE_MYSQLILIB, 1, [ ]) + PHP_CHECK_LIBRARY($MYSQL_LIB_NAME, mysql_set_character_set, [ ],[ - AC_MSG_ERROR([MySQLI doesn't support versions < 4.1.3 (for MySQL 4.1.x) and < 5.0.1 for (MySQL 5.0.x) anymore. Please update your libraries.]) - ],[$MYSQLI_LIBLINE]) + AC_MSG_ERROR([MySQLI doesn't support versions < 4.1.13 (for MySQL 4.1.x) and < 5.0.7 for (MySQL 5.0.x) anymore. Please update your libraries.]) + ],[$MYSQLI_LIBLINE]) ],[ AC_MSG_ERROR([wrong mysql library version or lib not found. Check config.log for more information.]) ],[ $MYSQLI_LIBLINE ]) - PHP_NEW_EXTENSION(mysqli, mysqli.c mysqli_api.c mysqli_prop.c mysqli_nonapi.c mysqli_fe.c mysqli_report.c mysqli_repl.c mysqli_driver.c mysqli_warning.c mysqli_exception.c mysqli_embedded.c, $ext_shared) + mysqli_extra_sources="$mysqli_extra_sources mysqli_repl.c" +fi + +dnl Build extension +if test "$PHP_MYSQLI" != "no"; then + mysqli_sources="mysqli.c mysqli_api.c mysqli_prop.c mysqli_nonapi.c \ + mysqli_fe.c mysqli_report.c mysqli_driver.c mysqli_warning.c \ + mysqli_exception.c $mysqli_extra_sources" + PHP_NEW_EXTENSION(mysqli, $mysqli_sources, $ext_shared) PHP_SUBST(MYSQLI_SHARED_LIBADD) + + if test "$PHP_MYSQLI" = "mysqlnd"; then + PHP_ADD_EXTENSION_DEP(mysqli, mysqlnd) + fi fi diff --git a/ext/mysqli/config.w32 b/ext/mysqli/config.w32 index 789112ea14..0f418f0cba 100644 --- a/ext/mysqli/config.w32 +++ b/ext/mysqli/config.w32 @@ -1,14 +1,42 @@ // $Id$ // vim:ft=javascript +// Note: The extension name is "mysqli", you enable it with "--with-mysqli". +// Passing value "mysqlnd" to it enables the bundled +// client library to connect to the MySQL server, i.e. no external MySQL +// client library is needed to perform the build. + ARG_WITH("mysqli", "MySQLi support", "no"); if (PHP_MYSQLI != "no") { - if (CHECK_LIB("libmysql.lib", "mysqli", PHP_MYSQLI) && - CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_MYSQLI", PHP_MYSQLI + "\\include;" + PHP_PHP_BUILD + "\\include\\mysql;" + PHP_MYSQLI)) { - EXTENSION("mysqli", "mysqli.c mysqli_api.c mysqli_prop.c mysqli_nonapi.c mysqli_fe.c mysqli_report.c mysqli_repl.c mysqli_driver.c mysqli_warning.c mysqli_exception.c mysqli_embedded.c"); - AC_DEFINE('HAVE_MYSQLILIB', 1, 'Have MySQLi library'); + mysqli_source = + "mysqli.c " + + "mysqli_api.c " + + "mysqli_driver.c " + + "mysqli_embedded.c " + + "mysqli_exception.c " + + "mysqli_fe.c " + + "mysqli_nonapi.c " + + "mysqli_prop.c " + + "mysqli_report.c " + + "mysqli_warning.c"; + + if (PHP_MYSQLI != "mysqlnd") { + if (CHECK_LIB("libmysql.lib", "mysqli", PHP_MYSQLI) && + CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_MYSQLI", PHP_MYSQLI + + "\\include;" + PHP_PHP_BUILD + + "\\include\\mysql;" + PHP_MYSQLI)) { + // No "mysqli_repl.c" when using "mysqlnd" + mysqli_extra_sources = "mysqli_repl.c"; + EXTENSION("mysqli", mysqli_source + " " + mysqli_extra_sources); + AC_DEFINE('HAVE_MYSQLILIB', 1, 'Have MySQLi library'); + } else { + WARNING("mysqli not enabled; libraries and headers not found"); + } } else { - WARNING("mysqli not enabled; libraries and headers not found"); + EXTENSION("mysqli", mysqli_source); + AC_DEFINE('HAVE_MYSQLND', 1, 'MySQLi with native driver support enabled'); + AC_DEFINE('HAVE_MYSQLILIB', 1, 'Have MySQLi library'); + ADD_EXTENSION_DEP('mysqli', 'mysqlnd', true); } } diff --git a/ext/mysqli/mysqli.c b/ext/mysqli/mysqli.c index ff4f206b7a..8de80f5e05 100644 --- a/ext/mysqli/mysqli.c +++ b/ext/mysqli/mysqli.c @@ -28,7 +28,7 @@ #include "php_ini.h" #include "ext/standard/info.h" #include "ext/standard/php_string.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" #include "zend_exceptions.h" #define MYSQLI_STORE_RESULT 0 @@ -52,6 +52,12 @@ zend_class_entry *mysqli_driver_class_entry; zend_class_entry *mysqli_warning_class_entry; zend_class_entry *mysqli_exception_class_entry; +#ifdef HAVE_MYSQLND +MYSQLND_ZVAL_PCACHE *mysqli_mysqlnd_zval_cache; +MYSQLND_QCACHE *mysqli_mysqlnd_qcache; +#endif + + extern void php_mysqli_connect(INTERNAL_FUNCTION_PARAMETERS); typedef int (*mysqli_read_t)(mysqli_object *obj, zval **retval TSRMLS_DC); @@ -62,6 +68,63 @@ typedef struct _mysqli_prop_handler { mysqli_write_t write_func; } mysqli_prop_handler; +static int le_pmysqli; + +static int php_mysqli_persistent_on_rshut(zend_rsrc_list_entry *le TSRMLS_DC) +{ + 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); +#endif + 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); + } +} + + +int php_le_pmysqli(void) +{ + return le_pmysqli; +} + +#ifndef HAVE_MYSQLND /* {{{ php_free_stmt_bind_buffer */ void php_free_stmt_bind_buffer(BIND_BUFFER bbuf, int type) { @@ -80,7 +143,7 @@ void php_free_stmt_bind_buffer(BIND_BUFFER bbuf, int type) if (bbuf.vars[i]) { zval_ptr_dtor(&bbuf.vars[i]); - } + } } if (bbuf.vars) { @@ -100,30 +163,44 @@ void php_free_stmt_bind_buffer(BIND_BUFFER bbuf, int type) } bbuf.var_cnt = 0; - return; } /* }}} */ +#endif /* {{{ php_clear_stmt_bind */ -void php_clear_stmt_bind(MY_STMT *stmt) +void php_clear_stmt_bind(MY_STMT *stmt TSRMLS_DC) { if (stmt->stmt) { - mysql_stmt_close(stmt->stmt); + if (mysqli_stmt_close(stmt->stmt, TRUE)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error occured while closing statement"); + return; + } } + /* + mysqlnd keeps track of the binding and has freed its + structures in stmt_close() above + */ +#ifndef HAVE_MYSQLND + /* Clean param bind */ php_free_stmt_bind_buffer(stmt->param, FETCH_SIMPLE); + /* Clean output bind */ php_free_stmt_bind_buffer(stmt->result, FETCH_RESULT); +#endif if (stmt->query) { efree(stmt->query); } efree(stmt); - return; } /* }}} */ /* {{{ 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); @@ -140,7 +217,7 @@ static void mysqli_objects_free_storage(void *object TSRMLS_DC) mysqli_object *intern = (mysqli_object *)zo; MYSQLI_RESOURCE *my_res = (MYSQLI_RESOURCE *)intern->ptr; - my_efree(my_res); + my_efree(my_res); zend_object_std_dtor(&intern->zo TSRMLS_CC); efree(intern); } @@ -157,7 +234,9 @@ static void mysqli_link_free_storage(void *object TSRMLS_DC) if (my_res && my_res->ptr) { MY_MYSQL *mysql = (MY_MYSQL *)my_res->ptr; if (mysql->mysql) { - mysql_close(mysql->mysql); + if (!mysql->persistent) { + mysqli_close(mysql->mysql, MYSQLI_CLOSE_IMPLICIT); + } } php_clear_mysql(mysql); efree(mysql); @@ -166,6 +245,13 @@ static void mysqli_link_free_storage(void *object TSRMLS_DC) } /* }}} */ +/* {{{ mysql_driver_free_storage */ +static void mysqli_driver_free_storage(void *object TSRMLS_DC) +{ + mysqli_objects_free_storage(object TSRMLS_CC); +} +/* }}} */ + /* {{{ mysqli_stmt_free_storage */ static void mysqli_stmt_free_storage(void *object TSRMLS_DC) @@ -176,7 +262,7 @@ static void mysqli_stmt_free_storage(void *object TSRMLS_DC) if (my_res && my_res->ptr) { MY_STMT *stmt = (MY_STMT *)my_res->ptr; - php_clear_stmt_bind(stmt); + php_clear_stmt_bind(stmt TSRMLS_CC); } mysqli_objects_free_storage(object TSRMLS_CC); } @@ -243,7 +329,7 @@ zval *mysqli_read_property(zval *object, zval *member, int type TSRMLS_DC) ret = FAILURE; obj = (mysqli_object *)zend_objects_get_address(object TSRMLS_CC); - if (member->type != IS_STRING) { + if (member->type != IS_STRING) { tmp_member = *member; zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); @@ -256,7 +342,8 @@ zval *mysqli_read_property(zval *object, zval *member, int type TSRMLS_DC) if (ret == SUCCESS) { if (strcmp(obj->zo.ce->name, "mysqli_driver") && - (!obj->ptr || ((MYSQLI_RESOURCE *)(obj->ptr))->status < MYSQLI_STATUS_INITIALIZED)) { + (!obj->ptr || ((MYSQLI_RESOURCE *)(obj->ptr))->status < MYSQLI_STATUS_INITIALIZED)) + { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't fetch %s", obj->zo.ce->name ); retval = EG(uninitialized_zval_ptr); return(retval); @@ -290,7 +377,7 @@ void mysqli_write_property(zval *object, zval *member, zval *value TSRMLS_DC) zend_object_handlers *std_hnd; int ret; - if (member->type != IS_STRING) { + if (member->type != IS_STRING) { tmp_member = *member; zval_copy_ctor(&tmp_member); convert_to_string(&tmp_member); @@ -333,7 +420,6 @@ void mysqli_add_property(HashTable *h, char *pname, mysqli_read_t r_func, mysqli static union _zend_function *php_mysqli_constructor_get(zval *object TSRMLS_DC) { - mysqli_object *obj = (mysqli_object *)zend_objects_get_address(object TSRMLS_CC); zend_class_entry * ce = Z_OBJCE_P(object); if (ce != mysqli_link_class_entry && ce != mysqli_stmt_class_entry && @@ -342,6 +428,7 @@ static union _zend_function *php_mysqli_constructor_get(zval *object TSRMLS_DC) return zend_std_get_constructor(object TSRMLS_CC); } else { static zend_internal_function f; + mysqli_object *obj = (mysqli_object *)zend_objects_get_address(object TSRMLS_CC); f.function_name = obj->zo.ce->name; f.scope = obj->zo.ce; @@ -361,7 +448,7 @@ static union _zend_function *php_mysqli_constructor_get(zval *object TSRMLS_DC) } else if (obj->zo.ce == mysqli_warning_class_entry) { f.handler = ZEND_MN(mysqli_warning___construct); } - + return (union _zend_function*)&f; } } @@ -382,8 +469,7 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry *class_ intern->prop_handler = NULL; mysqli_base_class = class_type; - while (mysqli_base_class->type != ZEND_INTERNAL_CLASS && mysqli_base_class->parent != NULL) - { + while (mysqli_base_class->type != ZEND_INTERNAL_CLASS && mysqli_base_class->parent != NULL) { mysqli_base_class = mysqli_base_class->parent; } zend_hash_find(&classes, mysqli_base_class->name, mysqli_base_class->name_length + 1, @@ -396,6 +482,8 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry *class_ /* link object */ if (instanceof_function(class_type, mysqli_link_class_entry TSRMLS_CC)) { free_storage = mysqli_link_free_storage; + } else if (instanceof_function(class_type, mysqli_driver_class_entry TSRMLS_CC)) { /* driver object */ + free_storage = mysqli_driver_free_storage; } else if (instanceof_function(class_type, mysqli_stmt_class_entry TSRMLS_CC)) { /* stmt object */ free_storage = mysqli_stmt_free_storage; } else if (instanceof_function(class_type, mysqli_result_class_entry TSRMLS_CC)) { /* result object */ @@ -412,17 +500,21 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry *class_ return retval; } /* }}} */ - -/* {{{ mysqli_module_entry - */ + + /* Dependancies */ -static const zend_module_dep mysqli_deps[] = { +const static zend_module_dep mysqli_deps[] = { #if defined(HAVE_SPL) && ((PHP_MAJOR_VERSION > 5) || (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION >= 1)) ZEND_MOD_REQUIRED("spl") #endif +#if defined(HAVE_MYSQLND) + ZEND_MOD_REQUIRED("mysqlnd") +#endif {NULL, NULL, NULL} }; +/* {{{ mysqli_module_entry + */ zend_module_entry mysqli_module_entry = { #if ZEND_MODULE_API_NO >= 20050922 STANDARD_MODULE_HEADER_EX, NULL, @@ -454,22 +546,33 @@ ZEND_GET_MODULE(mysqli) */ 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) STD_PHP_INI_ENTRY("mysqli.default_port", "3306", PHP_INI_ALL, OnUpdateLong, default_port, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_ENTRY("mysqli.default_socket", NULL, PHP_INI_ALL, OnUpdateStringUnempty, default_socket, zend_mysqli_globals, mysqli_globals) STD_PHP_INI_BOOLEAN("mysqli.reconnect", "0", PHP_INI_SYSTEM, OnUpdateLong, reconnect, zend_mysqli_globals, mysqli_globals) + STD_PHP_INI_BOOLEAN("mysqli.allow_local_infile", "1", PHP_INI_SYSTEM, OnUpdateLong, allow_local_infile, zend_mysqli_globals, mysqli_globals) +#ifdef HAVE_MYSQLND + STD_PHP_INI_ENTRY("mysqli.cache_size", "2000", PHP_INI_SYSTEM, OnUpdateLong, cache_size, zend_mysqli_globals, mysqli_globals) +#endif PHP_INI_END() - /* }}} */ + /* {{{ PHP_GINIT_FUNCTION */ static PHP_GINIT_FUNCTION(mysqli) { mysqli_globals->num_links = 0; - mysqli_globals->max_links = 0; + mysqli_globals->num_active_persistent = 0; + mysqli_globals->num_inactive_persistent = 0; + mysqli_globals->max_links = -1; + 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; @@ -478,11 +581,16 @@ static PHP_GINIT_FUNCTION(mysqli) mysqli_globals->reconnect = 0; mysqli_globals->report_mode = 0; mysqli_globals->report_ht = 0; + mysqli_globals->allow_local_infile = 1; #ifdef HAVE_EMBEDDED_MYSQLI mysqli_globals->embedded = 1; #else mysqli_globals->embedded = 0; #endif +#ifdef HAVE_MYSQLND + mysqli_globals->cache_size = 0; + mysqli_globals->mysqlnd_thd_zval_cache = NULL; +#endif } /* }}} */ @@ -494,6 +602,16 @@ PHP_MINIT_FUNCTION(mysqli) zend_object_handlers *std_hnd = zend_get_std_object_handlers(); 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(); +#endif memcpy(&mysqli_object_handlers, zend_get_std_object_handlers(), sizeof(zend_object_handlers)); mysqli_object_handlers.clone_obj = NULL; @@ -504,6 +622,10 @@ PHP_MINIT_FUNCTION(mysqli) zend_hash_init(&classes, 0, NULL, NULL, 1); + /* persistent connections */ + le_pmysqli = zend_register_list_destructors_ex(NULL, php_mysqli_dtor, + "MySqli persistent connection", module_number); + INIT_CLASS_ENTRY(cex, "mysqli_sql_exception", mysqli_exception_methods); #ifdef HAVE_SPL mysqli_exception_class_entry = zend_register_internal_class_ex(&cex, spl_ce_RuntimeException, NULL TSRMLS_CC); @@ -552,6 +674,13 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_LONG_CONSTANT("MYSQLI_OPT_CONNECT_TIMEOUT", MYSQL_OPT_CONNECT_TIMEOUT, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_OPT_LOCAL_INFILE", MYSQL_OPT_LOCAL_INFILE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_INIT_COMMAND", MYSQL_INIT_COMMAND, CONST_CS | CONST_PERSISTENT); +#if defined(HAVE_MYSQLND) + 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); +#endif /* mysqli_real_connect flags */ REGISTER_LONG_CONSTANT("MYSQLI_CLIENT_SSL", CLIENT_SSL, CONST_CS | CONST_PERSISTENT); @@ -573,7 +702,7 @@ PHP_MINIT_FUNCTION(mysqli) /* for mysqli_stmt_set_attr */ REGISTER_LONG_CONSTANT("MYSQLI_STMT_ATTR_UPDATE_MAX_LENGTH", STMT_ATTR_UPDATE_MAX_LENGTH, CONST_CS | CONST_PERSISTENT); -#if MYSQL_VERSION_ID > 50003 +#if MYSQL_VERSION_ID > 50003 || defined(HAVE_MYSQLND) REGISTER_LONG_CONSTANT("MYSQLI_STMT_ATTR_CURSOR_TYPE", STMT_ATTR_CURSOR_TYPE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_CURSOR_TYPE_NO_CURSOR", CURSOR_TYPE_NO_CURSOR, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_CURSOR_TYPE_READ_ONLY", CURSOR_TYPE_READ_ONLY, CONST_CS | CONST_PERSISTENT); @@ -581,7 +710,7 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_LONG_CONSTANT("MYSQLI_CURSOR_TYPE_SCROLLABLE", CURSOR_TYPE_SCROLLABLE, CONST_CS | CONST_PERSISTENT); #endif -#if MYSQL_VERSION_ID > 50007 +#if MYSQL_VERSION_ID > 50007 || defined(HAVE_MYSQLND) REGISTER_LONG_CONSTANT("MYSQLI_STMT_ATTR_PREFETCH_ROWS", STMT_ATTR_PREFETCH_ROWS, CONST_CS | CONST_PERSISTENT); #endif @@ -627,17 +756,19 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_LONG_CONSTANT("MYSQLI_TYPE_INTERVAL", FIELD_TYPE_INTERVAL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_TYPE_GEOMETRY", FIELD_TYPE_GEOMETRY, CONST_CS | CONST_PERSISTENT); -#if MYSQL_VERSION_ID > 50002 +#if MYSQL_VERSION_ID > 50002 || defined(HAVE_MYSQLND) REGISTER_LONG_CONSTANT("MYSQLI_TYPE_NEWDECIMAL", FIELD_TYPE_NEWDECIMAL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_TYPE_BIT", FIELD_TYPE_BIT, CONST_CS | CONST_PERSISTENT); #endif - + REGISTER_LONG_CONSTANT("MYSQLI_SET_CHARSET_NAME", MYSQL_SET_CHARSET_NAME, CONST_CS | CONST_PERSISTENT); /* replication */ +#if !defined(HAVE_MYSQLND) REGISTER_LONG_CONSTANT("MYSQLI_RPL_MASTER", MYSQL_RPL_MASTER, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_RPL_SLAVE", MYSQL_RPL_SLAVE, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_RPL_ADMIN", MYSQL_RPL_ADMIN, CONST_CS | CONST_PERSISTENT); +#endif /* bind support */ REGISTER_LONG_CONSTANT("MYSQLI_NO_DATA", MYSQL_NO_DATA, CONST_CS | CONST_PERSISTENT); @@ -652,10 +783,6 @@ PHP_MINIT_FUNCTION(mysqli) REGISTER_LONG_CONSTANT("MYSQLI_REPORT_ALL", MYSQLI_REPORT_ALL, CONST_CS | CONST_PERSISTENT); REGISTER_LONG_CONSTANT("MYSQLI_REPORT_OFF", 0, CONST_CS | CONST_PERSISTENT); - if (mysql_server_init(0, NULL, NULL)) { - return FAILURE; - } - return SUCCESS; } /* }}} */ @@ -664,15 +791,25 @@ PHP_MINIT_FUNCTION(mysqli) */ 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) { + /* + 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); +#endif zend_hash_destroy(&mysqli_driver_properties); zend_hash_destroy(&mysqli_result_properties); @@ -690,13 +827,16 @@ PHP_MSHUTDOWN_FUNCTION(mysqli) */ PHP_RINIT_FUNCTION(mysqli) { -#ifdef ZTS +#if !defined(HAVE_MYSQLND) && defined(ZTS) && MYSQL_VERSION_ID >= 40000 if (mysql_thread_init()) { return FAILURE; } #endif MyG(error_msg) = NULL; MyG(error_no) = 0; +#ifdef HAVE_MYSQLND + MyG(mysqlnd_thd_zval_cache) = mysqlnd_palloc_rinit(mysqli_mysqlnd_zval_cache); +#endif return SUCCESS; } @@ -706,27 +846,55 @@ PHP_RINIT_FUNCTION(mysqli) */ PHP_RSHUTDOWN_FUNCTION(mysqli) { -#ifdef 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)) { efree(MyG(error_msg)); } +#ifdef HAVE_MYSQLND + mysqlnd_palloc_rshutdown(MyG(mysqlnd_thd_zval_cache)); +#endif return SUCCESS; } /* }}} */ + /* {{{ PHP_MINFO_FUNCTION */ PHP_MINFO_FUNCTION(mysqli) { + char buf[32]; + 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()); + 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); +#if !defined(HAVE_MYSQLND) 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 + { + zval values; + + php_info_print_table_header(2, "Persistent cache", mysqli_mysqlnd_zval_cache? "enabled":"disabled"); + + if (mysqli_mysqlnd_zval_cache) { + /* Now report cache status */ + mysqlnd_palloc_stats(mysqli_mysqlnd_zval_cache, &values); + mysqlnd_minfo_print_hash(&values); + zval_dtor(&values); + } + } +#endif php_info_print_table_end(); DISPLAY_INI_ENTRIES(); @@ -742,16 +910,16 @@ Parameters: ZEND_FUNCTION(mysqli_stmt_construct) { MY_MYSQL *mysql; - zval *mysql_link; + zval *mysql_link; MY_STMT *stmt; - MYSQLI_RESOURCE *mysqli_resource; + MYSQLI_RESOURCE *mysqli_resource; char *statement; - int stmt_len; + int statement_len; switch (ZEND_NUM_ARGS()) { case 1: /* mysql_stmt_init */ - if (zend_parse_parameters(1 TSRMLS_CC, "O", &mysql_link, mysqli_link_class_entry)==FAILURE) { + if (zend_parse_parameters(1 TSRMLS_CC, "O", &mysql_link, mysqli_link_class_entry)==FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); @@ -761,15 +929,15 @@ ZEND_FUNCTION(mysqli_stmt_construct) stmt->stmt = mysql_stmt_init(mysql->mysql); break; case 2: - if (zend_parse_parameters(2 TSRMLS_CC, "Os", &mysql_link, mysqli_link_class_entry, &statement, &stmt_len)==FAILURE) { + if (zend_parse_parameters(2 TSRMLS_CC, "Os", &mysql_link, mysqli_link_class_entry, &statement, &statement_len)==FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT)); - + if ((stmt->stmt = mysql_stmt_init(mysql->mysql))) { - mysql_stmt_prepare(stmt->stmt, statement, stmt_len); + mysql_stmt_prepare(stmt->stmt, statement, statement_len); } break; default: @@ -800,20 +968,24 @@ ZEND_FUNCTION(mysqli_result_construct) MY_MYSQL *mysql; MYSQL_RES *result; zval *mysql_link; - MYSQLI_RESOURCE *mysqli_resource; + MYSQLI_RESOURCE *mysqli_resource; long resmode = MYSQLI_STORE_RESULT; switch (ZEND_NUM_ARGS()) { case 1: - if (zend_parse_parameters(1 TSRMLS_CC, "O", &mysql_link, mysqli_link_class_entry)==FAILURE) { + if (zend_parse_parameters(1 TSRMLS_CC, "O", &mysql_link, mysqli_link_class_entry)==FAILURE) { return; } - break; + break; case 2: - if (zend_parse_parameters(2 TSRMLS_CC, "Ol", &mysql_link, mysqli_link_class_entry, &resmode)==FAILURE) { + if (zend_parse_parameters(2 TSRMLS_CC, "Ol", &mysql_link, mysqli_link_class_entry, &resmode)==FAILURE) { return; } - break; + if (resmode != MYSQLI_USE_RESULT && resmode != MYSQLI_STORE_RESULT) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for resultmode"); + RETURN_FALSE; + } + break; default: WRONG_PARAM_COUNT; } @@ -830,7 +1002,7 @@ ZEND_FUNCTION(mysqli_result_construct) mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = (void *)result; mysqli_resource->status = MYSQLI_STATUS_VALID; - + ((mysqli_object *) zend_object_store_get_object(getThis() TSRMLS_CC))->ptr = mysqli_resource; } @@ -843,12 +1015,14 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags MYSQL_RES *result; zval *mysql_result; long fetchtype; + zval *ctor_params = NULL; + zend_class_entry *ce = NULL; +#if !defined(HAVE_MYSQLND) unsigned int i; MYSQL_FIELD *fields; MYSQL_ROW row; unsigned long *field_len; - zval *ctor_params = NULL; - zend_class_entry *ce = NULL; +#endif if (into_object) { char *class_name; @@ -882,11 +1056,12 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags } MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); - if ((fetchtype & MYSQLI_BOTH) == 0) { + if (fetchtype < MYSQLI_ASSOC || fetchtype > MYSQLI_BOTH) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "The result type should be either MYSQLI_NUM, MYSQLI_ASSOC or MYSQLI_BOTH"); RETURN_FALSE; } +#if !defined(HAVE_MYSQLND) if (!(row = mysql_fetch_row(result))) { RETURN_NULL(); } @@ -930,16 +1105,19 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags } } } +#else + mysqlnd_fetch_into(result, MYSQLND_FETCH_ASSOC, return_value, MYSQLND_MYSQLI); +#endif - if (into_object) { + if (into_object && Z_TYPE_P(return_value) != IS_NULL) { zval dataset = *return_value; zend_fcall_info fci; zend_fcall_info_cache fcc; zval *retval_ptr; - + object_and_properties_init(return_value, ce, NULL); zend_merge_properties(return_value, Z_ARRVAL(dataset), 1 TSRMLS_CC); - + if (ce->constructor) { fci.size = sizeof(fci); fci.function_table = &ce->function_table; @@ -951,7 +1129,7 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags if (Z_TYPE_P(ctor_params) == IS_ARRAY) { HashTable *ht = Z_ARRVAL_P(ctor_params); Bucket *p; - + fci.param_count = 0; fci.params = safe_emalloc(sizeof(zval*), ht->nNumOfElements, 0); p = ht->pListHead; @@ -979,7 +1157,7 @@ void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flags fcc.function_handler = ce->constructor; fcc.calling_scope = EG(scope); fcc.object_pp = &return_value; - + if (zend_call_function(&fci, &fcc TSRMLS_CC) == FAILURE) { zend_throw_exception_ex(zend_exception_get_default(TSRMLS_C), 0 TSRMLS_CC, "Could not execute %s::%s()", ce->name, ce->constructor->common.function_name); } else { @@ -1009,6 +1187,8 @@ PHP_MYSQLI_API void php_mysqli_set_error(long mysql_errno, char *mysql_err TSRML } /* }}} */ +#if !defined(HAVE_MYSQLND) + #define ALLOC_CALLBACK_ARGS(a, b, c)\ if (c) {\ a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\ @@ -1029,7 +1209,7 @@ if (a) {\ #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)); /* {{{ void php_set_local_infile_handler_default */ @@ -1037,7 +1217,10 @@ void php_set_local_infile_handler_default(MY_MYSQL *mysql) { /* register internal callback functions */ 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); - mysql->li_read = NULL; + if (mysql->li_read) { + zval_ptr_dtor(&mysql->li_read); + mysql->li_read = NULL; + } } /* }}} */ @@ -1047,7 +1230,7 @@ int php_local_infile_init(void **ptr, const char *filename, void *userdata) { mysqli_local_infile *data; MY_MYSQL *mysql; - php_stream_context *context = NULL; + php_stream_context *context = NULL; TSRMLS_FETCH(); @@ -1086,7 +1269,7 @@ int php_local_infile_init(void **ptr, const char *filename, void *userdata) int php_local_infile_read(void *ptr, char *buf, uint buf_len) { mysqli_local_infile *data; - MY_MYSQL *mysql; + MY_MYSQL *mysql; zval ***callback_args; zval *retval; zval *fp; @@ -1101,9 +1284,7 @@ int php_local_infile_read(void *ptr, char *buf, uint buf_len) /* default processing */ if (!mysql->li_read) { - int count; - - count = (int)php_stream_read(mysql->li_stream, buf, buf_len); + int count = (int)php_stream_read(mysql->li_stream, buf, buf_len); if (count < 0) { LOCAL_INFILE_ERROR_MSG(data->error_msg, ER(2)); @@ -1113,21 +1294,21 @@ int php_local_infile_read(void *ptr, char *buf, uint buf_len) } ALLOC_CALLBACK_ARGS(callback_args, 1, argc); - + /* set parameters: filepointer, buffer, buffer_len, errormsg */ MAKE_STD_ZVAL(fp); php_stream_to_zval(mysql->li_stream, fp); callback_args[0] = &fp; - ZVAL_STRING(*callback_args[1], "", 1); - ZVAL_LONG(*callback_args[2], buf_len); - ZVAL_STRING(*callback_args[3], "", 1); + 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, mysql->li_read, &retval, - argc, + argc, callback_args, 0, NULL TSRMLS_CC) == SUCCESS) { @@ -1136,22 +1317,36 @@ int php_local_infile_read(void *ptr, char *buf, uint buf_len) zval_ptr_dtor(&retval); if (rc > 0) { - if (rc > buf_len) { + if (rc >= 0 && rc != Z_STRLEN_P(*callback_args[1])) { + LOCAL_INFILE_ERROR_MSG(data->error_msg, + "Mismatch between the return value of the callback and the content " + "length of the buffer."); + rc = -1; + } else if (rc > buf_len) { /* check buffer overflow */ - LOCAL_INFILE_ERROR_MSG(data->error_msg, "Read buffer too large"); + LOCAL_INFILE_ERROR_MSG(data->error_msg, "Too much data returned"); rc = -1; } else { - memcpy(buf, Z_STRVAL_P(*callback_args[1]), rc); + memcpy(buf, Z_STRVAL_P(*callback_args[1]), MIN(rc, Z_STRLEN_P(*callback_args[1]))); } - } - if (rc < 0) { + } else if (rc < 0) { LOCAL_INFILE_ERROR_MSG(data->error_msg, Z_STRVAL_P(*callback_args[3])); } } else { 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 rc; @@ -1167,7 +1362,7 @@ int php_local_infile_error(void *ptr, char *error_msg, uint error_msg_len) if (data) { strlcpy(error_msg, data->error_msg, error_msg_len); return 2000; - } + } strlcpy(error_msg, ER(CR_OUT_OF_MEMORY), error_msg_len); return CR_OUT_OF_MEMORY; } @@ -1175,10 +1370,10 @@ int php_local_infile_error(void *ptr, char *error_msg, uint error_msg_len) /* {{{ php_local_infile_end */ -void php_local_infile_end(void *ptr) +void php_local_infile_end(void *ptr) { - mysqli_local_infile *data; - MY_MYSQL *mysql; + mysqli_local_infile *data; + MY_MYSQL *mysql; TSRMLS_FETCH(); @@ -1193,9 +1388,10 @@ void php_local_infile_end(void *ptr) php_stream_close(mysql->li_stream); free(data); - return; + return; } /* }}} */ +#endif /* * Local variables: diff --git a/ext/mysqli/mysqli_api.c b/ext/mysqli/mysqli_api.c index fd01ba9ffa..5e55be7d51 100644 --- a/ext/mysqli/mysqli_api.c +++ b/ext/mysqli/mysqli_api.c @@ -12,7 +12,9 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Georg Richter <georg@php.net> | + | Authors: Georg Richter <georg@php.net> | + | Andrey Hristov <andrey@php.net> | + | Ulf Wendel <uw@php.net> | +----------------------------------------------------------------------+ $Id$ @@ -26,8 +28,9 @@ #include "php.h" #include "php_ini.h" +#include "php_globals.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" /* {{{ proto mixed mysqli_affected_rows(object link) Get number of affected rows in previous MySQL operation */ @@ -51,16 +54,17 @@ PHP_FUNCTION(mysqli_affected_rows) } /* }}} */ + /* {{{ proto bool mysqli_autocommit(object link, bool mode) Turn auto commit on or of */ PHP_FUNCTION(mysqli_autocommit) { - MY_MYSQL *mysql; - zval *mysql_link; - zend_bool automode; + MY_MYSQL *mysql; + zval *mysql_link; + zend_bool automode; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ob", &mysql_link, mysqli_link_class_entry, &automode) == FAILURE) { - return; + return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); @@ -71,83 +75,38 @@ PHP_FUNCTION(mysqli_autocommit) } /* }}} */ -/* {{{ proto bool mysqli_stmt_bind_param(object stmt, string types, mixed variable [,mixed,....]) - Bind variables to a prepared statement as parameters */ -PHP_FUNCTION(mysqli_stmt_bind_param) +/* {{{ mysqli_stmt_bind_param_do_bind */ +#ifndef HAVE_MYSQLND +static +int mysqli_stmt_bind_param_do_bind(MY_STMT *stmt, unsigned int argc, unsigned int num_vars, + zval ***args, unsigned int start, const char * const types TSRMLS_DC) { - zval ***args; - int argc = ZEND_NUM_ARGS(); - int i; - int num_vars; - int start = 2; - int ofs; - MY_STMT *stmt; - zval *mysql_stmt; + int i, ofs; MYSQL_BIND *bind; - char *types; - int typelen; unsigned long rc; - /* calculate and check number of parameters */ - if (argc < 2) { - /* there has to be at least one pair */ - WRONG_PARAM_COUNT; - } - - if (zend_parse_method_parameters((getThis()) ? 1:2 TSRMLS_CC, getThis(), "Os", &mysql_stmt, mysqli_stmt_class_entry, &types, &typelen) == FAILURE) { - return; - } - - MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); - - num_vars = argc - 1; - if (getThis()) { - start = 1; - } else { - /* ignore handle parameter in procedural interface*/ - --num_vars; - } - - if (typelen != argc - start) { - /* number of bind variables doesn't match number of elements in type definition string */ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements in type definition string doesn't match number of bind variables"); - RETURN_FALSE; - } - - if (typelen != stmt->stmt->param_count) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of variables doesn't match number of parameters in prepared statement"); - RETURN_FALSE; - } - /* prevent leak if variables are already bound */ if (stmt->param.var_cnt) { php_free_stmt_bind_buffer(stmt->param, FETCH_SIMPLE); } - args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); - - if (zend_get_parameters_array_ex(argc, args) == FAILURE) { - efree(args); - WRONG_PARAM_COUNT; - } - stmt->param.is_null = ecalloc(num_vars, sizeof(char)); - bind = (MYSQL_BIND *)ecalloc(num_vars, sizeof(MYSQL_BIND)); + bind = (MYSQL_BIND *) ecalloc(num_vars, sizeof(MYSQL_BIND)); ofs = 0; - for (i=start; i < argc; i++) { + for (i = start; i < argc; i++) { /* set specified type */ switch (types[ofs]) { case 'd': /* Double */ bind[ofs].buffer_type = MYSQL_TYPE_DOUBLE; - bind[ofs].buffer = (char*)&Z_DVAL_PP(args[i]); + bind[ofs].buffer = &Z_DVAL_PP(args[i]); bind[ofs].is_null = &stmt->param.is_null[ofs]; break; case 'i': /* Integer */ - bind[ofs].buffer_type = MYSQL_TYPE_LONG; - bind[ofs].buffer = (char*)&Z_LVAL_PP(args[i]); + bind[ofs].buffer_type = (sizeof(long) > 4) ? MYSQL_TYPE_LONGLONG : MYSQL_TYPE_LONG; + bind[ofs].buffer = &Z_LVAL_PP(args[i]); bind[ofs].is_null = &stmt->param.is_null[ofs]; break; @@ -164,85 +123,162 @@ PHP_FUNCTION(mysqli_stmt_bind_param) default: php_error_docref(NULL TSRMLS_CC, E_WARNING, "Undefined fieldtype %c (parameter %d)", types[ofs], i+1); - RETVAL_FALSE; - goto end; + rc = 1; + goto end_1; } ofs++; } rc = mysql_stmt_bind_param(stmt->stmt, bind); - MYSQLI_REPORT_STMT_ERROR(stmt->stmt); +end_1: if (rc) { - RETVAL_FALSE; - goto end; + efree(stmt->param.is_null); + } else { + stmt->param.var_cnt = num_vars; + stmt->param.vars = (zval **)safe_emalloc(num_vars, sizeof(zval), 0); + for (i = 0; i < num_vars; i++) { + if (bind[i].buffer_type != MYSQL_TYPE_LONG_BLOB) { + ZVAL_ADDREF(*args[i+start]); + stmt->param.vars[i] = *args[i+start]; + } else { + stmt->param.vars[i] = NULL; + } + } } + efree(bind); - stmt->param.var_cnt = num_vars; - stmt->param.vars = (zval **)safe_emalloc(num_vars, sizeof(zval), 0); - for (i = 0; i < num_vars; i++) { - if (bind[i].buffer_type != MYSQL_TYPE_LONG_BLOB) { - ZVAL_ADDREF(*args[i+start]); - stmt->param.vars[i] = *args[i+start]; - } else { - stmt->param.vars[i] = NULL; + return rc; +} +#else +static +int mysqli_stmt_bind_param_do_bind(MY_STMT *stmt, unsigned int argc, unsigned int num_vars, + zval ***args, unsigned int start, const char * const types TSRMLS_DC) +{ + int i; + MYSQLND_PARAM_BIND *params; + enum_func_status ret = FAIL; + + /* If no params -> skip binding and return directly */ + if (argc == start) { + return PASS; + } + params = emalloc((argc - start) * sizeof(MYSQLND_PARAM_BIND)); + for (i = 0; i < (argc - start); i++) { + zend_uchar type; + switch (types[i]) { + case 'd': /* Double */ + type = MYSQL_TYPE_DOUBLE; + break; + case 'i': /* Integer */ +#if SIZEOF_LONG==8 + type = MYSQL_TYPE_LONGLONG; +#elif SIZEOF_LONG==4 + type = MYSQL_TYPE_LONG; +#endif + break; + case 'b': /* Blob (send data) */ + type = MYSQL_TYPE_LONG_BLOB; + break; + case 's': /* string */ + type = MYSQL_TYPE_VAR_STRING; + break; + default: + /* We count parameters from 1 */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Undefined fieldtype %c (parameter %d)", types[i], i + start + 1); + ret = FAIL; + efree(params); + goto end; } + params[i].zv = *(args[i + start]); + params[i].type = type; } - RETVAL_TRUE; + ret = mysqlnd_stmt_bind_param(stmt->stmt, params); + end: - efree(args); - efree(bind); + return ret; } +#endif /* }}} */ -/* {{{ proto bool mysqli_stmt_bind_result(object stmt, mixed var, [,mixed, ...]) - Bind variables to a prepared statement for result storage */ - -/* TODO: - do_alloca, free_alloca -*/ - -PHP_FUNCTION(mysqli_stmt_bind_result) +/* {{{ proto bool mysqli_stmt_bind_param(object stmt, string types, mixed variable [,mixed,....]) U + Bind variables to a prepared statement as parameters */ +PHP_FUNCTION(mysqli_stmt_bind_param) { - zval ***args; - int argc = ZEND_NUM_ARGS(); - int i; - int start = 1; - int var_cnt; - int ofs; - long col_type; - ulong rc; - MY_STMT *stmt; - zval *mysql_stmt; - MYSQL_BIND *bind; + zval ***args; + int argc = ZEND_NUM_ARGS(); + int num_vars; + int start = 2; + MY_STMT *stmt; + zval *mysql_stmt; + char *types; + int types_len; + unsigned long rc; - if (getThis()) { - start = 0; + /* calculate and check number of parameters */ + if (argc < 2) { + /* there has to be at least one pair */ + WRONG_PARAM_COUNT; } - if (zend_parse_method_parameters((getThis()) ? 0:1 TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { + if (zend_parse_method_parameters((getThis()) ? 1:2 TSRMLS_CC, getThis(), "Os", &mysql_stmt, mysqli_stmt_class_entry, + &types, &types_len) == FAILURE) { return; } - MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); + MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); - if (argc < (getThis() ? 1 : 2)) { - WRONG_PARAM_COUNT; + num_vars = argc - 1; + if (getThis()) { + start = 1; + } else { + /* ignore handle parameter in procedural interface*/ + --num_vars; + } + if (!types_len) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid type or no types specified"); + RETURN_FALSE; + } + + if (types_len != argc - start) { + /* number of bind variables doesn't match number of elements in type definition string */ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of elements in type definition string doesn't match number of bind variables"); + RETURN_FALSE; + } + + if (types_len != mysql_stmt_param_count(stmt->stmt)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of variables doesn't match number of parameters in prepared statement"); + RETURN_FALSE; } args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); if (zend_get_parameters_array_ex(argc, args) == FAILURE) { - efree(args); - WRONG_PARAM_COUNT; + zend_wrong_param_count(TSRMLS_C); + rc = 1; + } else { + rc = mysqli_stmt_bind_param_do_bind(stmt, argc, num_vars, args, start, types TSRMLS_CC); + MYSQLI_REPORT_STMT_ERROR(stmt->stmt); } - var_cnt = argc - start; + efree(args); - if (var_cnt != mysql_stmt_field_count(stmt->stmt)) { - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of bind variables doesn't match number of fields in prepared statement"); - efree(args); - RETURN_FALSE; - } + RETURN_BOOL(!rc); +} +/* }}} */ + +/* {{{ mysqli_stmt_bind_result_do_bind */ +#ifndef HAVE_MYSQLND +/* TODO: + do_alloca, free_alloca +*/ +static int +mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval ***args, unsigned int argc, unsigned int start TSRMLS_DC) +{ + MYSQL_BIND *bind; + int i, ofs; + int var_cnt = argc - start; + long col_type; + ulong rc; /* prevent leak if variables are already bound */ if (stmt->result.var_cnt) { @@ -268,7 +304,7 @@ PHP_FUNCTION(mysqli_stmt_bind_result) convert_to_double_ex(args[i]); stmt->result.buf[ofs].type = IS_DOUBLE; stmt->result.buf[ofs].buflen = sizeof(double); - + /* allocate buffer for double */ stmt->result.buf[ofs].val = (char *)emalloc(sizeof(double)); bind[ofs].buffer_type = MYSQL_TYPE_DOUBLE; @@ -305,7 +341,7 @@ PHP_FUNCTION(mysqli_stmt_bind_result) break; case MYSQL_TYPE_LONGLONG: -#if MYSQL_VERSION_ID > 50002 +#if MYSQL_VERSION_ID > 50002 || defined(HAVE_MYSQLND) case MYSQL_TYPE_BIT: #endif stmt->result.buf[ofs].type = IS_STRING; @@ -324,8 +360,8 @@ PHP_FUNCTION(mysqli_stmt_bind_result) case MYSQL_TYPE_NEWDATE: case MYSQL_TYPE_VAR_STRING: case MYSQL_TYPE_STRING: - case MYSQL_TYPE_BLOB: case MYSQL_TYPE_TINY_BLOB: + case MYSQL_TYPE_BLOB: case MYSQL_TYPE_MEDIUM_BLOB: case MYSQL_TYPE_LONG_BLOB: case MYSQL_TYPE_TIMESTAMP: @@ -385,7 +421,6 @@ PHP_FUNCTION(mysqli_stmt_bind_result) } /* Don't free stmt->result.is_null because is_null & buf are one block of memory */ efree(stmt->result.buf); - RETVAL_FALSE; } else { stmt->result.var_cnt = var_cnt; stmt->result.vars = (zval **)safe_emalloc((var_cnt), sizeof(zval), 0); @@ -394,10 +429,69 @@ PHP_FUNCTION(mysqli_stmt_bind_result) ZVAL_ADDREF(*args[i]); stmt->result.vars[ofs] = *args[i]; } - RETVAL_TRUE; } - efree(args); efree(bind); + + return rc; +} +#else +static int +mysqli_stmt_bind_result_do_bind(MY_STMT *stmt, zval ***args, unsigned int argc, unsigned int start TSRMLS_DC) +{ + unsigned int i; + MYSQLND_RESULT_BIND *params; + + params = emalloc((argc - start) * sizeof(MYSQLND_RESULT_BIND)); + for (i = 0; i < (argc - start); i++) { + params[i].zv = *(args[i + start]); + } + return mysqlnd_stmt_bind_result(stmt->stmt, params); +} +#endif +/* }}} */ + +/* {{{ proto bool mysqli_stmt_bind_result(object stmt, mixed var, [,mixed, ...]) U + Bind variables to a prepared statement for result storage */ +PHP_FUNCTION(mysqli_stmt_bind_result) +{ + zval ***args; + int argc = ZEND_NUM_ARGS(); + int start = 1; + ulong rc; + MY_STMT *stmt; + zval *mysql_stmt; + + if (getThis()) { + start = 0; + } + + if (zend_parse_method_parameters((getThis()) ? 0:1 TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { + return; + } + + MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); + + if (argc < (getThis() ? 1 : 2)) { + WRONG_PARAM_COUNT; + } + + if ((argc - start) != mysql_stmt_field_count(stmt->stmt)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of bind variables doesn't match number of fields in prepared statement"); + RETURN_FALSE; + } + + args = (zval ***)safe_emalloc(argc, sizeof(zval **), 0); + + if (zend_get_parameters_array_ex(argc, args) == FAILURE) { + efree(args); + WRONG_PARAM_COUNT; + } + + rc = mysqli_stmt_bind_result_do_bind(stmt, args, argc, start TSRMLS_CC); + + efree(args); + + RETURN_BOOL(!rc); } /* }}} */ @@ -406,9 +500,9 @@ PHP_FUNCTION(mysqli_stmt_bind_result) PHP_FUNCTION(mysqli_change_user) { MY_MYSQL *mysql; - zval *mysql_link = NULL; - char *user, *password, *dbname; - int user_len, password_len, dbname_len; + zval *mysql_link = NULL; + char *user, *password, *dbname; + int user_len, password_len, dbname_len; ulong rc; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osss", &mysql_link, mysqli_link_class_entry, &user, &user_len, &password, &password_len, &dbname, &dbname_len) == FAILURE) { @@ -431,8 +525,8 @@ PHP_FUNCTION(mysqli_change_user) Returns the name of the character set used for this connection */ PHP_FUNCTION(mysqli_character_set_name) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -440,7 +534,7 @@ PHP_FUNCTION(mysqli_character_set_name) MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - RETURN_STRING((char *) mysql_character_set_name(mysql->mysql), 1); + RETURN_STRING((char *)mysql_character_set_name(mysql->mysql), 1); } /* }}} */ @@ -448,8 +542,8 @@ PHP_FUNCTION(mysqli_character_set_name) Close connection */ PHP_FUNCTION(mysqli_close) { - zval *mysql_link; - MY_MYSQL *mysql; + zval *mysql_link; + MY_MYSQL *mysql; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -457,11 +551,32 @@ PHP_FUNCTION(mysqli_close) MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_INITIALIZED); - mysql_close(mysql->mysql); - mysql->mysql = NULL; + 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); - MYSQLI_CLEAR_RESOURCE(&mysql_link); RETURN_TRUE; } /* }}} */ @@ -470,8 +585,8 @@ PHP_FUNCTION(mysqli_close) Commit outstanding actions and close transaction */ PHP_FUNCTION(mysqli_commit) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -489,8 +604,8 @@ PHP_FUNCTION(mysqli_commit) PHP_FUNCTION(mysqli_data_seek) { MYSQL_RES *result; - zval *mysql_result; - long offset; + zval *mysql_result; + long offset; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) { return; @@ -498,13 +613,13 @@ PHP_FUNCTION(mysqli_data_seek) MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); - if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT) { + if (mysqli_result_is_unbuffered(result)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT"); RETURN_FALSE; } - if (offset < 0 || offset >= result->row_count) { - RETURN_FALSE; + if (offset < 0 || offset >= mysql_num_rows(result)) { + RETURN_FALSE; } mysql_data_seek(result, offset); @@ -512,12 +627,12 @@ PHP_FUNCTION(mysqli_data_seek) } /* }}} */ -/* {{{ proto void mysqli_debug(string debug) +/* {{{ proto void mysqli_debug(string debug) U */ PHP_FUNCTION(mysqli_debug) { - char *debug; - int debug_len; + char *debug; + int debug_len; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &debug, &debug_len) == FAILURE) { return; @@ -528,25 +643,20 @@ PHP_FUNCTION(mysqli_debug) } /* }}} */ + /* {{{ proto bool mysqli_dump_debug_info(object link) */ PHP_FUNCTION(mysqli_dump_debug_info) { - MY_MYSQL *mysql; - zval *mysql_link; - ulong rc; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - rc = mysql_dump_debug_info(mysql->mysql); - - if (rc) { - RETURN_FALSE; - } - RETURN_TRUE; + RETURN_BOOL(!mysql_dump_debug_info(mysql->mysql)) } /* }}} */ @@ -554,8 +664,8 @@ PHP_FUNCTION(mysqli_dump_debug_info) Returns the numerical value of the error message from previous MySQL operation */ PHP_FUNCTION(mysqli_errno) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -569,8 +679,8 @@ PHP_FUNCTION(mysqli_errno) Returns the text of the error message from previous MySQL operation */ PHP_FUNCTION(mysqli_error) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -584,16 +694,19 @@ PHP_FUNCTION(mysqli_error) Execute a prepared statement */ PHP_FUNCTION(mysqli_stmt_execute) { - MY_STMT *stmt; - zval *mysql_stmt; - unsigned int i; + MY_STMT *stmt; + zval *mysql_stmt; +#ifndef HAVE_MYSQLND + unsigned int i; +#endif if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); - - for (i = 0; i < stmt->param.var_cnt; i++) { + +#ifndef HAVE_MYSQLND + for (i = 0; i < stmt->param.var_cnt; i++) { if (stmt->param.vars[i]) { if ( !(stmt->param.is_null[i] = (stmt->param.vars[i]->type == IS_NULL)) ) { switch (stmt->stmt->params[i].buffer_type) { @@ -604,40 +717,43 @@ PHP_FUNCTION(mysqli_stmt_execute) break; case MYSQL_TYPE_DOUBLE: convert_to_double_ex(&stmt->param.vars[i]); - stmt->stmt->params[i].buffer = (char*)&Z_LVAL_PP(&stmt->param.vars[i]); + stmt->stmt->params[i].buffer = &Z_LVAL_PP(&stmt->param.vars[i]); break; case MYSQL_TYPE_LONG: convert_to_long_ex(&stmt->param.vars[i]); - stmt->stmt->params[i].buffer = (char*)&Z_LVAL_PP(&stmt->param.vars[i]); + stmt->stmt->params[i].buffer = &Z_LVAL_PP(&stmt->param.vars[i]); break; default: break; } - } + } } } +#endif + if (mysql_stmt_execute(stmt->stmt)) { MYSQLI_REPORT_STMT_ERROR(stmt->stmt); - RETURN_FALSE; + RETVAL_FALSE; + } else { + RETVAL_TRUE; } if (MyG(report_mode) & MYSQLI_REPORT_INDEX) { - php_mysqli_report_index(stmt->query, stmt->stmt->mysql->server_status TSRMLS_CC); + php_mysqli_report_index(stmt->query, mysqli_stmt_server_status(stmt->stmt) TSRMLS_CC); } - - RETURN_TRUE; } /* }}} */ -/* {{{ proto mixed mysqli_stmt_fetch(object stmt) +#ifndef HAVE_MYSQLND +/* {{{ void mysqli_stmt_fetch_libmysql Fetch results from a prepared statement into the bound variables */ -PHP_FUNCTION(mysqli_stmt_fetch) +void mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAMETERS) { - MY_STMT *stmt; - zval *mysql_stmt; - unsigned int i; - ulong ret; - unsigned int uval; + MY_STMT *stmt; + zval *mysql_stmt; + unsigned int i; + ulong ret; + unsigned int uval; my_ulonglong llval; @@ -647,8 +763,6 @@ PHP_FUNCTION(mysqli_stmt_fetch) MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); /* reset buffers */ - - for (i = 0; i < stmt->result.var_cnt; i++) { if (stmt->result.buf[i].type == IS_STRING) { memset(stmt->result.buf[i].val, 0, stmt->result.buf[i].buflen); @@ -661,6 +775,11 @@ PHP_FUNCTION(mysqli_stmt_fetch) if (!ret) { #endif for (i = 0; i < stmt->result.var_cnt; i++) { + /* + QQ: Isn't it quite better to call zval_dtor(). What if the user has + assigned a resource, or an array to the bound variable? We are going + to leak probably. zval_dtor() will handle also Unicode/Non-unicode mode. + */ /* Even if the string is of length zero there is one byte alloced so efree() in all cases */ if (Z_TYPE_P(stmt->result.vars[i]) == IS_STRING) { efree(stmt->result.vars[i]->value.str.val); @@ -669,11 +788,11 @@ PHP_FUNCTION(mysqli_stmt_fetch) switch (stmt->result.buf[i].type) { case IS_LONG: if ((stmt->stmt->fields[i].type == MYSQL_TYPE_LONG) - && (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)) + && (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)) { /* unsigned int (11) */ uval= *(unsigned int *) stmt->result.buf[i].val; - +#if SIZEOF_LONG==4 if (uval > INT_MAX) { char *tmp, *p; int j=10; @@ -681,13 +800,14 @@ PHP_FUNCTION(mysqli_stmt_fetch) p= &tmp[9]; do { *p-- = (uval % 10) + 48; - uval = uval / 10; + uval = uval / 10; } while (--j > 0); tmp[10]= '\0'; - /* unsigned int > INT_MAX is 10 digis - ALWAYS */ + /* unsigned int > INT_MAX is 10 digits - ALWAYS */ ZVAL_STRINGL(stmt->result.vars[i], tmp, 10, 0); break; } +#endif } if (stmt->stmt->fields[i].flags & UNSIGNED_FLAG) { ZVAL_LONG(stmt->result.vars[i], *(unsigned int *)stmt->result.buf[i].val); @@ -702,11 +822,12 @@ PHP_FUNCTION(mysqli_stmt_fetch) if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_LONGLONG) { my_bool uns= (stmt->stmt->fields[i].flags & UNSIGNED_FLAG)? 1:0; llval= *(my_ulonglong *) stmt->result.buf[i].val; -#if SIZEOF_LONG==8 +#if SIZEOF_LONG==8 if (uns && llval > 9223372036854775807L) { #elif SIZEOF_LONG==4 if ((uns && llval > L64(2147483647)) || - (!uns && (( L64(2147483647) < (my_longlong) llval) || (L64(-2147483648) > (my_longlong) llval)))) + (!uns && (( L64(2147483647) < (my_longlong) llval) || + (L64(-2147483648) > (my_longlong) llval)))) { #endif char tmp[22]; @@ -719,7 +840,7 @@ PHP_FUNCTION(mysqli_stmt_fetch) } else { ZVAL_LONG(stmt->result.vars[i], llval); } - } + } #if MYSQL_VERSION_ID > 50002 else if (stmt->stmt->bind[i].buffer_type == MYSQL_TYPE_BIT) { llval = *(my_ulonglong *)stmt->result.buf[i].val; @@ -728,19 +849,21 @@ PHP_FUNCTION(mysqli_stmt_fetch) #endif else { #if defined(MYSQL_DATA_TRUNCATED) && MYSQL_VERSION_ID > 50002 - if(ret == MYSQL_DATA_TRUNCATED && *(stmt->stmt->bind[i].error) != 0) { + if (ret == MYSQL_DATA_TRUNCATED && *(stmt->stmt->bind[i].error) != 0) { /* result was truncated */ - ZVAL_STRINGL(stmt->result.vars[i], stmt->result.buf[i].val, stmt->stmt->bind[i].buffer_length, 1); + ZVAL_STRINGL(stmt->result.vars[i], stmt->result.buf[i].val, + stmt->stmt->bind[i].buffer_length, 1); } else { #else { #endif - ZVAL_STRINGL(stmt->result.vars[i], stmt->result.buf[i].val, stmt->result.buf[i].buflen, 1); + ZVAL_STRINGL(stmt->result.vars[i], stmt->result.buf[i].val, + stmt->result.buf[i].buflen, 1); } } break; default: - break; + break; } } else { ZVAL_NULL(stmt->result.vars[i]); @@ -770,14 +893,68 @@ PHP_FUNCTION(mysqli_stmt_fetch) } } /* }}} */ +#else +/* {{{ mixed mysqli_stmt_fetch_mysqlnd */ +void mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAMETERS) +{ + MY_STMT *stmt; + zval *mysql_stmt; + zend_bool fetched_anything; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); + + if (FAIL == mysqlnd_stmt_fetch(stmt->stmt, &fetched_anything)) { + RETURN_BOOL(FALSE); + } else if (fetched_anything == TRUE) { + RETURN_BOOL(TRUE); + } else { + RETURN_NULL(); + } +} +#endif +/* }}} */ + + +/* {{{ proto mixed mysqli_stmt_fetch(object stmt) U + Fetch results from a prepared statement into the bound variables */ +PHP_FUNCTION(mysqli_stmt_fetch) +{ +#if !defined(HAVE_MYSQLND) + mysqli_stmt_fetch_libmysql(INTERNAL_FUNCTION_PARAM_PASSTHRU); +#else + mysqli_stmt_fetch_mysqlnd(INTERNAL_FUNCTION_PARAM_PASSTHRU); +#endif +} +/* }}} */ + +/* {{{ php_add_field_properties */ +static void php_add_field_properties(zval *value, MYSQL_FIELD *field TSRMLS_DC) +{ + add_property_string(value, "name",(field->name ? field->name : ""), 1); + add_property_string(value, "orgname",(field->org_name ? field->org_name : ""), 1); + add_property_string(value, "table",(field->table ? field->table : ""), 1); + add_property_string(value, "orgtable",(field->org_table ? field->org_table : ""), 1); + add_property_string(value, "def",(field->def ? field->def : ""), 1); + + add_property_long(value, "max_length", field->max_length); + add_property_long(value, "length", field->length); + add_property_long(value, "charsetnr", field->charsetnr); + add_property_long(value, "flags", field->flags); + add_property_long(value, "type", field->type); + add_property_long(value, "decimals", field->decimals); +} +/* }}} */ /* {{{ proto mixed mysqli_fetch_field (object result) Get column information from a result and return as an object */ PHP_FUNCTION(mysqli_fetch_field) { - MYSQL_RES *result; - zval *mysql_result; - MYSQL_FIELD *field; + MYSQL_RES *result; + zval *mysql_result; + MYSQL_FIELD *field; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) { return; @@ -790,18 +967,7 @@ PHP_FUNCTION(mysqli_fetch_field) } object_init(return_value); - - add_property_string(return_value, "name",(field->name ? field->name : ""), 1); - add_property_string(return_value, "orgname",(field->org_name ? field->org_name : ""), 1); - add_property_string(return_value, "table",(field->table ? field->table : ""), 1); - add_property_string(return_value, "orgtable",(field->org_table ? field->org_table : ""), 1); - add_property_string(return_value, "def",(field->def ? field->def : ""), 1); - add_property_long(return_value, "max_length", field->max_length); - add_property_long(return_value, "length", field->length); - add_property_long(return_value, "charsetnr", field->charsetnr); - add_property_long(return_value, "flags", field->flags); - add_property_long(return_value, "type", field->type); - add_property_long(return_value, "decimals", field->decimals); + php_add_field_properties(return_value, field TSRMLS_CC); } /* }}} */ @@ -810,9 +976,9 @@ PHP_FUNCTION(mysqli_fetch_field) PHP_FUNCTION(mysqli_fetch_fields) { MYSQL_RES *result; - zval *mysql_result; + zval *mysql_result; MYSQL_FIELD *field; - zval *obj; + zval *obj; unsigned int i; @@ -827,22 +993,10 @@ PHP_FUNCTION(mysqli_fetch_fields) for (i = 0; i < mysql_num_fields(result); i++) { field = mysql_fetch_field_direct(result, i); - MAKE_STD_ZVAL(obj); object_init(obj); - add_property_string(obj, "name",(field->name ? field->name : ""), 1); - add_property_string(obj, "orgname",(field->org_name ? field->org_name : ""), 1); - add_property_string(obj, "table",(field->table ? field->table : ""), 1); - add_property_string(obj, "orgtable",(field->org_table ? field->org_table : ""), 1); - add_property_string(obj, "def",(field->def ? field->def : ""), 1); - add_property_long(obj, "max_length", field->max_length); - add_property_long(obj, "length", field->length); - add_property_long(obj, "charsetnr", field->charsetnr); - add_property_long(obj, "flags", field->flags); - add_property_long(obj, "type", field->type); - add_property_long(obj, "decimals", field->decimals); - + php_add_field_properties(obj, field TSRMLS_CC); add_index_zval(return_value, i, obj); } } @@ -854,8 +1008,8 @@ PHP_FUNCTION(mysqli_fetch_field_direct) { MYSQL_RES *result; zval *mysql_result; - MYSQL_FIELD *field; - long offset; + MYSQL_FIELD *field; + long offset; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &mysql_result, mysqli_result_class_entry, &offset) == FAILURE) { return; @@ -873,18 +1027,7 @@ PHP_FUNCTION(mysqli_fetch_field_direct) } object_init(return_value); - - add_property_string(return_value, "name",(field->name ? field->name : ""), 1); - add_property_string(return_value, "orgname",(field->org_name ? field->org_name : ""), 1); - add_property_string(return_value, "table",(field->table ? field->table : ""), 1); - add_property_string(return_value, "orgtable",(field->org_table ? field->org_table : ""), 1); - add_property_string(return_value, "def",(field->def ? field->def : ""), 1); - add_property_long(return_value, "max_length", field->max_length); - add_property_long(return_value, "length", field->length); - add_property_long(return_value, "charsetnr", field->charsetnr); - add_property_long(return_value, "flags", field->flags); - add_property_long(return_value, "type", field->type); - add_property_long(return_value, "decimals", field->decimals); + php_add_field_properties(return_value, field TSRMLS_CC); } /* }}} */ @@ -896,7 +1039,7 @@ PHP_FUNCTION(mysqli_fetch_lengths) zval *mysql_result; unsigned int i; unsigned long *ret; - + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) { return; } @@ -910,7 +1053,7 @@ PHP_FUNCTION(mysqli_fetch_lengths) array_init(return_value); for (i = 0; i < mysql_num_fields(result); i++) { - add_index_long(return_value, i, ret[i]); + add_index_long(return_value, i, ret[i]); } } /* }}} */ @@ -919,17 +1062,28 @@ PHP_FUNCTION(mysqli_fetch_lengths) Get a result row as an enumerated array */ PHP_FUNCTION(mysqli_fetch_row) { +#if !defined(HAVE_MYSQLND) php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_NUM, 0); +#else + MYSQL_RES *result; + zval *mysql_result; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); + mysqlnd_fetch_into(result, MYSQLND_FETCH_NUM, return_value, MYSQLND_MYSQLI); +#endif } /* }}} */ /* {{{ proto int mysqli_field_count(object link) Fetch the number of fields returned by the last query for the given link */ -PHP_FUNCTION(mysqli_field_count) +PHP_FUNCTION(mysqli_field_count) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -958,7 +1112,7 @@ PHP_FUNCTION(mysqli_field_seek) php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid field offset"); RETURN_FALSE; } - + mysql_field_seek(result, fieldnr); RETURN_TRUE; } @@ -975,7 +1129,7 @@ PHP_FUNCTION(mysqli_field_tell) return; } MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); - + RETURN_LONG(mysql_field_tell(result)); } /* }}} */ @@ -992,12 +1146,12 @@ PHP_FUNCTION(mysqli_free_result) } MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); - mysql_free_result(result); - MYSQLI_CLEAR_RESOURCE(&mysql_result); + mysqli_free_result(result, FALSE); + MYSQLI_CLEAR_RESOURCE(&mysql_result); } /* }}} */ -/* {{{ proto string mysqli_get_client_info(void) +/* {{{ proto string mysqli_get_client_info(void) Get MySQL client info */ PHP_FUNCTION(mysqli_get_client_info) { @@ -1005,7 +1159,7 @@ PHP_FUNCTION(mysqli_get_client_info) } /* }}} */ -/* {{{ proto int mysqli_get_client_version(void) +/* {{{ proto int mysqli_get_client_version(void) Get MySQL client info */ PHP_FUNCTION(mysqli_get_client_version) { @@ -1018,7 +1172,7 @@ PHP_FUNCTION(mysqli_get_client_version) PHP_FUNCTION(mysqli_get_host_info) { MY_MYSQL *mysql; - zval *mysql_link = NULL; + zval *mysql_link = NULL; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1033,24 +1187,23 @@ PHP_FUNCTION(mysqli_get_host_info) Get MySQL protocol information */ PHP_FUNCTION(mysqli_get_proto_info) { - MY_MYSQL *mysql; - zval *mysql_link = NULL; + MY_MYSQL *mysql; + zval *mysql_link = NULL; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - RETURN_LONG(mysql_get_proto_info(mysql->mysql)); } /* }}} */ -/* {{{ proto string mysqli_get_server_info(object link) +/* {{{ proto string mysqli_get_server_info(object link) Get MySQL server info */ PHP_FUNCTION(mysqli_get_server_info) { MY_MYSQL *mysql; - zval *mysql_link = NULL; + zval *mysql_link = NULL; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1083,14 +1236,16 @@ PHP_FUNCTION(mysqli_get_server_version) PHP_FUNCTION(mysqli_info) { MY_MYSQL *mysql; - zval *mysql_link = NULL; + zval *mysql_link = NULL; + const char *info; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - RETURN_STRING((mysql->mysql->info) ? mysql->mysql->info : "", 1); + info = mysql_info(mysql->mysql); + RETURN_STRING((info) ? (char *)info : "", 1); } /* }}} */ @@ -1101,7 +1256,12 @@ PHP_FUNCTION(mysqli_init) MYSQLI_RESOURCE *mysqli_resource; MY_MYSQL *mysql = (MY_MYSQL *)ecalloc(1, sizeof(MY_MYSQL)); - if (!(mysql->mysql = mysql_init(NULL))) { +#if !defined(HAVE_MYSQLND) + if (!(mysql->mysql = mysql_init(NULL))) +#else + if (!(mysql->mysql = mysql_init(FALSE))) +#endif + { efree(mysql); RETURN_FALSE; } @@ -1123,8 +1283,8 @@ PHP_FUNCTION(mysqli_init) PHP_FUNCTION(mysqli_insert_id) { MY_MYSQL *mysql; - my_ulonglong rc; - zval *mysql_link; + my_ulonglong rc; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1139,15 +1299,20 @@ PHP_FUNCTION(mysqli_insert_id) Kill a mysql process on the server */ PHP_FUNCTION(mysqli_kill) { - MY_MYSQL *mysql; - zval *mysql_link; - long processid; + MY_MYSQL *mysql; + zval *mysql_link; + long processid; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &mysql_link, mysqli_link_class_entry, &processid) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - + + if (processid <= 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "processid should have positive value"); + RETURN_FALSE; + } + if (mysql_kill(mysql->mysql, processid)) { MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); RETURN_FALSE; @@ -1158,6 +1323,7 @@ PHP_FUNCTION(mysqli_kill) /* {{{ proto void mysqli_set_local_infile_default(object link) unsets user defined handler for load local infile command */ +#if !defined(HAVE_MYSQLND) PHP_FUNCTION(mysqli_set_local_infile_default) { MY_MYSQL *mysql; @@ -1182,7 +1348,7 @@ PHP_FUNCTION(mysqli_set_local_infile_default) PHP_FUNCTION(mysqli_set_local_infile_handler) { MY_MYSQL *mysql; - zval *mysql_link; + zval *mysql_link; char *callback_name; zval *callback_func; @@ -1197,24 +1363,29 @@ PHP_FUNCTION(mysqli_set_local_infile_handler) if (!zend_is_callable(callback_func, 0, &callback_name)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Not a valid callback function %s", callback_name); efree(callback_name); - RETURN_FALSE; + RETURN_FALSE; } efree(callback_name); /* save callback function */ - ALLOC_ZVAL(mysql->li_read); - ZVAL_STRING(mysql->li_read, callback_func->value.str.val, 1); + 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); RETURN_TRUE; } +#endif /* }}} */ /* {{{ proto bool mysqli_more_results(object link) check if there any more query results from a multi query */ PHP_FUNCTION(mysqli_more_results) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1228,14 +1399,20 @@ PHP_FUNCTION(mysqli_more_results) /* {{{ proto bool mysqli_next_result(object link) read next result from multi_query */ PHP_FUNCTION(mysqli_next_result) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); + if (!mysql_more_results(mysql->mysql)) { + php_error_docref(NULL TSRMLS_CC, E_STRICT, "There is no next result set. " + "Please, call mysqli_more_results()/mysqli::more_results() to check " + "whether to call this function/method"); + } + RETURN_BOOL(!mysql_next_result(mysql->mysql)); } /* }}} */ @@ -1268,7 +1445,7 @@ PHP_FUNCTION(mysqli_num_rows) } MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); - if (result->handle && result->handle->status == MYSQL_STATUS_USE_RESULT) { + if (mysqli_result_is_unbuffered(result)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "Function cannot be used with MYSQL_USE_RESULT"); RETURN_LONG(0); } @@ -1281,12 +1458,12 @@ PHP_FUNCTION(mysqli_num_rows) Set options */ PHP_FUNCTION(mysqli_options) { - MY_MYSQL *mysql; - zval *mysql_link = NULL; - zval *mysql_value; - long mysql_option; - unsigned int l_value; - long ret; + MY_MYSQL *mysql; + zval *mysql_link = NULL; + zval *mysql_value; + long mysql_option; + unsigned int l_value; + long ret; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Olz", &mysql_link, mysqli_link_class_entry, &mysql_option, &mysql_value) == FAILURE) { return; @@ -1311,7 +1488,7 @@ PHP_FUNCTION(mysqli_options) } RETURN_BOOL(!ret); -} +} /* }}} */ @@ -1319,8 +1496,8 @@ PHP_FUNCTION(mysqli_options) Ping a server connection or reconnect if there is no connection */ PHP_FUNCTION(mysqli_ping) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; long rc; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { @@ -1339,60 +1516,71 @@ PHP_FUNCTION(mysqli_ping) PHP_FUNCTION(mysqli_prepare) { MY_MYSQL *mysql; - MY_STMT *stmt; + MY_STMT *stmt; char *query = NULL; unsigned int query_len; zval *mysql_link; - MYSQLI_RESOURCE *mysqli_resource; + MYSQLI_RESOURCE *mysqli_resource; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os",&mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); + +#if !defined(HAVE_MYSQLND) if (mysql->mysql->status == MYSQL_STATUS_GET_RESULT) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "All data must be fetched before a new statement prepare takes place"); RETURN_FALSE; } +#endif stmt = (MY_STMT *)ecalloc(1,sizeof(MY_STMT)); if ((stmt->stmt = mysql_stmt_init(mysql->mysql))) { if (mysql_stmt_prepare(stmt->stmt, query, query_len)) { - char last_error[MYSQL_ERRMSG_SIZE]; - char sqlstate[SQLSTATE_LENGTH+1]; + /* mysql_stmt_close() clears errors, so we have to store them temporarily */ +#if !defined(HAVE_MYSQLND) + char last_error[MYSQL_ERRMSG_SIZE]; + char sqlstate[SQLSTATE_LENGTH+1]; unsigned int last_errno; - /* mysql_stmt_close clears errors, so we have to store them temporarily */ last_errno = stmt->stmt->last_errno; memcpy(last_error, stmt->stmt->last_error, MYSQL_ERRMSG_SIZE); memcpy(sqlstate, mysql->mysql->net.sqlstate, SQLSTATE_LENGTH+1); - - mysql_stmt_close(stmt->stmt); +#else + mysqlnd_error_info error_info = mysql->mysql->error_info; +#endif + mysqli_stmt_close(stmt->stmt, FALSE); stmt->stmt = NULL; /* restore error messages */ +#if !defined(HAVE_MYSQLND) mysql->mysql->net.last_errno = last_errno; memcpy(mysql->mysql->net.last_error, last_error, MYSQL_ERRMSG_SIZE); memcpy(mysql->mysql->net.sqlstate, sqlstate, SQLSTATE_LENGTH+1); +#else + mysql->mysql->error_info = error_info; +#endif } } - /* don't joing to the previous if because it won't work if mysql_stmt_prepare_fails */ + + /* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */ + /* Get performance boost if reporting is switched off */ + if (stmt->stmt && query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) { + stmt->query = (char *)emalloc(query_len + 1); + memcpy(stmt->query, query, query_len); + stmt->query[query_len] = '\0'; + } + + /* don't join to the previous if because it won't work if mysql_stmt_prepare_fails */ if (!stmt->stmt) { MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); efree(stmt); RETURN_FALSE; } - mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = (void *)stmt; - /* don't initialize stmt->query with NULL, we ecalloc()-ed the memory */ - /* Get performance boost if reporting is switched off */ - if (query_len && (MyG(report_mode) & MYSQLI_REPORT_INDEX)) { - stmt->query = (char *)emalloc(query_len + 1); - memcpy(stmt->query, query, query_len); - stmt->query[query_len] = '\0'; - } /* change status */ mysqli_resource->status = MYSQLI_STATUS_VALID; @@ -1404,10 +1592,10 @@ PHP_FUNCTION(mysqli_prepare) Open a connection to a mysql server */ PHP_FUNCTION(mysqli_real_connect) { - MY_MYSQL *mysql; - 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; - unsigned long port=0, flags=0; + MY_MYSQL *mysql; + 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; + unsigned long port=0, flags=0; zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|sssslsl", &mysql_link, mysqli_link_class_entry, @@ -1419,37 +1607,38 @@ PHP_FUNCTION(mysqli_real_connect) if (!socket_len) { socket = NULL; } - - /* TODO: safe mode handling */ - if (PG(sql_safe_mode)) { - } else { - if (!passwd) { - passwd = MyG(default_pw); - if (!username){ - username = MyG(default_user); - if (!hostname) { - hostname = MyG(default_host); - } - } - } + if (!socket) { + socket = MyG(default_socket); } + if (!passwd) { + passwd = MyG(default_pw); + passwd_len = strlen(passwd); + } + if (!username){ + username = MyG(default_user); + } + if (!hostname) { + hostname = MyG(default_host); + } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_INITIALIZED); /* remove some insecure options */ flags &= ~CLIENT_MULTI_STATEMENTS; /* don't allow multi_queries via connect parameter */ - if ((PG(open_basedir) && PG(open_basedir)[0] != '\0') || PG(safe_mode)) { - flags &= ~CLIENT_LOCAL_FILES; - } - - if (!socket) { - socket = MyG(default_socket); + if (PG(open_basedir) && PG(open_basedir)[0] != '\0') { + flags ^= CLIENT_LOCAL_FILES; } - if (mysql_real_connect(mysql->mysql,hostname,username,passwd,dbname,port,socket,flags) == NULL) { +#if !defined(HAVE_MYSQLND) + if (mysql_real_connect(mysql->mysql, hostname, username, passwd, dbname ,port, socket ,flags) == NULL) +#else + if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len, + port, socket, flags, MyG(mysqlnd_thd_zval_cache) TSRMLS_CC) == NULL) +#endif + { php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql) TSRMLS_CC); - php_mysqli_throw_sql_exception( mysql->mysql->net.sqlstate, mysql->mysql->net.last_errno TSRMLS_CC, - "%s", mysql->mysql->net.last_error); + php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC, + "%s", mysql_error(mysql->mysql)); /* change status */ MYSQLI_SET_STATUS(&mysql_link, MYSQLI_STATUS_INITIALIZED); @@ -1458,10 +1647,14 @@ PHP_FUNCTION(mysqli_real_connect) php_mysqli_set_error(mysql_errno(mysql->mysql), (char *)mysql_error(mysql->mysql) TSRMLS_CC); +#if !defined(HAVE_MYSQLND) mysql->mysql->reconnect = MyG(reconnect); /* set our own local_infile handler */ php_set_local_infile_handler_default(mysql); +#endif + + mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&MyG(allow_local_infile)); /* change status */ MYSQLI_SET_STATUS(&mysql_link, MYSQLI_STATUS_VALID); @@ -1477,7 +1670,7 @@ PHP_FUNCTION(mysqli_real_query) MY_MYSQL *mysql; zval *mysql_link; char *query = NULL; - unsigned int query_len; + unsigned int query_len; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &mysql_link, mysqli_link_class_entry, &query, &query_len) == FAILURE) { return; @@ -1493,7 +1686,7 @@ PHP_FUNCTION(mysqli_real_query) if (!mysql_field_count(mysql->mysql)) { if (MyG(report_mode) & MYSQLI_REPORT_INDEX) { - php_mysqli_report_index(query, mysql->mysql->server_status TSRMLS_CC); + php_mysqli_report_index(query, mysqli_server_status(mysql->mysql) TSRMLS_CC); } } @@ -1517,7 +1710,7 @@ PHP_FUNCTION(mysqli_real_escape_string) { newstr = safe_emalloc(2, escapestr_len, 1); newstr_len = mysql_real_escape_string(mysql->mysql, newstr, escapestr, escapestr_len); newstr = erealloc(newstr, newstr_len + 1); - + RETURN_STRINGL(newstr, newstr_len, 0); } /* }}} */ @@ -1527,7 +1720,7 @@ PHP_FUNCTION(mysqli_real_escape_string) { PHP_FUNCTION(mysqli_rollback) { MY_MYSQL *mysql; - zval *mysql_link; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1546,12 +1739,11 @@ PHP_FUNCTION(mysqli_rollback) PHP_FUNCTION(mysqli_stmt_send_long_data) { MY_STMT *stmt; - zval *mysql_stmt; + zval *mysql_stmt; char *data; long param_nr; int data_len; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ols", &mysql_stmt, mysqli_stmt_class_entry, ¶m_nr, &data, &data_len) == FAILURE) { return; } @@ -1573,8 +1765,8 @@ PHP_FUNCTION(mysqli_stmt_send_long_data) Return the number of rows affected in the last query for the given link */ PHP_FUNCTION(mysqli_stmt_affected_rows) { - MY_STMT *stmt; - zval *mysql_stmt; + MY_STMT *stmt; + zval *mysql_stmt; my_ulonglong rc; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { @@ -1590,21 +1782,21 @@ PHP_FUNCTION(mysqli_stmt_affected_rows) } /* }}} */ -/* {{{ proto bool mysqli_stmt_close(object stmt) +/* {{{ proto bool mysqli_stmt_close(object stmt) Close statement */ PHP_FUNCTION(mysqli_stmt_close) { - MY_STMT *stmt; - zval *mysql_stmt; + MY_STMT *stmt; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); - mysql_stmt_close(stmt->stmt); + mysqli_stmt_close(stmt->stmt, FALSE); stmt->stmt = NULL; - php_clear_stmt_bind(stmt); + php_clear_stmt_bind(stmt TSRMLS_CC); MYSQLI_CLEAR_RESOURCE(&mysql_stmt); RETURN_TRUE; } @@ -1614,9 +1806,9 @@ PHP_FUNCTION(mysqli_stmt_close) Move internal result pointer */ PHP_FUNCTION(mysqli_stmt_data_seek) { - MY_STMT *stmt; - zval *mysql_stmt; - long offset; + MY_STMT *stmt; + zval *mysql_stmt; + long offset; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Ol", &mysql_stmt, mysqli_stmt_class_entry, &offset) == FAILURE) { return; @@ -1636,7 +1828,7 @@ PHP_FUNCTION(mysqli_stmt_data_seek) Return the number of result columns for the given statement */ PHP_FUNCTION(mysqli_stmt_field_count) { - MY_STMT *stmt; + MY_STMT *stmt; zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { @@ -1652,8 +1844,8 @@ PHP_FUNCTION(mysqli_stmt_field_count) Free stored result memory for the given statement handle */ PHP_FUNCTION(mysqli_stmt_free_result) { - MY_STMT *stmt; - zval *mysql_stmt; + MY_STMT *stmt; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; @@ -1669,9 +1861,9 @@ PHP_FUNCTION(mysqli_stmt_free_result) Get the ID generated from the previous INSERT operation */ PHP_FUNCTION(mysqli_stmt_insert_id) { - MY_STMT *stmt; - my_ulonglong rc; - zval *mysql_stmt; + MY_STMT *stmt; + my_ulonglong rc; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; @@ -1682,13 +1874,13 @@ PHP_FUNCTION(mysqli_stmt_insert_id) } /* }}} */ -/* {{{ proto int mysqli_stmt_param_count(object stmt) { +/* {{{ proto int mysqli_stmt_param_count(object stmt) Return the number of parameter for the given statement */ PHP_FUNCTION(mysqli_stmt_param_count) { - MY_STMT *stmt; + MY_STMT *stmt; zval *mysql_stmt; - + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } @@ -1700,10 +1892,10 @@ PHP_FUNCTION(mysqli_stmt_param_count) /* {{{ proto bool mysqli_stmt_reset(object stmt) reset a prepared statement */ -PHP_FUNCTION(mysqli_stmt_reset) +PHP_FUNCTION(mysqli_stmt_reset) { - MY_STMT *stmt; - zval *mysql_stmt; + MY_STMT *stmt; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; @@ -1722,8 +1914,8 @@ PHP_FUNCTION(mysqli_stmt_reset) Return the number of rows in statements result set */ PHP_FUNCTION(mysqli_stmt_num_rows) { - MY_STMT *stmt; - zval *mysql_stmt; + MY_STMT *stmt; + zval *mysql_stmt; my_ulonglong rc; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { @@ -1737,27 +1929,25 @@ PHP_FUNCTION(mysqli_stmt_num_rows) } /* }}} */ -/* {{{ proto string mysqli_select_db(object link, string dbname) +/* {{{ proto bool mysqli_select_db(object link, string dbname) Select a MySQL database */ PHP_FUNCTION(mysqli_select_db) { MY_MYSQL *mysql; - zval *mysql_link; - char *dbname; - int dbname_len; - + zval *mysql_link; + char *dbname; + int dbname_len; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Os", &mysql_link, mysqli_link_class_entry, &dbname, &dbname_len) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - - if (!mysql_select_db(mysql->mysql, dbname)) { - RETURN_TRUE; + + if (mysql_select_db(mysql->mysql, dbname)) { + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); + RETURN_FALSE; } - - MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); - RETURN_FALSE; + RETURN_TRUE; } /* }}} */ @@ -1765,8 +1955,8 @@ PHP_FUNCTION(mysqli_select_db) Returns the SQLSTATE error from previous MySQL operation */ PHP_FUNCTION(mysqli_sqlstate) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1776,21 +1966,22 @@ PHP_FUNCTION(mysqli_sqlstate) } /* }}} */ -/* {{{ proto bool mysqli_ssl_set(object link ,string key ,string cert ,string ca ,string capath ,string cipher]) +/* {{{ proto bool mysqli_ssl_set(object link ,string key ,string cert ,string ca ,string capath ,string cipher]) U */ +#if !defined(HAVE_MYSQLND) PHP_FUNCTION(mysqli_ssl_set) { MY_MYSQL *mysql; - zval *mysql_link; - char *ssl_parm[5]; + zval *mysql_link; + char *ssl_parm[5]; int ssl_parm_len[5], i; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Osssss", &mysql_link, mysqli_link_class_entry, &ssl_parm[0], &ssl_parm_len[0], &ssl_parm[1], &ssl_parm_len[1], &ssl_parm[2], &ssl_parm_len[2], &ssl_parm[3], &ssl_parm_len[3], &ssl_parm[4], &ssl_parm_len[4]) == FAILURE) { return; } - MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_INITIALIZED); + MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - for (i=0; i < 5; i++) { + for (i = 0; i < 5; i++) { if (!ssl_parm_len[i]) { ssl_parm[i] = NULL; } @@ -1800,25 +1991,37 @@ PHP_FUNCTION(mysqli_ssl_set) RETURN_TRUE; } +#endif /* }}} */ /* {{{ proto mixed mysqli_stat(object link) Get current system status */ PHP_FUNCTION(mysqli_stat) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; char *stat; +#if defined(HAVE_MYSQLND) + uint stat_len; +#endif if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); - if ((stat = (char *)mysql_stat(mysql->mysql))) { +#if !defined(HAVE_MYSQLND) + if ((stat = (char *)mysql_stat(mysql->mysql))) + { RETURN_STRING(stat, 1); +#else + if (mysqlnd_stat(mysql->mysql, &stat, &stat_len) == PASS) + { + RETURN_STRINGL(stat, stat_len, 0); +#endif + } else { + RETURN_FALSE; } - RETURN_FALSE; } /* }}} */ @@ -1828,16 +2031,23 @@ PHP_FUNCTION(mysqli_stat) PHP_FUNCTION(mysqli_stmt_attr_set) { MY_STMT *stmt; - zval *mysql_stmt; - ulong mode; + zval *mysql_stmt; + long mode_in; + ulong mode; ulong attr; int rc; - if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode) == FAILURE) { + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "Oll", &mysql_stmt, mysqli_stmt_class_entry, &attr, &mode_in) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); + if (mode_in < 0) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "mode should be non-negative, %ld passed", mode_in); + RETURN_FALSE; + } + + mode = mode_in; if ((rc = mysql_stmt_attr_set(stmt->stmt, attr, (void *)&mode))) { RETURN_FALSE; } @@ -1850,8 +2060,8 @@ PHP_FUNCTION(mysqli_stmt_attr_set) PHP_FUNCTION(mysqli_stmt_attr_get) { MY_STMT *stmt; - zval *mysql_stmt; -#if MYSQL_VERSION_ID > 50099 + zval *mysql_stmt; +#if !defined(HAVE_MYSQLND) && MYSQL_VERSION_ID > 50099 my_bool value; #else ulong value = 0; @@ -1876,7 +2086,7 @@ PHP_FUNCTION(mysqli_stmt_attr_get) PHP_FUNCTION(mysqli_stmt_errno) { MY_STMT *stmt; - zval *mysql_stmt; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; @@ -1909,9 +2119,9 @@ PHP_FUNCTION(mysqli_stmt_error) PHP_FUNCTION(mysqli_stmt_init) { MY_MYSQL *mysql; - MY_STMT *stmt; + MY_STMT *stmt; zval *mysql_link; - MYSQLI_RESOURCE *mysqli_resource; + MYSQLI_RESOURCE *mysqli_resource; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",&mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -1961,9 +2171,9 @@ PHP_FUNCTION(mysqli_stmt_prepare) return result set from statement */ PHP_FUNCTION(mysqli_stmt_result_metadata) { - MY_STMT *stmt; + MY_STMT *stmt; MYSQL_RES *result; - zval *mysql_stmt; + zval *mysql_stmt; MYSQLI_RESOURCE *mysqli_resource; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { @@ -1979,7 +2189,7 @@ PHP_FUNCTION(mysqli_stmt_result_metadata) mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = (void *)result; mysqli_resource->status = MYSQLI_STATUS_VALID; - MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); + MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); } /* }}} */ @@ -1987,32 +2197,37 @@ PHP_FUNCTION(mysqli_stmt_result_metadata) */ PHP_FUNCTION(mysqli_stmt_store_result) { - MY_STMT *stmt; - zval *mysql_stmt; - int i=0; + MY_STMT *stmt; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); - /* - If the user wants to store the data and we have BLOBs/TEXTs we try to allocate - not the maximal length of the type (which is 16MB even for LONGBLOB) but - the maximal length of the field in the result set. If he/she has quite big - BLOB/TEXT columns after calling store_result() the memory usage of PHP will - double - but this is a known problem of the simple MySQL API ;) - */ - for (i = mysql_stmt_field_count(stmt->stmt) - 1; i >=0; --i) { - 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; +#if !defined(HAVE_MYSQLND) + { + /* + If the user wants to store the data and we have BLOBs/TEXTs we try to allocate + not the maximal length of the type (which is 16MB even for LONGBLOB) but + the maximal length of the field in the result set. If he/she has quite big + BLOB/TEXT columns after calling store_result() the memory usage of PHP will + double - but this is a known problem of the simple MySQL API ;) + */ + 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 || + 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; + } } } +#endif if (mysql_stmt_store_result(stmt->stmt)){ MYSQLI_REPORT_STMT_ERROR(stmt->stmt); @@ -2024,16 +2239,16 @@ PHP_FUNCTION(mysqli_stmt_store_result) /* {{{ proto string mysqli_stmt_sqlstate(object stmt) */ -PHP_FUNCTION(mysqli_stmt_sqlstate) +PHP_FUNCTION(mysqli_stmt_sqlstate) { - MY_STMT *stmt; - zval *mysql_stmt; + MY_STMT *stmt; + zval *mysql_stmt; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { return; } MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); - + RETURN_STRING((char *)mysql_stmt_sqlstate(stmt->stmt),1); } /* }}} */ @@ -2042,9 +2257,9 @@ PHP_FUNCTION(mysqli_stmt_sqlstate) Buffer result set on client */ PHP_FUNCTION(mysqli_store_result) { - MY_MYSQL *mysql; - MYSQL_RES *result; - zval *mysql_link; + MY_MYSQL *mysql; + MYSQL_RES *result; + zval *mysql_link; MYSQLI_RESOURCE *mysqli_resource; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { @@ -2057,22 +2272,23 @@ PHP_FUNCTION(mysqli_store_result) RETURN_FALSE; } if (MyG(report_mode) & MYSQLI_REPORT_INDEX) { - php_mysqli_report_index("from previous query", mysql->mysql->server_status TSRMLS_CC); + php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql) TSRMLS_CC); } mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = (void *)result; mysqli_resource->status = MYSQLI_STATUS_VALID; - MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); + MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); } /* }}} */ + /* {{{ proto int mysqli_thread_id(object link) Return the current thread ID */ PHP_FUNCTION(mysqli_thread_id) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -2089,17 +2305,16 @@ PHP_FUNCTION(mysqli_thread_safe) { RETURN_BOOL(mysql_thread_safe()); } - /* }}} */ /* {{{ proto mixed mysqli_use_result(object link) Directly retrieve query results - do not buffer results on client side */ PHP_FUNCTION(mysqli_use_result) { - MY_MYSQL *mysql; - MYSQL_RES *result; - zval *mysql_link; - MYSQLI_RESOURCE *mysqli_resource; + MY_MYSQL *mysql; + MYSQL_RES *result; + zval *mysql_link; + MYSQLI_RESOURCE *mysqli_resource; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -2112,12 +2327,12 @@ PHP_FUNCTION(mysqli_use_result) } if (MyG(report_mode) & MYSQLI_REPORT_INDEX) { - php_mysqli_report_index("from previous query", mysql->mysql->server_status TSRMLS_CC); + php_mysqli_report_index("from previous query", mysqli_server_status(mysql->mysql) TSRMLS_CC); } mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = (void *)result; mysqli_resource->status = MYSQLI_STATUS_VALID; - MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); + MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); } /* }}} */ @@ -2125,8 +2340,8 @@ PHP_FUNCTION(mysqli_use_result) Return number of warnings from the last query for the given link */ PHP_FUNCTION(mysqli_warning_count) { - MY_MYSQL *mysql; - zval *mysql_link; + MY_MYSQL *mysql; + zval *mysql_link; if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; diff --git a/ext/mysqli/mysqli_driver.c b/ext/mysqli/mysqli_driver.c index 494c2a554b..e8a9f71806 100644 --- a/ext/mysqli/mysqli_driver.c +++ b/ext/mysqli/mysqli_driver.c @@ -25,7 +25,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" #include "zend_exceptions.h" @@ -110,7 +110,7 @@ static int driver_client_version_read(mysqli_object *obj, zval **retval TSRMLS_D static int driver_client_info_read(mysqli_object *obj, zval **retval TSRMLS_DC) { ALLOC_ZVAL(*retval); - ZVAL_STRING(*retval, MYSQL_SERVER_VERSION, 1); + ZVAL_STRING(*retval, (char *)mysql_get_client_info(), 1); return SUCCESS; } /* }}} */ @@ -130,9 +130,17 @@ MAP_PROPERTY_MYG_LONG_READ(driver_report_read, report_mode); ZEND_FUNCTION(mysqli_driver_construct) { +#if G0 + MYSQLI_RESOURCE *mysqli_resource; + + mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); + mysqli_resource->ptr = 1; + mysqli_resource->status = (ZEND_NUM_ARGS() == 1) ? MYSQLI_STATUS_INITIALIZED : MYSQLI_STATUS_VALID; + ((mysqli_object *) zend_object_store_get_object(getThis() TSRMLS_CC))->ptr = mysqli_resource; +#endif } -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}, @@ -145,8 +153,10 @@ mysqli_property_entry mysqli_driver_property_entries[] = { /* {{{ mysqli_driver_methods[] */ const zend_function_entry mysqli_driver_methods[] = { +#if defined(HAVE_EMBEDDED_MYSQLI) PHP_FALIAS(embedded_server_start, mysqli_embedded_server_start, NULL) PHP_FALIAS(embedded_server_end, mysqli_embedded_server_end, NULL) +#endif {NULL, NULL, NULL} }; /* }}} */ diff --git a/ext/mysqli/mysqli_embedded.c b/ext/mysqli/mysqli_embedded.c index 12affc87c2..328025af21 100644 --- a/ext/mysqli/mysqli_embedded.c +++ b/ext/mysqli/mysqli_embedded.c @@ -25,7 +25,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" /* {{{ proto bool mysqli_embedded_server_start(bool start, array arguments, array groups) initialize and start embedded server */ diff --git a/ext/mysqli/mysqli_exception.c b/ext/mysqli/mysqli_exception.c index b6b1d8903e..7b8a1d63e1 100644 --- a/ext/mysqli/mysqli_exception.c +++ b/ext/mysqli/mysqli_exception.c @@ -25,7 +25,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" #include "zend_exceptions.h" /* {{{ mysqli_exception_methods[] diff --git a/ext/mysqli/mysqli_fe.c b/ext/mysqli/mysqli_fe.c index f82d31c405..623042e576 100644 --- a/ext/mysqli/mysqli_fe.c +++ b/ext/mysqli/mysqli_fe.c @@ -27,7 +27,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" static @@ -61,14 +61,24 @@ const zend_function_entry mysqli_functions[] = { PHP_FE(mysqli_connect_errno, NULL) PHP_FE(mysqli_connect_error, NULL) PHP_FE(mysqli_data_seek, NULL) + PHP_FE(mysqli_dump_debug_info, NULL) PHP_FE(mysqli_debug, NULL) +#if !defined(HAVE_MYSQLND) PHP_FE(mysqli_disable_reads_from_master, NULL) PHP_FE(mysqli_disable_rpl_parse, NULL) - PHP_FE(mysqli_dump_debug_info, NULL) PHP_FE(mysqli_enable_reads_from_master, NULL) PHP_FE(mysqli_enable_rpl_parse, NULL) + PHP_FE(mysqli_send_query, NULL) + PHP_FE(mysqli_slave_query, NULL) + PHP_FE(mysqli_master_query, NULL) + PHP_FE(mysqli_rpl_parse_enabled, NULL) + PHP_FE(mysqli_rpl_probe, NULL) + PHP_FE(mysqli_rpl_query_type, NULL) +#endif +#if defined(HAVE_EMBEDDED_MYSQLI) PHP_FE(mysqli_embedded_server_end, NULL) PHP_FE(mysqli_embedded_server_start, NULL) +#endif PHP_FE(mysqli_errno, NULL) PHP_FE(mysqli_error, NULL) PHP_FE(mysqli_stmt_execute, NULL) @@ -77,14 +87,22 @@ const zend_function_entry mysqli_functions[] = { PHP_FE(mysqli_fetch_fields, NULL) PHP_FE(mysqli_fetch_field_direct, NULL) PHP_FE(mysqli_fetch_lengths, NULL) +#ifdef HAVE_MYSQLND + PHP_FE(mysqli_fetch_all, NULL) +#endif PHP_FE(mysqli_fetch_array, NULL) PHP_FE(mysqli_fetch_assoc, NULL) - PHP_FE(mysqli_fetch_object, NULL) + PHP_FE(mysqli_fetch_object, NULL) PHP_FE(mysqli_fetch_row, NULL) PHP_FE(mysqli_field_count, NULL) PHP_FE(mysqli_field_seek, NULL) PHP_FE(mysqli_field_tell, NULL) PHP_FE(mysqli_free_result, NULL) +#if defined(HAVE_MYSQLND) + PHP_FE(mysqli_get_cache_stats, NULL) + PHP_FE(mysqli_get_connection_stats, NULL) + PHP_FE(mysqli_get_client_stats, NULL) +#endif #ifdef HAVE_MYSQLI_GET_CHARSET PHP_FE(mysqli_get_charset, NULL) #endif @@ -99,9 +117,10 @@ const zend_function_entry mysqli_functions[] = { 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) - PHP_FE(mysqli_master_query, NULL) +#endif PHP_FE(mysqli_more_results, NULL) PHP_FE(mysqli_multi_query, NULL) PHP_FE(mysqli_next_result, NULL) @@ -116,9 +135,6 @@ const zend_function_entry mysqli_functions[] = { PHP_FE(mysqli_real_escape_string, NULL) PHP_FE(mysqli_real_query, NULL) PHP_FE(mysqli_rollback, NULL) - PHP_FE(mysqli_rpl_parse_enabled, NULL) - PHP_FE(mysqli_rpl_probe, NULL) - PHP_FE(mysqli_rpl_query_type, NULL) PHP_FE(mysqli_select_db, NULL) #ifdef HAVE_MYSQLI_SET_CHARSET PHP_FE(mysqli_set_charset, NULL) @@ -134,14 +150,17 @@ const zend_function_entry mysqli_functions[] = { PHP_FE(mysqli_stmt_bind_result, second_arg_force_by_ref_rest) PHP_FE(mysqli_stmt_fetch, NULL) PHP_FE(mysqli_stmt_free_result, NULL) +#if defined(HAVE_MYSQLND) + PHP_FE(mysqli_stmt_get_result, NULL) +#endif PHP_FE(mysqli_stmt_get_warnings, NULL) PHP_FE(mysqli_stmt_insert_id, NULL) PHP_FE(mysqli_stmt_reset, NULL) PHP_FE(mysqli_stmt_param_count, NULL) - PHP_FE(mysqli_send_query, NULL) - PHP_FE(mysqli_slave_query, NULL) PHP_FE(mysqli_sqlstate, NULL) +#if !defined(HAVE_MYSQLND) PHP_FE(mysqli_ssl_set, NULL) +#endif PHP_FE(mysqli_stat, NULL) PHP_FE(mysqli_stmt_affected_rows, NULL) PHP_FE(mysqli_stmt_close, NULL) @@ -150,8 +169,8 @@ const zend_function_entry mysqli_functions[] = { PHP_FE(mysqli_stmt_error, NULL) PHP_FE(mysqli_stmt_num_rows, NULL) PHP_FE(mysqli_stmt_sqlstate, NULL) - PHP_FE(mysqli_store_result, NULL) PHP_FE(mysqli_stmt_store_result, NULL) + PHP_FE(mysqli_store_result, NULL) PHP_FE(mysqli_thread_id, NULL) PHP_FE(mysqli_thread_safe, NULL) PHP_FE(mysqli_use_result, NULL) @@ -184,23 +203,34 @@ const zend_function_entry mysqli_link_methods[] = { PHP_FALIAS(close,mysqli_close,NULL) PHP_FALIAS(commit,mysqli_commit,NULL) PHP_FALIAS(connect,mysqli_connect,NULL) + PHP_FALIAS(dump_debug_info,mysqli_dump_debug_info,NULL) PHP_FALIAS(debug,mysqli_debug,NULL) +#if !defined(HAVE_MYSQLND) PHP_FALIAS(disable_reads_from_master,mysqli_disable_reads_from_master,NULL) PHP_FALIAS(disable_rpl_parse,mysqli_disable_rpl_parse,NULL) - PHP_FALIAS(dump_debug_info,mysqli_dump_debug_info,NULL) PHP_FALIAS(enable_reads_from_master,mysqli_enable_reads_from_master,NULL) PHP_FALIAS(enable_rpl_parse,mysqli_enable_rpl_parse,NULL) + PHP_FALIAS(rpl_parse_enabled,mysqli_rpl_parse_enabled,NULL) + PHP_FALIAS(rpl_probe,mysqli_rpl_probe,NULL) + PHP_FALIAS(rpl_query_type,mysqli_rpl_query_type,NULL) + PHP_FALIAS(master_query,mysqli_master_query,NULL) + PHP_FALIAS(slave_query,mysqli_slave_query,NULL) +#endif #ifdef HAVE_MYSQLI_GET_CHARSET PHP_FALIAS(get_charset,mysqli_get_charset,NULL) #endif PHP_FALIAS(get_client_info,mysqli_get_client_info,NULL) +#if defined(HAVE_MYSQLND) + PHP_FALIAS(get_connection_stats,mysqli_get_connection_stats,NULL) +#endif PHP_FALIAS(get_server_info,mysqli_get_server_info,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) - PHP_FALIAS(master_query,mysqli_master_query,NULL) +#endif PHP_FALIAS(multi_query,mysqli_multi_query,NULL) PHP_FALIAS(mysqli,mysqli_connect,NULL) PHP_FALIAS(more_results,mysqli_more_results, NULL) @@ -214,16 +244,14 @@ const zend_function_entry mysqli_link_methods[] = { PHP_FALIAS(escape_string, mysqli_real_escape_string,NULL) PHP_FALIAS(real_query,mysqli_real_query,NULL) PHP_FALIAS(rollback,mysqli_rollback,NULL) - PHP_FALIAS(rpl_parse_enabled,mysqli_rpl_parse_enabled,NULL) - PHP_FALIAS(rpl_probe,mysqli_rpl_probe,NULL) - PHP_FALIAS(rpl_query_type,mysqli_rpl_query_type,NULL) PHP_FALIAS(select_db,mysqli_select_db,NULL) #ifdef HAVE_MYSQLI_SET_CHARSET PHP_FALIAS(set_charset,mysqli_set_charset,NULL) #endif PHP_FALIAS(set_opt, mysqli_options,NULL) - PHP_FALIAS(slave_query,mysqli_slave_query,NULL) +#if !defined(HAVE_MYSQLND) PHP_FALIAS(ssl_set,mysqli_ssl_set,NULL) +#endif PHP_FALIAS(stat,mysqli_stat,NULL) PHP_FALIAS(stmt_init,mysqli_stmt_init, NULL) PHP_FALIAS(store_result,mysqli_store_result,NULL) @@ -238,18 +266,20 @@ const zend_function_entry mysqli_link_methods[] = { * Every user visible function must have an entry in mysqli_result_functions[]. */ const zend_function_entry mysqli_result_methods[] = { - PHP_FALIAS(mysqli_result, mysqli_result_construct, NULL) + PHP_FALIAS(__construct, mysqli_result_construct, NULL) PHP_FALIAS(close,mysqli_free_result,NULL) PHP_FALIAS(free,mysqli_free_result,NULL) PHP_FALIAS(data_seek,mysqli_data_seek,NULL) PHP_FALIAS(fetch_field,mysqli_fetch_field,NULL) PHP_FALIAS(fetch_fields,mysqli_fetch_fields,NULL) PHP_FALIAS(fetch_field_direct,mysqli_fetch_field_direct,NULL) +#if defined(HAVE_MYSQLND) + PHP_FALIAS(fetch_all,mysqli_fetch_all,NULL) +#endif PHP_FALIAS(fetch_array,mysqli_fetch_array,NULL) PHP_FALIAS(fetch_assoc,mysqli_fetch_assoc,NULL) PHP_FALIAS(fetch_object,mysqli_fetch_object,NULL) PHP_FALIAS(fetch_row,mysqli_fetch_row,NULL) - PHP_FALIAS(field_count,mysqli_field_count,NULL) PHP_FALIAS(field_seek,mysqli_field_seek,NULL) PHP_FALIAS(free_result,mysqli_free_result,NULL) {NULL, NULL, NULL} @@ -261,7 +291,7 @@ const zend_function_entry mysqli_result_methods[] = { * Every user visible function must have an entry in mysqli_stmt_functions[]. */ const zend_function_entry mysqli_stmt_methods[] = { - PHP_FALIAS(mysqli_stmt, mysqli_stmt_construct, NULL) + PHP_FALIAS(__construct, mysqli_stmt_construct, NULL) PHP_FALIAS(attr_get,mysqli_stmt_attr_get,NULL) PHP_FALIAS(attr_set,mysqli_stmt_attr_set,NULL) PHP_FALIAS(bind_param,mysqli_stmt_bind_param,second_arg_force_by_ref_rest) @@ -279,6 +309,9 @@ const zend_function_entry mysqli_stmt_methods[] = { PHP_FALIAS(reset,mysqli_stmt_reset,NULL) PHP_FALIAS(prepare,mysqli_stmt_prepare, NULL) PHP_FALIAS(store_result,mysqli_stmt_store_result,NULL) +#if defined(HAVE_MYSQLND) + PHP_FALIAS(get_result,mysqli_stmt_get_result,NULL) +#endif {NULL, NULL, NULL} }; /* }}} */ diff --git a/ext/mysqli/mysqli_libmysql.h b/ext/mysqli/mysqli_libmysql.h new file mode 100644 index 0000000000..1ea1fc3bf4 --- /dev/null +++ b/ext/mysqli/mysqli_libmysql.h @@ -0,0 +1,36 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 6 | + +----------------------------------------------------------------------+ + | Copyright (c) 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> | + +----------------------------------------------------------------------+ + +*/ + +/* These are unused */ +#define MYSQLI_CLOSE_EXPLICIT +#define MYSQLI_CLOSE_IMPLICIT +#define MYSQLI_CLOSE_DISCONNECTED +#define MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE 200 +#define MYSQLND_OPT_INT_AND_YEAR_AS_INT 201 + +#define mysqli_result_is_unbuffered(r) ((r)->handle && (r)->handle->status == MYSQL_STATUS_USE_RESULT) +#define mysqli_server_status(c) (c)->server_status +#define mysqli_stmt_warning_count(s) mysql_warning_count((s)->mysql) +#define mysqli_stmt_server_status(s) (s)->mysql->server_status +#define mysqli_stmt_get_connection(s) (s)->mysql +#define mysqli_close(c, is_forced) mysql_close((c)) +#define mysqli_stmt_close(c, implicit) mysql_stmt_close((c)) +#define mysqli_free_result(r, is_forced) mysql_free_result((r)) diff --git a/ext/mysqli/mysqli_mysqlnd.h b/ext/mysqli/mysqli_mysqlnd.h new file mode 100644 index 0000000000..27032f15c8 --- /dev/null +++ b/ext/mysqli/mysqli_mysqlnd.h @@ -0,0 +1,41 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | 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> | + +----------------------------------------------------------------------+ + +*/ + +#ifndef MYSQLI_MYSQLND_H +#define MYSQLI_MYSQLND_H + +#include "ext/mysqlnd/mysqlnd_libmysql_compat.h" + +/* Here comes non-libmysql API to have less ifdefs in mysqli*/ +#define MYSQLI_CLOSE_EXPLICIT MYSQLND_CLOSE_EXPLICIT +#define MYSQLI_CLOSE_IMPLICIT MYSQLND_CLOSE_IMPLICIT +#define MYSQLI_CLOSE_DISCONNECTED MYSQLND_CLOSE_DISCONNECTED + +#define mysqli_result_is_unbuffered(r) ((r)->unbuf) +#define mysqli_server_status(c) (c)->upsert_status.server_status +#define mysqli_stmt_warning_count(s) mysqlnd_stmt_warning_count((s)) +#define mysqli_stmt_server_status(s) (s)->upsert_status.server_status +#define mysqli_stmt_get_connection(s) (s)->conn +#define mysqli_close(c, how) mysqlnd_close((c), (how)) +#define mysqli_stmt_close(c, implicit) mysqlnd_stmt_close((c), (implicit)) +#define mysqli_free_result(r, implicit) mysqlnd_free_result((r), (implicit)) + +#endif diff --git a/ext/mysqli/mysqli_nonapi.c b/ext/mysqli/mysqli_nonapi.c index 2f9ba5325b..918594ad76 100644 --- a/ext/mysqli/mysqli_nonapi.c +++ b/ext/mysqli/mysqli_nonapi.c @@ -12,7 +12,9 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Georg Richter <georg@php.net> | + | Authors: Georg Richter <georg@php.net> | + | Andrey Hristov <andrey@php.net> | + | Ulf Wendel <uw@php.net> | +----------------------------------------------------------------------+ $Id$ @@ -27,46 +29,54 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" + +#define SAFE_STR(a) ((a)?a:"") + /* {{{ proto object mysqli_connect([string hostname [,string username [,string passwd [,string dbname [,int port [,string socket]]]]]]) Open a connection to a mysql server */ PHP_FUNCTION(mysqli_connect) { - 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; - long port=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; + 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 = username = dbname = passwd = socket = NULL; if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ssssls", &hostname, &hostname_len, &username, &username_len, &passwd, &passwd_len, &dbname, &dbname_len, &port, &socket, &socket_len) == FAILURE) { return; } - if (!socket_len) { - socket = NULL; + if (!socket_len || !socket) { + socket = MyG(default_socket); } - - /* TODO: safe mode handling */ - if (PG(sql_safe_mode)){ - } else { - if (!passwd) { - passwd = MyG(default_pw); - if (!username){ - username = MyG(default_user); - if (!hostname) { - hostname = MyG(default_host); - } - } - } + + if (!passwd) { + passwd = MyG(default_pw); + passwd_len = strlen(SAFE_STR(passwd)); + } + if (!username){ + username = MyG(default_user); + } + if (!hostname || !hostname_len) { + 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 && @@ -75,7 +85,7 @@ PHP_FUNCTION(mysqli_connect) mysql = (MY_MYSQL*)mysqli_resource->ptr; php_clear_mysql(mysql); if (mysql->mysql) { - mysql_close(mysql->mysql); + mysqli_close(mysql->mysql, MYSQLI_CLOSE_EXPLICIT); mysql->mysql = NULL; } } @@ -84,61 +94,194 @@ PHP_FUNCTION(mysqli_connect) mysql = (MY_MYSQL *) ecalloc(1, sizeof(MY_MYSQL)); } + 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; + } + 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->free_links.pDestructor = pDestructor; /* Restore the destructor */ + mysql->mysql = *free_mysql; + + 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)) { +#else + if (!mysql_ping(mysql->mysql)) { +#endif +#ifdef HAVE_MYSQLND + mysqlnd_restart_psession(mysql->mysql); +#endif + 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); + MyG(num_links)--; + break; + } + mysql->hash_index = idx; + mysql->hash_key = hash_key; + goto end; + } + } + } while (0); + } + } 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(2, MyG(max_persistent)), NULL, php_mysqli_dtor_p_elements, 1); + zend_hash_init(&plist->used_links, MAX(2, 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))) { - efree(mysql); - RETURN_FALSE; +#else + if (!(mysql->mysql = mysqlnd_init(persistent))) { +#endif + goto err; } + new_connection = TRUE; #ifdef HAVE_EMBEDDED_MYSQLI - if (strcmp(hostname, ":embedded")) { + if (hostname_len) { unsigned int external=1; mysql_options(mysql->mysql, MYSQL_OPT_USE_REMOTE_CONNECTION, (char *)&external); } else { - hostname[0] = '\0'; mysql_options(mysql->mysql, MYSQL_OPT_USE_EMBEDDED_CONNECTION, 0); } #endif - if (!socket) { - socket = MyG(default_socket); - } - - if (mysql_real_connect(mysql->mysql,hostname,username,passwd,dbname,port,socket,CLIENT_MULTI_RESULTS) == NULL) { +#if !defined(HAVE_MYSQLND) + if (mysql_real_connect(mysql->mysql, hostname, username, passwd, dbname, port, socket, CLIENT_MULTI_RESULTS) == NULL) +#else + if (mysqlnd_connect(mysql->mysql, hostname, username, passwd, passwd_len, dbname, dbname_len, + port, socket, CLIENT_MULTI_RESULTS, MyG(mysqlnd_thd_zval_cache) TSRMLS_CC) == NULL) +#endif + { /* Save error messages */ - - php_mysqli_throw_sql_exception( mysql->mysql->net.sqlstate, mysql->mysql->net.last_errno TSRMLS_CC, - "%s", mysql->mysql->net.last_error); - php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql) TSRMLS_CC); + php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC, + "%s", mysql_error(mysql->mysql)); /* free mysql structure */ - mysql_close(mysql->mysql); - efree(mysql); - RETURN_FALSE; + mysqli_close(mysql->mysql, MYSQLI_CLOSE_DISCONNECTED); + goto err; } /* clear error */ php_mysqli_set_error(mysql_errno(mysql->mysql), (char *) mysql_error(mysql->mysql) TSRMLS_CC); +#if !defined(HAVE_MYSQLND) mysql->mysql->reconnect = MyG(reconnect); /* set our own local_infile handler */ php_set_local_infile_handler_default(mysql); +#endif + + mysql_options(mysql->mysql, MYSQL_OPT_LOCAL_INFILE, (char *)&MyG(allow_local_infile)); +end: 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) { + /* save persistent connection */ + ulong hash_index = zend_hash_next_free_element(&plist->used_links); + 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"); + } 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; } /* }}} */ + /* {{{ proto int mysqli_connect_errno(void) Returns the numerical value of the error message from last connect command */ PHP_FUNCTION(mysqli_connect_errno) @@ -159,11 +302,30 @@ PHP_FUNCTION(mysqli_connect_error) } /* }}} */ + /* {{{ proto mixed mysqli_fetch_array (object result [,int resulttype]) Fetch a result row as an associative array, a numeric array, or both */ PHP_FUNCTION(mysqli_fetch_array) { +#if !defined(HAVE_MYSQLND) php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0); +#else + MYSQL_RES *result; + zval *mysql_result; + long mode = MYSQLND_FETCH_BOTH; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); + + if (mode < MYSQLI_ASSOC || mode > MYSQLI_BOTH) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "The result type should be either MYSQLI_NUM, MYSQLI_ASSOC or MYSQLI_BOTH"); + RETURN_FALSE; + } + + mysqlnd_fetch_into(result, mode, return_value, MYSQLND_MYSQLI); +#endif } /* }}} */ @@ -171,20 +333,102 @@ PHP_FUNCTION(mysqli_fetch_array) Fetch a result row as an associative array */ PHP_FUNCTION(mysqli_fetch_assoc) { +#if !defined(HAVE_MYSQLND) php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 0); +#else + MYSQL_RES *result; + zval *mysql_result; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_result, mysqli_result_class_entry) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); + mysqlnd_fetch_into(result, MYSQLND_FETCH_ASSOC, return_value, MYSQLND_MYSQLI); + +#endif } /* }}} */ + +/* {{{ proto mixed mysqli_fetch_all (object result [,int resulttype]) + Fetches all result rows as an associative array, a numeric array, or both */ +#if defined(HAVE_MYSQLND) +PHP_FUNCTION(mysqli_fetch_all) +{ + MYSQL_RES *result; + zval *mysql_result; + long mode = MYSQLND_FETCH_NUM; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O|l", &mysql_result, mysqli_result_class_entry, &mode) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(result, MYSQL_RES *, &mysql_result, "mysqli_result", MYSQLI_STATUS_VALID); + + if (!mode || (mode & ~MYSQLND_FETCH_BOTH)) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Mode can be only MYSQLI_FETCH_NUM, " + "MYSQLI_FETCH_ASSOC or MYSQLI_FETCH_BOTH"); + RETURN_FALSE; + } + + mysqlnd_fetch_all(result, mode, return_value); +} +/* }}} */ + + +/* {{{ proto array mysqli_cache_stats(void) U + Returns statistics about the zval cache */ +PHP_FUNCTION(mysqli_get_cache_stats) +{ + if (ZEND_NUM_ARGS()) { + WRONG_PARAM_COUNT; + } + mysqlnd_palloc_stats(mysqli_mysqlnd_zval_cache, return_value); +} +/* }}} */ + + +/* {{{ proto array mysqli_get_client_stats(void) + Returns statistics about the zval cache */ +PHP_FUNCTION(mysqli_get_client_stats) +{ + if (ZEND_NUM_ARGS()) { + WRONG_PARAM_COUNT; + } + mysqlnd_get_client_stats(return_value); +} +/* }}} */ + + +/* {{{ proto array mysqli_get_connection_stats(void) + Returns statistics about the zval cache */ +PHP_FUNCTION(mysqli_get_connection_stats) +{ + MY_MYSQL *mysql; + zval *mysql_link; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", + &mysql_link, mysqli_link_class_entry) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); + + mysqlnd_get_connection_stats(mysql->mysql, return_value); +} +#endif +/* }}} */ + + /* {{{ proto mixed mysqli_fetch_object (object result [, string class_name [, NULL|array ctor_params]]) Fetch a result row as an object */ PHP_FUNCTION(mysqli_fetch_object) { php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAM_PASSTHRU, MYSQLI_ASSOC, 1); +/* todo: mysqlnd support */ } /* }}} */ /* {{{ proto bool mysqli_multi_query(object link, string query) - Binary-safe version of mysql_query() */ + allows to execute multiple queries */ PHP_FUNCTION(mysqli_multi_query) { MY_MYSQL *mysql; @@ -199,25 +443,30 @@ PHP_FUNCTION(mysqli_multi_query) MYSQLI_ENABLE_MQ; if (mysql_real_query(mysql->mysql, query, query_len)) { +#ifndef HAVE_MYSQLND char s_error[MYSQL_ERRMSG_SIZE], s_sqlstate[SQLSTATE_LENGTH+1]; unsigned int s_errno; - MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); - /* we have to save error information, cause MYSQLI_DISABLE_MQ will reset error information */ strcpy(s_error, mysql_error(mysql->mysql)); strcpy(s_sqlstate, mysql_sqlstate(mysql->mysql)); s_errno = mysql_errno(mysql->mysql); - +#else + mysqlnd_error_info error_info = mysql->mysql->error_info; +#endif + MYSQLI_REPORT_MYSQL_ERROR(mysql->mysql); MYSQLI_DISABLE_MQ; +#ifndef HAVE_MYSQLND /* restore error information */ strcpy(mysql->mysql->net.last_error, s_error); strcpy(mysql->mysql->net.sqlstate, s_sqlstate); mysql->mysql->net.last_errno = s_errno; - +#else + mysql->mysql->error_info = error_info; +#endif RETURN_FALSE; - } + } RETURN_TRUE; } /* }}} */ @@ -258,7 +507,7 @@ PHP_FUNCTION(mysqli_query) if (!mysql_field_count(mysql->mysql)) { /* no result set - not a SELECT */ if (MyG(report_mode) & MYSQLI_REPORT_INDEX) { - php_mysqli_report_index(query, mysql->mysql->server_status TSRMLS_CC); + php_mysqli_report_index(query, mysqli_server_status(mysql->mysql) TSRMLS_CC); } RETURN_TRUE; } @@ -266,13 +515,13 @@ PHP_FUNCTION(mysqli_query) result = (resultmode == MYSQLI_USE_RESULT) ? mysql_use_result(mysql->mysql) : mysql_store_result(mysql->mysql); if (!result) { - php_mysqli_throw_sql_exception(mysql->mysql->net.sqlstate, mysql->mysql->net.last_errno TSRMLS_CC, - "%s", mysql->mysql->net.last_error); + php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC, + "%s", mysql_error(mysql->mysql)); RETURN_FALSE; } if (MyG(report_mode) & MYSQLI_REPORT_INDEX) { - php_mysqli_report_index(query, mysql->mysql->server_status TSRMLS_CC); + php_mysqli_report_index(query, mysqli_server_status(mysql->mysql) TSRMLS_CC); } mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); @@ -282,6 +531,36 @@ PHP_FUNCTION(mysqli_query) } /* }}} */ + +#if defined(HAVE_MYSQLND) +/* {{{ proto object mysqli_stmt_get_result(object link) U + Buffer result set on client */ +PHP_FUNCTION(mysqli_stmt_get_result) +{ + MYSQL_RES *result; + MYSQLI_RESOURCE *mysqli_resource; + MY_STMT *stmt; + zval *mysql_stmt; + + if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_stmt, mysqli_stmt_class_entry) == FAILURE) { + return; + } + MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt", MYSQLI_STATUS_VALID); + + if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) { + MYSQLI_REPORT_STMT_ERROR(stmt->stmt); + RETURN_FALSE; + } + + mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); + mysqli_resource->ptr = (void *)result; + mysqli_resource->status = MYSQLI_STATUS_VALID; + MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry); +} +/* }}} */ +#endif + + /* {{{ proto object mysqli_get_warnings(object link) */ PHP_FUNCTION(mysqli_get_warnings) { @@ -296,12 +575,13 @@ PHP_FUNCTION(mysqli_get_warnings) MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL*, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID); if (mysql_warning_count(mysql->mysql)) { - w = php_get_warnings(mysql->mysql); + w = php_get_warnings(mysql->mysql TSRMLS_CC); } else { RETURN_FALSE; } mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = mysqli_resource->info = (void *)w; + mysqli_resource->status = MYSQLI_STATUS_VALID; MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry); } /* }}} */ @@ -317,15 +597,16 @@ PHP_FUNCTION(mysqli_stmt_get_warnings) if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &stmt_link, mysqli_stmt_class_entry) == FAILURE) { return; } - MYSQLI_FETCH_RESOURCE(stmt, MY_STMT*, &stmt_link, "mysqli_stmt", 1); + MYSQLI_FETCH_RESOURCE(stmt, MY_STMT*, &stmt_link, "mysqli_stmt", MYSQLI_STATUS_VALID); - if (mysql_warning_count(stmt->stmt->mysql)) { - w = php_get_warnings(stmt->stmt->mysql); + if (mysqli_stmt_warning_count(stmt->stmt)) { + w = php_get_warnings(mysqli_stmt_get_connection(stmt->stmt) TSRMLS_CC); } else { RETURN_FALSE; } mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); mysqli_resource->ptr = mysqli_resource->info = (void *)w; + mysqli_resource->status = MYSQLI_STATUS_VALID; MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry); } /* }}} */ @@ -354,13 +635,19 @@ PHP_FUNCTION(mysqli_set_charset) #endif #ifdef HAVE_MYSQLI_GET_CHARSET -/* {{{ proto object mysqli_get_charset(object link) +/* {{{ proto object mysqli_get_charset(object link) U returns a character set object */ PHP_FUNCTION(mysqli_get_charset) { MY_MYSQL *mysql; zval *mysql_link; + char *name = NULL, *collation = NULL, *dir = NULL; + uint minlength, maxlength, number, state; +#if !defined(HAVE_MYSQLND) MY_CHARSET_INFO cs; +#else + const MYSQLND_CHARSET *cs; +#endif if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O", &mysql_link, mysqli_link_class_entry) == FAILURE) { return; @@ -369,16 +656,32 @@ PHP_FUNCTION(mysqli_get_charset) object_init(return_value); +#if !defined(HAVE_MYSQLND) mysql_get_character_set_info(mysql->mysql, &cs); + name = (char *)cs.csname; + collation = (char *)cs.name; + dir = (char *)cs.dir; + minlength = cs.mbminlen; + maxlength = cs.mbmaxlen; + number = cs.number; + state = cs.state; +#else + cs = mysql->mysql->charset; + name = cs->name; + collation = cs->collation; + minlength = cs->char_minlen; + maxlength = cs->char_maxlen; + number = cs->nr; + state = 1; /* all charsets are compiled in */ +#endif - add_property_string(return_value, "charset", (cs.name) ? (char *)cs.csname : "", 1); - add_property_string(return_value, "collation",(cs.name) ? (char *)cs.name : "", 1); - add_property_string(return_value, "comment", (cs.comment) ? (char *)cs.comment : "", 1); - add_property_string(return_value, "dir", (cs.dir) ? (char *)cs.dir : "", 1); - add_property_long(return_value, "min_length", cs.mbminlen); - add_property_long(return_value, "max_length", cs.mbmaxlen); - add_property_long(return_value, "number", cs.number); - add_property_long(return_value, "state", cs.state); + add_property_string(return_value, "charset", (name) ? (char *)name : "", 1); + add_property_string(return_value, "collation",(collation) ? (char *)collation : "", 1); + add_property_string(return_value, "dir", (dir) ? (char *)dir : "", 1); + add_property_long(return_value, "min_length", minlength); + add_property_long(return_value, "max_length", maxlength); + add_property_long(return_value, "number", number); + add_property_long(return_value, "state", state); } /* }}} */ #endif diff --git a/ext/mysqli/mysqli_prop.c b/ext/mysqli/mysqli_prop.c index fd0b8a21fa..fd8281b551 100644 --- a/ext/mysqli/mysqli_prop.c +++ b/ext/mysqli/mysqli_prop.c @@ -27,7 +27,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" #define CHECK_STATUS(value) \ if (((MYSQLI_RESOURCE *)obj->ptr)->status < value ) { \ @@ -221,24 +221,23 @@ static int result_type_read(mysqli_object *obj, zval **retval TSRMLS_DC) static int result_lengths_read(mysqli_object *obj, zval **retval TSRMLS_DC) { MYSQL_RES *p; + ulong *ret; ALLOC_ZVAL(*retval); CHECK_STATUS(MYSQLI_STATUS_VALID); p = (MYSQL_RES *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr; - if (!p || !p->field_count) { + if (!p || !p->field_count || !(ret = mysql_fetch_lengths(p))) + { ZVAL_NULL(*retval); } else { ulong i; - zval *l; array_init(*retval); for (i=0; i < p->field_count; i++) { - MAKE_STD_ZVAL(l); - ZVAL_LONG(l, p->lengths[i]); - add_index_zval(*retval, i, l); - } + add_index_long(*retval, i, ret[i]); + } } return SUCCESS; } @@ -312,7 +311,7 @@ MYSQLI_MAP_PROPERTY_FUNC_STRING(stmt_error_read, mysql_stmt_error, MYSQLI_GET_ST 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}, @@ -333,7 +332,7 @@ mysqli_property_entry mysqli_link_property_entries[] = { {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}, @@ -342,7 +341,7 @@ mysqli_property_entry mysqli_result_property_entries[] = { {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}, diff --git a/ext/mysqli/mysqli_repl.c b/ext/mysqli/mysqli_repl.c index b12706fa6b..8096c0239a 100644 --- a/ext/mysqli/mysqli_repl.c +++ b/ext/mysqli/mysqli_repl.c @@ -27,7 +27,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" /* {{{ proto void mysqli_disable_reads_from_master(object link) */ diff --git a/ext/mysqli/mysqli_report.c b/ext/mysqli/mysqli_report.c index be6e857226..dae2f9242d 100644 --- a/ext/mysqli/mysqli_report.c +++ b/ext/mysqli/mysqli_report.c @@ -25,7 +25,7 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" /* {{{ proto bool mysqli_report(int flags) sets report level */ @@ -45,13 +45,14 @@ PHP_FUNCTION(mysqli_report) /* }}} */ /* {{{ void php_mysqli_report_error(char *sqlstate, int errorno, char *error) */ -void php_mysqli_report_error(char *sqlstate, int errorno, char *error TSRMLS_DC) { - php_mysqli_throw_sql_exception(sqlstate, errorno TSRMLS_CC, "%s", error); +void php_mysqli_report_error(const char *sqlstate, int errorno, const char *error TSRMLS_DC) +{ + php_mysqli_throw_sql_exception((char *)sqlstate, errorno TSRMLS_CC, "%s", error); } /* }}} */ /* {{{ void php_mysqli_report_index() */ -void php_mysqli_report_index(char *query, unsigned int status TSRMLS_DC) { +void php_mysqli_report_index(const char *query, unsigned int status TSRMLS_DC) { char index[15]; if (status & SERVER_QUERY_NO_GOOD_INDEX_USED) { diff --git a/ext/mysqli/mysqli_warning.c b/ext/mysqli/mysqli_warning.c index 92dc8ce327..7b02d9117a 100644 --- a/ext/mysqli/mysqli_warning.c +++ b/ext/mysqli/mysqli_warning.c @@ -25,55 +25,144 @@ #include "php.h" #include "php_ini.h" #include "ext/standard/info.h" -#include "php_mysqli.h" +#include "php_mysqli_structs.h" + +/* Define these in the PHP5 tree to make merging easy process */ +#define ZSTR_DUPLICATE (1<<0) +#define ZSTR_AUTOFREE (1<<1) + +#define ZVAL_UTF8_STRING(z, s, flags) ZVAL_STRING((z), (char*)(s), ((flags) & ZSTR_DUPLICATE)) +#define ZVAL_UTF8_STRINGL(z, s, l, flags) ZVAL_STRINGL((z), (char*)(s), (l), ((flags) & ZSTR_DUPLICATE)) + /* {{{ void php_clear_warnings() */ void php_clear_warnings(MYSQLI_WARNING *w) { - MYSQLI_WARNING *n; + MYSQLI_WARNING *n; while (w) { n = w; - efree(w->reason); + zval_dtor(&(w->reason)); + zval_dtor(&(w->sqlstate)); w = w->next; efree(n); } } /* }}} */ + +#ifndef HAVE_MYSQLND /* {{{ MYSQLI_WARNING *php_new_warning */ -MYSQLI_WARNING *php_new_warning(char *reason, char *sqlstate, int errorno) +static +MYSQLI_WARNING *php_new_warning(const char *reason, int errorno TSRMLS_DC) { - MYSQLI_WARNING *w; + MYSQLI_WARNING *w; w = (MYSQLI_WARNING *)ecalloc(1, sizeof(MYSQLI_WARNING)); - w->reason = safe_estrdup(reason); - if (sqlstate) { - strcpy(w->sqlstate, sqlstate); - } else { - strcpy(w->sqlstate, "00000"); - } + ZVAL_UTF8_STRING(&(w->reason), reason, ZSTR_DUPLICATE); + + ZVAL_UTF8_STRINGL(&(w->sqlstate), "HY000", sizeof("HY000") - 1, ZSTR_DUPLICATE); + w->errorno = errorno; return w; } /* }}} */ -/* {{{ MYSQLI_WARNING *php_get_warnings(MYSQL *mysql) */ -MYSQLI_WARNING *php_get_warnings(MYSQL *mysql) + +/* {{{ MYSQLI_WARNING *php_get_warnings(MYSQL *mysql TSRMLS_DC) */ +MYSQLI_WARNING *php_get_warnings(MYSQL *mysql TSRMLS_DC) { - MYSQLI_WARNING *w, *first = NULL, *prev = NULL; + MYSQLI_WARNING *w, *first = NULL, *prev = NULL; MYSQL_RES *result; MYSQL_ROW row; - if (mysql_query(mysql, "SHOW WARNINGS")) { + if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) { return NULL; } result = mysql_store_result(mysql); + while ((row = mysql_fetch_row(result))) { - w = php_new_warning(row[2], "HY000", atoi(row[1])); + w = php_new_warning(row[2], atoi(row[1]) TSRMLS_CC); + if (!first) { + first = w; + } + if (prev) { + prev->next = w; + } + prev = w; + } + mysql_free_result(result); + return first; +} +/* }}} */ +#else +/* {{{ MYSQLI_WARNING *php_new_warning */ +static +MYSQLI_WARNING *php_new_warning(const zval *reason, int errorno TSRMLS_DC) +{ + MYSQLI_WARNING *w; + + w = (MYSQLI_WARNING *)ecalloc(1, sizeof(MYSQLI_WARNING)); + + w->reason = *reason; + zval_copy_ctor(&(w->reason)); + + ZVAL_UTF8_STRINGL(&(w->reason), Z_STRVAL(w->reason), Z_STRLEN(w->reason), ZSTR_AUTOFREE); + + ZVAL_UTF8_STRINGL(&(w->sqlstate), "HY000", sizeof("HY000") - 1, ZSTR_DUPLICATE); + + w->errorno = errorno; + + return w; +} +/* }}} */ + + +/* {{{ MYSQLI_WARNING *php_get_warnings(MYSQL *mysql TSRMLS_DC) */ +MYSQLI_WARNING *php_get_warnings(MYSQL *mysql TSRMLS_DC) +{ + MYSQLI_WARNING *w, *first = NULL, *prev = NULL; + MYSQL_RES *result; + zval *row; + + if (mysql_real_query(mysql, "SHOW WARNINGS", 13)) { + return NULL; + } + + result = mysql_use_result(mysql); + + for (;;) { + zval **entry; + int errno; + + MAKE_STD_ZVAL(row); + mysqlnd_fetch_into(result, MYSQLND_FETCH_NUM, row, MYSQLND_MYSQLI); + if (Z_TYPE_P(row) != IS_ARRAY) { + zval_ptr_dtor(&row); + break; + } + zend_hash_internal_pointer_reset(Z_ARRVAL_P(row)); + /* 0. we don't care about the first */ + zend_hash_move_forward(Z_ARRVAL_P(row)); + + /* 1. Here comes the error no */ + zend_hash_get_current_data(Z_ARRVAL_P(row), (void **)&entry); + convert_to_long_ex(entry); + errno = Z_LVAL_PP(entry); + zend_hash_move_forward(Z_ARRVAL_P(row)); + + /* 2. Here comes the reason */ + zend_hash_get_current_data(Z_ARRVAL_P(row), (void **)&entry); + + w = php_new_warning(*entry, errno TSRMLS_CC); + /* + Don't destroy entry, because the row destroy will decrease + the refcounter. Decreased twice then mysqlnd_free_result() + will crash, because it will try to access already freed memory. + */ if (!first) { first = w; } @@ -81,11 +170,16 @@ MYSQLI_WARNING *php_get_warnings(MYSQL *mysql) prev->next = (void *)w; } prev = w; + + zval_ptr_dtor(&row); } + mysql_free_result(result); return first; } /* }}} */ +#endif + /* {{{ bool mysqli_warning::next() */ PHP_METHOD(mysqli_warning, next) @@ -112,7 +206,9 @@ PHP_METHOD(mysqli_warning, next) } /* }}} */ + /* {{{ property mysqli_warning_message */ +static int mysqli_warning_message(mysqli_object *obj, zval **retval TSRMLS_DC) { MYSQLI_WARNING *w; @@ -122,17 +218,16 @@ int mysqli_warning_message(mysqli_object *obj, zval **retval TSRMLS_DC) } w = (MYSQLI_WARNING *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr; - ALLOC_ZVAL(*retval); - if (w->reason) { - ZVAL_STRING(*retval, w->reason, 1); - } else { - ZVAL_NULL(*retval); - } + MAKE_STD_ZVAL(*retval); + **retval = w->reason; + zval_copy_ctor(*retval); return SUCCESS; } /* }}} */ + /* {{{ property mysqli_warning_sqlstate */ +static int mysqli_warning_sqlstate(mysqli_object *obj, zval **retval TSRMLS_DC) { MYSQLI_WARNING *w; @@ -142,13 +237,16 @@ int mysqli_warning_sqlstate(mysqli_object *obj, zval **retval TSRMLS_DC) } w = (MYSQLI_WARNING *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr; - ALLOC_ZVAL(*retval); - ZVAL_STRING(*retval, w->sqlstate, 1); + MAKE_STD_ZVAL(*retval); + **retval = w->sqlstate; + zval_copy_ctor(*retval); return SUCCESS; } /* }}} */ + /* {{{ property mysqli_warning_error */ +static int mysqli_warning_errno(mysqli_object *obj, zval **retval TSRMLS_DC) { MYSQLI_WARNING *w; @@ -157,7 +255,7 @@ int mysqli_warning_errno(mysqli_object *obj, zval **retval TSRMLS_DC) return FAILURE; } w = (MYSQLI_WARNING *)((MYSQLI_RESOURCE *)(obj->ptr))->ptr; - ALLOC_ZVAL(*retval); + MAKE_STD_ZVAL(*retval); ZVAL_LONG(*retval, w->errorno); return SUCCESS; } @@ -187,20 +285,22 @@ PHP_METHOD(mysqli_warning, __construct) } else if (obj->zo.ce == mysqli_stmt_class_entry) { MY_STMT *stmt; MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &z, "mysqli_stmt", MYSQLI_STATUS_VALID); - hdl = stmt->stmt->mysql; + hdl = mysqli_stmt_get_connection(stmt->stmt); } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid class argument"); RETURN_FALSE; } if (mysql_warning_count(hdl)) { - w = php_get_warnings(hdl); + w = php_get_warnings(hdl TSRMLS_CC); } else { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "No warnings found"); RETURN_FALSE; } mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE)); - mysqli_resource->status = MYSQLI_STATUS_VALID; mysqli_resource->ptr = mysqli_resource->info = (void *)w; + mysqli_resource->status = MYSQLI_STATUS_VALID; if (!getThis() || !instanceof_function(Z_OBJCE_P(getThis()), mysqli_warning_class_entry TSRMLS_CC)) { MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_warning_class_entry); @@ -211,18 +311,22 @@ PHP_METHOD(mysqli_warning, __construct) } /* }}} */ +/* {{{ mysqli_warning_methods */ const zend_function_entry mysqli_warning_methods[] = { PHP_ME(mysqli_warning, __construct, NULL, ZEND_ACC_PROTECTED) PHP_ME(mysqli_warning, next, NULL, ZEND_ACC_PUBLIC) {NULL, NULL, NULL} }; +/* }}} */ -mysqli_property_entry mysqli_warning_property_entries[] = { +/* {{{ 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}, {NULL, NULL, NULL} }; +/* }}} */ /* * Local variables: diff --git a/ext/mysqli/php_mysqli.h b/ext/mysqli/php_mysqli.h index 965bec7082..d166d00f52 100644 --- a/ext/mysqli/php_mysqli.h +++ b/ext/mysqli/php_mysqli.h @@ -12,299 +12,17 @@ | obtain it through the world-wide-web, please send a note to | | license@php.net so we can mail you a copy immediately. | +----------------------------------------------------------------------+ - | Author: Georg Richter <georg@php.net> | + | Authors: Georg Richter <georg@php.net> | + | Andrey Hristov <andrey@php.net> | + | Ulf Wendel <uw@php.net> | +----------------------------------------------------------------------+ $Id$ */ -/* A little hack to prevent build break, when mysql is used together with - * c-client, which also defines LIST. - */ -#ifdef LIST -#undef LIST -#endif - -#include <mysql.h> - -/* character set support */ -#if MYSQL_VERSION_ID > 50009 -#define HAVE_MYSQLI_GET_CHARSET -#endif - -#if (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 -#define HAVE_MYSQLI_SET_CHARSET -#endif - - -#include <errmsg.h> - #ifndef PHP_MYSQLI_H #define PHP_MYSQLI_H -#define MYSQLI_VERSION_ID 101009 - -enum mysqli_status { - MYSQLI_STATUS_UNKNOWN=0, - MYSQLI_STATUS_CLEARED, - MYSQLI_STATUS_INITIALIZED, - MYSQLI_STATUS_VALID -}; - -typedef struct { - ulong buflen; - char *val; - ulong type; -} VAR_BUFFER; - -typedef struct { - unsigned int var_cnt; - VAR_BUFFER *buf; - zval **vars; - char *is_null; -} BIND_BUFFER; - -typedef struct { - MYSQL_STMT *stmt; - BIND_BUFFER param; - BIND_BUFFER result; - char *query; -} MY_STMT; - -typedef struct { - MYSQL *mysql; - zval *li_read; - php_stream *li_stream; - unsigned int multi_query; -} MY_MYSQL; - -typedef struct { - int mode; - int socket; - FILE *fp; -} PROFILER; - -typedef struct { - void *ptr; /* resource: (mysql, result, stmt) */ - void *info; /* additional buffer */ - enum mysqli_status status; -} MYSQLI_RESOURCE; - -typedef struct _mysqli_object { - zend_object zo; - void *ptr; - HashTable *prop_handler; -} mysqli_object; /* extends zend_object */ - -typedef struct { - char *reason; - char sqlstate[6]; - int errorno; - void *next; -} MYSQLI_WARNING; - -typedef struct _mysqli_property_entry { - char *pname; - int (*r_func)(mysqli_object *obj, zval **retval TSRMLS_DC); - int (*w_func)(mysqli_object *obj, zval *value TSRMLS_DC); -} mysqli_property_entry; - -typedef struct { - char error_msg[LOCAL_INFILE_ERROR_LEN]; - void *userdata; -} mysqli_local_infile; - -#define phpext_mysqli_ptr &mysqli_module_entry - -#ifdef PHP_WIN32 -#define PHP_MYSQLI_API __declspec(dllexport) -#define MYSQLI_LLU_SPEC "%I64u" -#define MYSQLI_LL_SPEC "%I64d" -#else -#define PHP_MYSQLI_API -#define MYSQLI_LLU_SPEC "%llu" -#define MYSQLI_LL_SPEC "%lld" -#endif - -#ifdef ZTS -#include "TSRM.h" -#endif - -#define PHP_MYSQLI_EXPORT(__type) PHP_MYSQLI_API __type - -extern zend_module_entry mysqli_module_entry; -extern const zend_function_entry mysqli_functions[]; -extern const zend_function_entry mysqli_link_methods[]; -extern const zend_function_entry mysqli_stmt_methods[]; -extern const zend_function_entry mysqli_result_methods[]; -extern const zend_function_entry mysqli_driver_methods[]; -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 void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flag, int into_object); -extern void php_clear_stmt_bind(MY_STMT *stmt); -extern void php_clear_mysql(MY_MYSQL *); -extern MYSQLI_WARNING *php_get_warnings(MYSQL *mysql); -extern void php_clear_warnings(MYSQLI_WARNING *w); -extern void php_free_stmt_bind_buffer(BIND_BUFFER bbuf, int type); -extern void php_mysqli_report_error(char *sqlstate, int errorno, char *error TSRMLS_DC); -extern void php_mysqli_report_index(char *query, unsigned int status TSRMLS_DC); -extern int php_local_infile_init(void **, const char *, void *); -extern int php_local_infile_read(void *, char *, uint); -extern void php_local_infile_end(void *); -extern int php_local_infile_error(void *, char *, uint); -extern void php_set_local_infile_handler_default(MY_MYSQL *); -extern void php_mysqli_throw_sql_exception(char *sqlstate, int errorno TSRMLS_DC, char *format, ...); -extern zend_class_entry *mysqli_link_class_entry; -extern zend_class_entry *mysqli_stmt_class_entry; -extern zend_class_entry *mysqli_result_class_entry; -extern zend_class_entry *mysqli_driver_class_entry; -extern zend_class_entry *mysqli_warning_class_entry; -extern zend_class_entry *mysqli_exception_class_entry; - -#ifdef HAVE_SPL -extern PHPAPI zend_class_entry *spl_ce_RuntimeException; -#endif - -PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry * TSRMLS_DC); - -#define MYSQLI_DISABLE_MQ if (mysql->multi_query) { \ - mysql_set_server_option(mysql->mysql, MYSQL_OPTION_MULTI_STATEMENTS_OFF); \ - mysql->multi_query = 0; \ -} - -#define MYSQLI_ENABLE_MQ if (!mysql->multi_query) { \ - mysql_set_server_option(mysql->mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON); \ - mysql->multi_query = 1; \ -} - -#define REGISTER_MYSQLI_CLASS_ENTRY(name, mysqli_entry, class_functions) { \ - zend_class_entry ce; \ - INIT_CLASS_ENTRY(ce, name,class_functions); \ - ce.create_object = mysqli_objects_new; \ - mysqli_entry = zend_register_internal_class(&ce TSRMLS_CC); \ -} \ - -#define MYSQLI_REGISTER_RESOURCE_EX(__ptr, __zval) \ - ((mysqli_object *) zend_object_store_get_object(__zval TSRMLS_CC))->ptr = __ptr; \ - -#define MYSQLI_RETURN_RESOURCE(__ptr, __ce) \ - Z_TYPE_P(return_value) = IS_OBJECT; \ - (return_value)->value.obj = mysqli_objects_new(__ce TSRMLS_CC); \ - MYSQLI_REGISTER_RESOURCE_EX(__ptr, return_value) - -#define MYSQLI_REGISTER_RESOURCE(__ptr, __ce) \ -{\ - zval *object = getThis();\ - if (!object || !instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) {\ - object = return_value;\ - Z_TYPE_P(object) = IS_OBJECT;\ - (object)->value.obj = mysqli_objects_new(__ce TSRMLS_CC);\ - }\ - MYSQLI_REGISTER_RESOURCE_EX(__ptr, object)\ -} - -#define MYSQLI_FETCH_RESOURCE(__ptr, __type, __id, __name, __check) \ -{ \ - MYSQLI_RESOURCE *my_res; \ - mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*(__id) TSRMLS_CC);\ - if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {\ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't fetch %s", intern->zo.ce->name);\ - RETURN_NULL();\ - }\ - __ptr = (__type)my_res->ptr; \ - if (__check && my_res->status < __check) { \ - php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid object or resource %s\n", intern->zo.ce->name); \ - RETURN_NULL();\ - }\ -} - -#define MYSQLI_SET_STATUS(__id, __value) \ -{ \ - mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*(__id) TSRMLS_CC);\ - ((MYSQLI_RESOURCE *)intern->ptr)->status = __value; \ -} \ - -#define MYSQLI_CLEAR_RESOURCE(__id) \ -{ \ - mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*(__id) TSRMLS_CC);\ - efree(intern->ptr); \ - intern->ptr = NULL; \ -} - -#define MYSQLI_RETURN_LONG_LONG(__val) \ -{ \ - if ((__val) < LONG_MAX) { \ - 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); \ - } \ -} - -#define MYSQLI_ADD_PROPERTIES(a,b) \ -{ \ - int i = 0; \ - while (b[i].pname != NULL) { \ - mysqli_add_property(a, b[i].pname, (mysqli_read_t)b[i].r_func, (mysqli_write_t)b[i].w_func TSRMLS_CC); \ - i++; \ - }\ -} - -#if WIN32|WINNT -#define SCLOSE(a) closesocket(a) -#else -#define SCLOSE(a) close(a) -#endif - -#define MYSQLI_STORE_RESULT 0 -#define MYSQLI_USE_RESULT 1 - -/* for mysqli_fetch_assoc */ -#define MYSQLI_ASSOC 1 -#define MYSQLI_NUM 2 -#define MYSQLI_BOTH 3 - -/* for mysqli_bind_param */ -#define MYSQLI_BIND_INT 1 -#define MYSQLI_BIND_DOUBLE 2 -#define MYSQLI_BIND_STRING 3 -#define MYSQLI_BIND_SEND_DATA 4 - -/* fetch types */ -#define FETCH_SIMPLE 1 -#define FETCH_RESULT 2 - -/*** REPORT MODES ***/ -#define MYSQLI_REPORT_OFF 0 -#define MYSQLI_REPORT_ERROR 1 -#define MYSQLI_REPORT_STRICT 2 -#define MYSQLI_REPORT_INDEX 4 -#define MYSQLI_REPORT_CLOSE 8 -#define MYSQLI_REPORT_ALL 255 - -#define MYSQLI_REPORT_MYSQL_ERROR(mysql) \ -if ((MyG(report_mode) & MYSQLI_REPORT_ERROR) && mysql->net.last_errno) { \ - php_mysqli_report_error(mysql->net.sqlstate, mysql->net.last_errno, mysql->net.last_error TSRMLS_CC); \ -} - -#define MYSQLI_REPORT_STMT_ERROR(stmt) \ -if ((MyG(report_mode) & MYSQLI_REPORT_ERROR) && stmt->last_errno) { \ - php_mysqli_report_error(stmt->sqlstate, stmt->last_errno, stmt->last_error TSRMLS_CC); \ -} - -PHP_MYSQLI_API void mysqli_register_link(zval *return_value, void *link TSRMLS_DC); -PHP_MYSQLI_API void mysqli_register_stmt(zval *return_value, void *stmt TSRMLS_DC); -PHP_MYSQLI_API void mysqli_register_result(zval *return_value, void *result TSRMLS_DC); -PHP_MYSQLI_API void php_mysqli_set_error(long mysql_errno, char *mysql_err TSRMLS_DC); PHP_MINIT_FUNCTION(mysqli); PHP_MSHUTDOWN_FUNCTION(mysqli); @@ -317,9 +35,7 @@ PHP_FUNCTION(mysqli_affected_rows); PHP_FUNCTION(mysqli_autocommit); PHP_FUNCTION(mysqli_change_user); PHP_FUNCTION(mysqli_character_set_name); -#ifdef HAVE_MYSQLI_SET_CHARSET PHP_FUNCTION(mysqli_set_charset); -#endif PHP_FUNCTION(mysqli_close); PHP_FUNCTION(mysqli_commit); PHP_FUNCTION(mysqli_connect); @@ -334,6 +50,7 @@ PHP_FUNCTION(mysqli_enable_reads_from_master); PHP_FUNCTION(mysqli_enable_rpl_parse); PHP_FUNCTION(mysqli_errno); PHP_FUNCTION(mysqli_error); +PHP_FUNCTION(mysqli_fetch_all); PHP_FUNCTION(mysqli_fetch_array); PHP_FUNCTION(mysqli_fetch_assoc); PHP_FUNCTION(mysqli_fetch_object); @@ -346,9 +63,10 @@ PHP_FUNCTION(mysqli_field_count); PHP_FUNCTION(mysqli_field_seek); PHP_FUNCTION(mysqli_field_tell); PHP_FUNCTION(mysqli_free_result); -#ifdef HAVE_MYSQLI_GET_CHARSET +PHP_FUNCTION(mysqli_get_cache_stats); +PHP_FUNCTION(mysqli_get_client_stats); +PHP_FUNCTION(mysqli_get_connection_stats); PHP_FUNCTION(mysqli_get_charset); -#endif PHP_FUNCTION(mysqli_get_client_info); PHP_FUNCTION(mysqli_get_client_version); PHP_FUNCTION(mysqli_get_host_info); @@ -408,6 +126,7 @@ PHP_FUNCTION(mysqli_stmt_data_seek); PHP_FUNCTION(mysqli_stmt_errno); PHP_FUNCTION(mysqli_stmt_error); PHP_FUNCTION(mysqli_stmt_free_result); +PHP_FUNCTION(mysqli_stmt_get_result); PHP_FUNCTION(mysqli_stmt_get_warnings); PHP_FUNCTION(mysqli_stmt_reset); PHP_FUNCTION(mysqli_stmt_insert_id); @@ -425,53 +144,11 @@ ZEND_FUNCTION(mysqli_result_construct); ZEND_FUNCTION(mysqli_driver_construct); ZEND_METHOD(mysqli_warning,__construct); -ZEND_BEGIN_MODULE_GLOBALS(mysqli) - long default_link; - long num_links; - long max_links; - unsigned int default_port; - char *default_host; - char *default_user; - char *default_socket; - char *default_pw; - int reconnect; - int strict; - long error_no; - char *error_msg; - int report_mode; - HashTable *report_ht; - unsigned int multi_query; - unsigned int embedded; -ZEND_END_MODULE_GLOBALS(mysqli) - - -#define MYSQLI_PROPERTY(a) extern int a(mysqli_object *obj, zval **retval TSRMLS_DC) - -MYSQLI_PROPERTY(my_prop_link_host); - -#ifdef ZTS -#define MyG(v) TSRMG(mysqli_globals_id, zend_mysqli_globals *, v) -#else -#define MyG(v) (mysqli_globals.v) -#endif - -#define my_estrdup(x) (x) ? estrdup(x) : NULL -#define my_efree(x) if (x) efree(x) - -#ifdef PHP_WIN32 -#define L64(x) x##i64 -typedef __int64 my_longlong; -#else -#define L64(x) x##LL -typedef long long my_longlong; -#endif - - -ZEND_EXTERN_MODULE_GLOBALS(mysqli) +#define phpext_mysqli_ptr &mysqli_module_entry +extern zend_module_entry mysqli_module_entry; #endif /* PHP_MYSQLI.H */ - /* * Local variables: * tab-width: 4 diff --git a/ext/mysqli/php_mysqli_structs.h b/ext/mysqli/php_mysqli_structs.h new file mode 100644 index 0000000000..5c6e23f4f3 --- /dev/null +++ b/ext/mysqli/php_mysqli_structs.h @@ -0,0 +1,396 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-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. | + +----------------------------------------------------------------------+ + | Author: Georg Richter <georg@php.net> | + +----------------------------------------------------------------------+ + + $Id$ +*/ + +#ifndef PHP_MYSQLI_STRUCTS_H +#define PHP_MYSQLI_STRUCTS_H + +/* A little hack to prevent build break, when mysql is used together with + * c-client, which also defines LIST. + */ +#ifdef LIST +#undef LIST +#endif + +#ifndef TRUE +#define TRUE 1 +#endif + +#ifndef FALSE +#define FALSE 0 +#endif + +#ifdef HAVE_MYSQLND +#include "ext/mysqlnd/mysqlnd.h" +#include "ext/mysqli/mysqli_mysqlnd.h" +#else +#include <mysql.h> +#include <errmsg.h> +#include "ext/mysqli/mysqli_libmysql.h" +#endif + +#include "php_mysqli.h" + +/* character set support */ +#if defined(MYSQLND_VERSION_ID) || MYSQL_VERSION_ID > 50009 +#define HAVE_MYSQLI_GET_CHARSET +#endif + +#if defined(MYSQLND_VERSION_ID) || (MYSQL_VERSION_ID > 40112 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID > 50005 +#define HAVE_MYSQLI_SET_CHARSET +#endif + +#define MYSQLI_VERSION_ID 101009 + +enum mysqli_status { + MYSQLI_STATUS_UNKNOWN=0, + MYSQLI_STATUS_CLEARED, + MYSQLI_STATUS_INITIALIZED, + MYSQLI_STATUS_VALID +}; + +typedef struct { + ulong buflen; + char *val; + ulong type; +} VAR_BUFFER; + +typedef struct { + unsigned int var_cnt; + VAR_BUFFER *buf; + zval **vars; + char *is_null; +} BIND_BUFFER; + +typedef struct { + MYSQL_STMT *stmt; + BIND_BUFFER param; + BIND_BUFFER result; + char *query; +} MY_STMT; + +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; +} MY_MYSQL; + +typedef struct { + int mode; + int socket; + FILE *fp; +} PROFILER; + +typedef struct { + void *ptr; /* resource: (mysql, result, stmt) */ + void *info; /* additional buffer */ + enum mysqli_status status; /* object status */ +} MYSQLI_RESOURCE; + +typedef struct _mysqli_object { + zend_object zo; + void *ptr; + HashTable *prop_handler; +} mysqli_object; /* extends zend_object */ + +typedef struct st_mysqli_warning MYSQLI_WARNING; + +struct st_mysqli_warning { + zval reason; + zval sqlstate; + int errorno; + MYSQLI_WARNING *next; +}; + +typedef struct _mysqli_property_entry { + char *pname; + int (*r_func)(mysqli_object *obj, zval **retval TSRMLS_DC); + int (*w_func)(mysqli_object *obj, zval *value TSRMLS_DC); +} mysqli_property_entry; + +#if !defined(HAVE_MYSQLND) +typedef struct { + char error_msg[LOCAL_INFILE_ERROR_LEN]; + void *userdata; +} 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" +#define MYSQLI_LL_SPEC "%I64d" +#define L64(x) x##i64 +typedef __int64 my_longlong; +#else +#define PHP_MYSQLI_API +#define MYSQLI_LLU_SPEC "%llu" +#define MYSQLI_LL_SPEC "%lld" +#define L64(x) x##LL +typedef long long my_longlong; +#endif + +#ifdef ZTS +#include "TSRM.h" +#endif + +#define PHP_MYSQLI_EXPORT(__type) PHP_MYSQLI_API __type + +extern const zend_function_entry mysqli_functions[]; +extern const zend_function_entry mysqli_link_methods[]; +extern const zend_function_entry mysqli_stmt_methods[]; +extern const zend_function_entry mysqli_result_methods[]; +extern const zend_function_entry mysqli_driver_methods[]; +extern const zend_function_entry mysqli_warning_methods[]; +extern const zend_function_entry mysqli_exception_methods[]; + +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 MYSQLND_QCACHE *mysqli_mysqlnd_qcache; +#endif + +extern void php_mysqli_fetch_into_hash(INTERNAL_FUNCTION_PARAMETERS, int override_flag, int into_object); +extern void php_clear_stmt_bind(MY_STMT *stmt TSRMLS_DC); +extern void php_clear_mysql(MY_MYSQL *); +extern MYSQLI_WARNING *php_get_warnings(MYSQL *mysql TSRMLS_DC); +extern void php_clear_warnings(MYSQLI_WARNING *w); +extern void php_free_stmt_bind_buffer(BIND_BUFFER bbuf, int type); +extern void php_mysqli_report_error(const char *sqlstate, int errorno, const char *error TSRMLS_DC); +extern void php_mysqli_report_index(const char *query, unsigned int status TSRMLS_DC); +extern int php_local_infile_init(void **, const char *, void *); +extern int php_local_infile_read(void *, char *, uint); +extern void php_local_infile_end(void *); +extern int php_local_infile_error(void *, char *, uint); +extern void php_set_local_infile_handler_default(MY_MYSQL *); +extern void php_mysqli_throw_sql_exception(char *sqlstate, int errorno TSRMLS_DC, char *format, ...); +extern zend_class_entry *mysqli_link_class_entry; +extern zend_class_entry *mysqli_stmt_class_entry; +extern zend_class_entry *mysqli_result_class_entry; +extern zend_class_entry *mysqli_driver_class_entry; +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; +#endif + +PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry * TSRMLS_DC); + +#define MYSQLI_DISABLE_MQ if (mysql->multi_query) { \ + mysql_set_server_option(mysql->mysql, MYSQL_OPTION_MULTI_STATEMENTS_OFF); \ + mysql->multi_query = 0; \ +} + +#define MYSQLI_ENABLE_MQ if (!mysql->multi_query) { \ + mysql_set_server_option(mysql->mysql, MYSQL_OPTION_MULTI_STATEMENTS_ON); \ + mysql->multi_query = 1; \ +} + +#define REGISTER_MYSQLI_CLASS_ENTRY(name, mysqli_entry, class_functions) { \ + zend_class_entry ce; \ + INIT_CLASS_ENTRY(ce, name,class_functions); \ + ce.create_object = mysqli_objects_new; \ + mysqli_entry = zend_register_internal_class(&ce TSRMLS_CC); \ +} \ + +#define MYSQLI_REGISTER_RESOURCE_EX(__ptr, __zval) \ + ((mysqli_object *) zend_object_store_get_object(__zval TSRMLS_CC))->ptr = __ptr; + +#define MYSQLI_RETURN_RESOURCE(__ptr, __ce) \ + Z_TYPE_P(return_value) = IS_OBJECT; \ + (return_value)->value.obj = mysqli_objects_new(__ce TSRMLS_CC); \ + MYSQLI_REGISTER_RESOURCE_EX(__ptr, return_value) + +#define MYSQLI_REGISTER_RESOURCE(__ptr, __ce) \ +{\ + zval *object = getThis();\ + if (!object || !instanceof_function(Z_OBJCE_P(object), mysqli_link_class_entry TSRMLS_CC)) {\ + object = return_value;\ + Z_TYPE_P(object) = IS_OBJECT;\ + (object)->value.obj = mysqli_objects_new(__ce TSRMLS_CC);\ + }\ + MYSQLI_REGISTER_RESOURCE_EX(__ptr, object)\ +} + +#define MYSQLI_FETCH_RESOURCE(__ptr, __type, __id, __name, __check) \ +{ \ + MYSQLI_RESOURCE *my_res; \ + mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*(__id) TSRMLS_CC);\ + if (!(my_res = (MYSQLI_RESOURCE *)intern->ptr)) {\ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Couldn't fetch %s", intern->zo.ce->name);\ + RETURN_NULL();\ + }\ + __ptr = (__type)my_res->ptr; \ + if (__check && my_res->status < __check) { \ + php_error_docref(NULL TSRMLS_CC, E_WARNING, "invalid object or resource %s\n", intern->zo.ce->name); \ + RETURN_NULL();\ + }\ +} + +#define MYSQLI_SET_STATUS(__id, __value) \ +{ \ + mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*(__id) TSRMLS_CC);\ + ((MYSQLI_RESOURCE *)intern->ptr)->status = __value; \ +} \ + +#define MYSQLI_CLEAR_RESOURCE(__id) \ +{ \ + mysqli_object *intern = (mysqli_object *)zend_object_store_get_object(*(__id) TSRMLS_CC);\ + efree(intern->ptr); \ + intern->ptr = NULL; \ +} + +#define MYSQLI_RETURN_LONG_LONG(__val) \ +{ \ + if ((__val) < LONG_MAX) { \ + RETURN_LONG((__val)); \ + } else { \ + char *ret; \ + int l = spprintf(&ret, 0, "%llu", (__val)); \ + RETURN_STRINGL(ret, l, 0); \ + } \ +} + +#define MYSQLI_ADD_PROPERTIES(a,b) \ +{ \ + int i = 0; \ + while (b[i].pname != NULL) { \ + mysqli_add_property(a, b[i].pname, (mysqli_read_t)b[i].r_func, (mysqli_write_t)b[i].w_func TSRMLS_CC); \ + i++; \ + }\ +} + +#if WIN32|WINNT +#define SCLOSE(a) closesocket(a) +#else +#define SCLOSE(a) close(a) +#endif + +#define MYSQLI_STORE_RESULT 0 +#define MYSQLI_USE_RESULT 1 + +/* for mysqli_fetch_assoc */ +#define MYSQLI_ASSOC 1 +#define MYSQLI_NUM 2 +#define MYSQLI_BOTH 3 + +/* for mysqli_bind_param */ +#define MYSQLI_BIND_INT 1 +#define MYSQLI_BIND_DOUBLE 2 +#define MYSQLI_BIND_STRING 3 +#define MYSQLI_BIND_SEND_DATA 4 + +/* fetch types */ +#define FETCH_SIMPLE 1 +#define FETCH_RESULT 2 + +/*** REPORT MODES ***/ +#define MYSQLI_REPORT_OFF 0 +#define MYSQLI_REPORT_ERROR 1 +#define MYSQLI_REPORT_STRICT 2 +#define MYSQLI_REPORT_INDEX 4 +#define MYSQLI_REPORT_CLOSE 8 +#define MYSQLI_REPORT_ALL 255 + +#define MYSQLI_REPORT_MYSQL_ERROR(mysql) \ +if ((MyG(report_mode) & MYSQLI_REPORT_ERROR) && mysql_errno(mysql)) { \ + php_mysqli_report_error(mysql_sqlstate(mysql), mysql_errno(mysql), mysql_error(mysql) TSRMLS_CC); \ +} + +#define MYSQLI_REPORT_STMT_ERROR(stmt) \ +if ((MyG(report_mode) & MYSQLI_REPORT_ERROR) && mysql_stmt_errno(stmt)) { \ + php_mysqli_report_error(mysql_stmt_sqlstate(stmt), mysql_stmt_errno(stmt), mysql_stmt_error(stmt) TSRMLS_CC); \ +} + +PHP_MYSQLI_API void mysqli_register_link(zval *return_value, void *link TSRMLS_DC); +PHP_MYSQLI_API void mysqli_register_stmt(zval *return_value, void *stmt TSRMLS_DC); +PHP_MYSQLI_API void mysqli_register_result(zval *return_value, void *result TSRMLS_DC); +PHP_MYSQLI_API void php_mysqli_set_error(long mysql_errno, char *mysql_err TSRMLS_DC); + +ZEND_BEGIN_MODULE_GLOBALS(mysqli) + 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; + char *default_user; + char *default_socket; + char *default_pw; + long reconnect; + long allow_local_infile; + long strict; + long error_no; + char *error_msg; + long report_mode; + HashTable *report_ht; + unsigned long multi_query; + unsigned long embedded; +#ifdef HAVE_MYSQLND + MYSQLND_THD_ZVAL_PCACHE *mysqlnd_thd_zval_cache; +#endif +ZEND_END_MODULE_GLOBALS(mysqli) + +#define MYSQLI_PROPERTY(a) extern int a(mysqli_object *obj, zval **retval TSRMLS_DC) + +MYSQLI_PROPERTY(my_prop_link_host); + +#ifdef ZTS +#define MyG(v) TSRMG(mysqli_globals_id, zend_mysqli_globals *, v) +#else +#define MyG(v) (mysqli_globals.v) +#endif + +#define my_estrdup(x) (x) ? estrdup(x) : NULL +#define my_efree(x) if (x) efree(x) + +ZEND_EXTERN_MODULE_GLOBALS(mysqli) + +#endif /* PHP_MYSQLI_STRUCTS.H */ + + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * indent-tabs-mode: t + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ |