Import mysqlnd

Patch ext/mysql and ext/mysqli to support mysqlnd
This commit is contained in:
Andrey Hristov 2007-10-05 21:23:56 +00:00
parent 9f9495a484
commit 8b9b553aa2
53 changed files with 17250 additions and 1237 deletions

View File

@ -40,7 +40,8 @@ AC_DEFUN([PHP_MYSQL_SOCKET_SEARCH], [
PHP_ARG_WITH(mysql, for MySQL support,
[ --with-mysql[=DIR] Include MySQL support. DIR is the MySQL base directory])
[ --with-mysql[=DIR] Include MySQL support. DIR is the MySQL base directory.
If mysqlnd is passed as DIR, the MySQL native driver will be used])
PHP_ARG_WITH(mysql-sock, for specified location of the MySQL UNIX socket,
[ --with-mysql-sock[=DIR] MySQL: Location of the MySQL unix socket pointer.
@ -51,9 +52,11 @@ if test -z "$PHP_ZLIB_DIR"; then
[ --with-zlib-dir[=DIR] MySQL: Set the path to libz install prefix], no, no)
fi
if test "$PHP_MYSQL" = "mysqlnd"; then
dnl enables build of mysqnd library
PHP_MYSQLND_ENABLED=yes
if test "$PHP_MYSQL" != "no"; then
AC_DEFINE(HAVE_MYSQL, 1, [Whether you have MySQL])
elif test "$PHP_MYSQL" != "no"; then
AC_MSG_CHECKING([for MySQL UNIX socket location])
if test "$PHP_MYSQL_SOCK" != "no" && test "$PHP_MYSQL_SOCK" != "yes"; then
@ -137,14 +140,22 @@ Note that the MySQL client library is not bundled anymore!])
PHP_ADD_LIBRARY_WITH_PATH($MYSQL_LIBNAME, $MYSQL_LIB_DIR, MYSQL_SHARED_LIBADD)
PHP_ADD_INCLUDE($MYSQL_INC_DIR)
PHP_NEW_EXTENSION(mysql, php_mysql.c, $ext_shared)
MYSQL_MODULE_TYPE=external
MYSQL_LIBS="-L$MYSQL_LIB_DIR -l$MYSQL_LIBNAME $MYSQL_LIBS"
MYSQL_INCLUDE=-I$MYSQL_INC_DIR
PHP_SUBST(MYSQL_SHARED_LIBADD)
PHP_SUBST_OLD(MYSQL_MODULE_TYPE)
PHP_SUBST_OLD(MYSQL_LIBS)
PHP_SUBST_OLD(MYSQL_INCLUDE)
fi
dnl Enable extension
if test "$PHP_MYSQL" != "no"; then
AC_DEFINE(HAVE_MYSQL, 1, [Whether you have MySQL])
PHP_NEW_EXTENSION(mysql, php_mysql.c, $ext_shared)
PHP_SUBST(MYSQL_SHARED_LIBADD)
if test "$PHP_MYSQLI" = "mysqlnd"; then
PHP_ADD_EXTENSION_DEP(mysqli, mysqlnd)
fi
fi

View File

@ -4,12 +4,17 @@
ARG_WITH("mysql", "MySQL support", "no");
if (PHP_MYSQL != "no") {
if (CHECK_LIB("libmysql.lib", "mysql", PHP_MYSQL) &&
if (PHP_MYSQLI != "mysqlnd") {
if (CHECK_LIB("libmysql.lib", "mysql", PHP_MYSQL) &&
CHECK_HEADER_ADD_INCLUDE("mysql.h", "CFLAGS_MYSQL",
PHP_MYSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\mysql;" + PHP_MYSQL)) {
EXTENSION("mysql", "php_mysql.c");
AC_DEFINE('HAVE_MYSQL', 1, 'Have MySQL library');
PHP_MYSQL + "\\include;" + PHP_PHP_BUILD + "\\include\\mysql;" + PHP_MYSQL)) {
} else {
WARNING("mysql not enabled; libraries and headers not found");
}
} else {
WARNING("mysql not enabled; libraries and headers not found");
AC_DEFINE('HAVE_MYSQLND', 1, 'MySQL native driver support enabled');
ADD_EXTENSION_DEP('mysql', 'mysqlnd', true);
}
EXTENSION("mysql", "php_mysql.c");
AC_DEFINE('HAVE_MYSQL', 1, 'Have MySQL library');
}

41
ext/mysql/mysql_mysqlnd.h Normal file
View File

@ -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 MYSQL_MYSQLND_H
#define MYSQL_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

File diff suppressed because it is too large Load Diff

View File

@ -34,6 +34,25 @@
#include "TSRM.h"
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#if defined(HAVE_MYSQLND)
#include "ext/mysqlnd/mysqlnd.h"
#include "ext/mysql/mysql_mysqlnd.h"
#else
#include <mysql.h>
#endif
#if (MYSQL_VERSION_ID >= 40113 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50007 || HAVE_MYSQLND
#define MYSQL_HAS_SET_CHARSET
#endif
extern zend_module_entry mysql_module_entry;
#define mysql_module_ptr &mysql_module_entry
@ -91,9 +110,6 @@ PHP_FUNCTION(mysql_stat);
PHP_FUNCTION(mysql_thread_id);
PHP_FUNCTION(mysql_client_encoding);
PHP_FUNCTION(mysql_ping);
#if (MYSQL_VERSION_ID >= 40113 && MYSQL_VERSION_ID < 50000) || MYSQL_VERSION_ID >= 50007
PHP_FUNCTION(mysql_set_charset);
#endif
ZEND_BEGIN_MODULE_GLOBALS(mysql)
long default_link;
@ -108,6 +124,12 @@ ZEND_BEGIN_MODULE_GLOBALS(mysql)
long connect_timeout;
long result_allocated;
long trace_mode;
long allow_local_infile;
#ifdef HAVE_MYSQLND
MYSQLND_THD_ZVAL_PCACHE *mysqlnd_thd_zval_cache;
MYSQLND_QCACHE *mysqlnd_qcache;
long cache_size;
#endif
ZEND_END_MODULE_GLOBALS(mysql)
#ifdef ZTS

View File

@ -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)
PHP_SUBST(MYSQLI_SHARED_LIBADD)
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

View File

@ -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);
}
}

View File

@ -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:

File diff suppressed because it is too large Load Diff

View File

@ -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}
};
/* }}} */

View File

@ -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 */

View File

@ -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[]

View File

@ -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}
};
/* }}} */

View File

@ -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))

View File

@ -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

View File

@ -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,45 +29,53 @@
#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;
@ -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 (!(mysql->mysql = mysql_init(NULL))) {
efree(mysql);
RETURN_FALSE;
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))) {
#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

View File

@ -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},

View File

@ -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)
*/

View File

@ -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) {

View File

@ -25,60 +25,72 @@
#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 = (void *)w;
prev->next = w;
}
prev = w;
}
@ -86,6 +98,88 @@ MYSQLI_WARNING *php_get_warnings(MYSQL *mysql)
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;
}
if (prev) {
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:

View File

@ -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

View File

@ -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
*/

2
ext/mysqlnd/CREDITS Normal file
View File

@ -0,0 +1,2 @@
MySQLnd
Georg Richter, Andrey Hristov, Ulf Wendel

98
ext/mysqlnd/config-win.h Normal file
View File

@ -0,0 +1,98 @@
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
/* Defines for Win32 to make it compatible for MySQL */
#include <sys/locking.h>
#include <windows.h>
#include <math.h> /* Because of rint() */
#include <fcntl.h>
#include <io.h>
#include <malloc.h>
#if defined(__NT__)
#define SYSTEM_TYPE "NT"
#elif defined(__WIN2000__)
#define SYSTEM_TYPE "WIN2000"
#else
#define SYSTEM_TYPE "Win95/Win98"
#endif
#ifdef _WIN64
#define MACHINE_TYPE "ia64" /* Define to machine type name */
#else
#define MACHINE_TYPE "i32" /* Define to machine type name */
#ifndef _WIN32
#define _WIN32 /* Compatible with old source */
#endif
#ifndef __WIN32__
#define __WIN32__
#endif
#endif /* _WIN64 */
#ifndef __WIN__
#define __WIN__ /* To make it easier in VC++ */
#endif
#define LONGLONG_MIN ((__int64) 0x8000000000000000)
#define LONGLONG_MAX ((__int64) 0x7FFFFFFFFFFFFFFF)
#define LL(A) ((__int64) A)
/* Type information */
typedef unsigned short ushort;
typedef unsigned int uint;
typedef unsigned __int64 ulonglong; /* Microsofts 64 bit types */
typedef __int64 longlong;
typedef int sigset_t;
#define longlong_defined
#define SIZEOF_CHAR 1
#define SIZEOF_LONG 4
#define SIZEOF_LONG_LONG 8
#ifndef _WIN64
/* Optimized store functions for Intel x86 */
#define sint2korr(A) (*((int16 *) (A)))
#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
(((uint32) 255L << 24) | \
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])) : \
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])))
#define sint4korr(A) (*((long *) (A)))
#define uint2korr(A) (*((uint16 *) (A)))
#define uint3korr(A) (long) (*((unsigned long *) (A)) & 0xFFFFFF)
#define uint4korr(A) (*((unsigned long *) (A)))
#define uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16) +\
(((uint32) ((uchar) (A)[3])) << 24)) +\
(((ulonglong) ((uchar) (A)[4])) << 32))
#define uint8korr(A) (*((ulonglong *) (A)))
#define sint8korr(A) (*((longlong *) (A)))
#define int2store(T,A) *((uint16*) (T))= (uint16) (A)
#define int3store(T,A) { *(T)= (uchar) ((A));\
*(T+1)=(uchar) (((uint) (A) >> 8));\
*(T+2)=(uchar) (((A) >> 16)); }
#define int4store(T,A) *((long *) (T))= (long) (A)
#define int5store(T,A) { *(T)= (uchar)((A));\
*((T)+1)=(uchar) (((A) >> 8));\
*((T)+2)=(uchar) (((A) >> 16));\
*((T)+3)=(uchar) (((A) >> 24)); \
*((T)+4)=(uchar) (((A) >> 32)); }
#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A)
#define doubleget(V,M) { *((long *) &V) = *((long*) M); \
*(((long *) &V)+1) = *(((long*) M)+1); }
#define doublestore(T,V) { *((long *) T) = *((long*) &V); \
*(((long *) T)+1) = *(((long*) &V)+1); }
#define float4get(V,M) { *((long *) &(V)) = *((long*) (M)); }
#define float8get(V,M) doubleget((V),(M))
#define float4store(V,M) memcpy((byte*) V,(byte*) (&M),sizeof(float))
#define float8store(V,M) doublestore((V),(M))
#endif /* _WIN64 */

20
ext/mysqlnd/config.w32 Normal file
View File

@ -0,0 +1,20 @@
// $Id$
// vim:ft=javascript
mysqld_source = "";
if (CHECK_LIB("ws2_32.lib", "mysqlnd")) {
mysqlnd_source =
"mysqlnd.c " +
"mysqlnd_debug.c " +
"mysqlnd_charset.c " +
"mysqlnd_loaddata.c " +
"mysqlnd_palloc.c " +
"mysqlnd_ps.c " +
"mysqlnd_ps_codec.c " +
"mysqlnd_qcache.c " +
"mysqlnd_result.c " +
"mysqlnd_result_meta.c " +
"mysqlnd_statistics.c " +
"mysqlnd_wireprotocol.c";
EXTENSION("mysqlnd", mysqlnd_source, false);
}

29
ext/mysqlnd/config9.m4 Normal file
View File

@ -0,0 +1,29 @@
dnl
dnl $Id$
dnl config.m4 for mysqlnd driver
dnl If some extension uses mysqlnd it will get compiled in PHP core
if test "$PHP_MYSQLND_ENABLED" = "yes"; then
mysqlnd_sources="mysqlnd.c mysqlnd_charset.c mysqlnd_wireprotocol.c \
mysqlnd_ps.c mysqlnd_loaddata.c mysqlnd_palloc.c \
mysqlnd_ps_codec.c mysqlnd_statistics.c mysqlnd_qcache.c\
mysqlnd_result.c mysqlnd_result_meta.c mysqlnd_debug.c"
PHP_NEW_EXTENSION(mysqlnd, $mysqlnd_sources, no)
PHP_ADD_BUILD_DIR([ext/mysqlnd], 1)
PHP_INSTALL_HEADERS([ext/mysqlnd])
PHP_INSTALL_HEADERS([$ext_builddir/php_mysqlnd_config.h])
AC_DEFINE([HAVE_MYSQLND], 1, [Whether mysqlnd is enabled])
dnl This creates a file so it has to be after above macros
PHP_CHECK_TYPES([int8 uint8 int16 uint16 int32 uint32 uchar ulong int8_t uint8_t int16_t uint16_t int32_t uint32_t int64_t uint64_t], [
$ext_builddir/php_mysqlnd_config.h
],[
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
])
fi

2078
ext/mysqlnd/mysqlnd.c Normal file

File diff suppressed because it is too large Load Diff

354
ext/mysqlnd/mysqlnd.h Normal file
View File

@ -0,0 +1,354 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_H
#define MYSQLND_H
#define MYSQLND_VERSION "mysqlnd 5.0.2-dev - 070928 - $Revision$"
#define MYSQLND_VERSION_ID 50002
/* This forces inlining of some accessor functions */
#define MYSQLND_USE_OPTIMISATIONS 0
/* #define MYSQLND_STRING_TO_INT_CONVERSION */
/*
This force mysqlnd to do a single (or more depending on ammount of data)
non-blocking read() calls before sending a command to the server. Useful
for debugging, if previous function hasn't consumed all the output sent
to it - like stmt_send_long_data() error because the data was larger that
max_allowed_packet_size, and COM_STMT_SEND_LONG_DATA by protocol doesn't
use response packets, thus letting the next command to fail miserably, if
the connector implementor is not aware of this deficiency. Should be off
on production systems, if of course measured performance degradation is not
minimal.
*/
#if PHP_DEBUG
#define MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND 1
#endif
#ifdef ZTS
#include "TSRM.h"
#endif
#include "mysqlnd_portability.h"
#include "mysqlnd_enum_n_def.h"
#include "mysqlnd_structs.h"
/* Library related */
#define mysqlnd_restart_psession(conn) _mysqlnd_restart_psession((conn) TSRMLS_CC)
PHPAPI void _mysqlnd_restart_psession(MYSQLND *conn TSRMLS_DC);
PHPAPI void mysqlnd_end_psession(MYSQLND *conn);
PHPAPI void mysqlnd_minfo_print_hash(zval *values);
#define mysqlnd_thread_safe() TRUE
PHPAPI const MYSQLND_CHARSET * mysqlnd_find_charset_nr(uint charsetno);
PHPAPI const MYSQLND_CHARSET * mysqlnd_find_charset_name(const char * const charsetname);
/* Connect */
#define mysqlnd_init(persistent) _mysqlnd_init((persistent) TSRMLS_CC)
PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC);
PHPAPI MYSQLND * mysqlnd_connect(MYSQLND *conn,
char *host, char *user,
char *passwd, unsigned int passwd_len,
char *db, unsigned int db_len,
unsigned int port,
char *socket,
unsigned int mysql_flags,
MYSQLND_THD_ZVAL_PCACHE *zval_cache
TSRMLS_DC);
#define mysqlnd_change_user(conn, user, passwd, db) (conn)->m->change_user((conn), (user), (passwd), (db) TSRMLS_CC)
#define mysqlnd_debug(x) _mysqlnd_debug((x) TSRMLS_CC)
void _mysqlnd_debug(const char *mode TSRMLS_DC);
/* Query */
#define mysqlnd_fetch_into(result, flags, ret_val, ext) (result)->m.fetch_into((result), (flags), (ret_val), (ext) TSRMLS_CC ZEND_FILE_LINE_CC)
#define mysqlnd_fetch_all(result, flags, return_value) (result)->m.fetch_all((result), (flags), (return_value) TSRMLS_CC ZEND_FILE_LINE_CC)
#define mysqlnd_result_fetch_field_data(res,offset,ret) (res)->m.fetch_field_data((res), (offset), (ret) TSRMLS_CC)
#define mysqlnd_get_connection_stats(conn, values) (conn)->m->get_statistics((conn), (values) TSRMLS_CC ZEND_FILE_LINE_CC)
#define mysqlnd_get_client_stats(values) _mysqlnd_get_client_stats((values) TSRMLS_CC ZEND_FILE_LINE_CC)
#define mysqlnd_close(conn,is_forced) (conn)->m->close((conn), (is_forced) TSRMLS_CC)
#define mysqlnd_query(conn, query_str, query_len) (conn)->m->query((conn), (query_str), (query_len) TSRMLS_CC)
#define mysqlnd_unbuffered_skip_result(result) (result)->m.skip_result((result) TSRMLS_CC)
#define mysqlnd_use_result(conn) (conn)->m->use_result((conn) TSRMLS_CC)
#define mysqlnd_store_result(conn) (conn)->m->store_result((conn) TSRMLS_CC)
#define mysqlnd_next_result(conn) (conn)->m->next_result((conn) TSRMLS_CC)
#define mysqlnd_more_results(conn) (conn)->m->more_results((conn))
#define mysqlnd_free_result(r,e_or_i) ((MYSQLND_RES*)r)->m.free_result(((MYSQLND_RES*)(r)), (e_or_i) TSRMLS_CC)
#define mysqlnd_data_seek(result, row) (result)->m.seek_data((result), (row) TSRMLS_CC)
/*****************************************************************************************************/
#if defined(MYSQLND_USE_OPTIMISATIONS) && MYSQLND_USE_OPTIMISATIONS == 1
/* Errors */
#define mysqlnd_errno(conn) (conn)->error_info.error_no
#define mysqlnd_error(conn) (conn)->error_info.error
#define mysqlnd_sqlstate(conn) ((conn)->error_info.sqlstate[0] ? conn->error_info.sqlstate:MYSQLND_SQLSTATE_NULL)
/* Charset */
#define mysqlnd_character_set_name(conn) (conn)->charset->name
/* Simple metadata */
#define mysqlnd_field_count(conn) (conn)->field_count
#define mysqlnd_insert_id(conn) (conn)->upsert_status.last_insert_id
#define mysqlnd_affected_rows(conn) (conn)->upsert_status.affected_rows
#define mysqlnd_warning_count(conn) (conn)->upsert_status.warning_count
#define mysqlnd_info(conn) (conn)->last_message
#define mysqlnd_get_server_info(conn) (conn)->server_version
#define mysqlnd_get_host_info(conn) (conn)->host_info
#define mysqlnd_get_proto_info(conn) (conn)->protocol_version
#define mysqlnd_thread_id(conn) (conn)->thread_id
#define mysqlnd_num_rows(result) ((result)->data? (result)->data->row_count:0)
#define mysqlnd_num_fields(result) (result)->field_count
#define mysqlnd_fetch_lengths(result) ((result)->m.fetch_lengths? (result)->m.fetch_lengths((result)):NULL)
#define mysqlnd_field_seek(result, ofs) (result)->m.seek_field((result), (ofs))
#define mysqlnd_field_tell(result) (result)->meta? (result)->meta->current_field:0)
#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result) TSRMLS_CC)
#define mysqlnd_fetch_field_direct(result,fnr) ((result)->meta? &((result)->meta->fields[(fnr)]):NULL)
/* mysqlnd metadata */
#define mysqlnd_get_client_info() MYSQLND_VERSION
#define mysqlnd_get_client_version() MYSQLND_VERSION_ID
/* PS */
#define mysqlnd_stmt_insert_id(stmt) (stmt)->upsert_status.last_insert_id
#define mysqlnd_stmt_affected_rows(stmt) (stmt)->upsert_status.affected_rows
#define mysqlnd_stmt_num_rows(stmt) (stmt)->result? mysqlnd_num_rows((stmt)->result):0
#define mysqlnd_stmt_param_count(stmt) (stmt)->param_count
#define mysqlnd_stmt_field_count(stmt) (stmt)->field_count
#define mysqlnd_stmt_warning_count(stmt) (stmt)->upsert_status.warning_count
#define mysqlnd_stmt_errno(stmt) (stmt)->error_info.error_no
#define mysqlnd_stmt_error(stmt) (stmt)->error_info.error
#define mysqlnd_stmt_sqlstate(stmt) ((stmt)->error_info.sqlstate[0] ? (stmt)->error_info.sqlstate:MYSQLND_SQLSTATE_NULL)
/*****************************************************************************************************/
#else /* Using plain functions */
/*****************************************************************************************************/
/* Errors */
#define mysqlnd_errno(conn) (conn)->m->get_error_no((conn))
#define mysqlnd_error(conn) (conn)->m->get_error_str((conn))
#define mysqlnd_sqlstate(conn) (conn)->m->get_sqlstate((conn))
/* Charset */
#define mysqlnd_character_set_name(conn) (conn)->m->charset_name((conn))
/* Simple metadata */
#define mysqlnd_field_count(conn) (conn)->m->get_field_count((conn))
#define mysqlnd_insert_id(conn) (conn)->m->get_last_insert_id((conn))
#define mysqlnd_affected_rows(conn) (conn)->m->get_affected_rows((conn))
#define mysqlnd_warning_count(conn) (conn)->m->get_warning_count((conn))
#define mysqlnd_info(conn) (conn)->m->get_last_message((conn))
#define mysqlnd_get_server_info(conn) (conn)->m->get_server_information((conn))
#define mysqlnd_get_host_info(conn) (conn)->m->get_host_information((conn))
#define mysqlnd_get_proto_info(conn) (conn)->m->get_protocol_information((conn))
#define mysqlnd_thread_id(conn) (conn)->m->get_thread_id((conn))
#define mysqlnd_num_rows(result) (result)->m.num_rows((result))
#define mysqlnd_num_fields(result) (result)->m.num_fields((result))
PHPAPI unsigned long * mysqlnd_fetch_lengths(MYSQLND_RES * const result);
#define mysqlnd_field_seek(result, ofs) (result)->m.seek_field((result), (ofs))
#define mysqlnd_field_tell(result) (result)->m.field_tell((result))
#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result) TSRMLS_CC)
#define mysqlnd_fetch_field_direct(result,fnr) (result)->m.fetch_field_direct((result), (fnr) TSRMLS_CC)
/* mysqlnd metadata */
PHPAPI const char * mysqlnd_get_client_info();
PHPAPI unsigned int mysqlnd_get_client_version();
/* PS */
#define mysqlnd_stmt_insert_id(stmt) (stmt)->m->get_last_insert_id((stmt))
#define mysqlnd_stmt_affected_rows(stmt) (stmt)->m->get_affected_rows((stmt))
#define mysqlnd_stmt_num_rows(stmt) (stmt)->m->get_num_rows((stmt))
#define mysqlnd_stmt_param_count(stmt) (stmt)->m->get_param_count((stmt))
#define mysqlnd_stmt_field_count(stmt) (stmt)->m->get_field_count((stmt))
#define mysqlnd_stmt_warning_count(stmt) (stmt)->m->get_warning_count((stmt))
#define mysqlnd_stmt_errno(stmt) (stmt)->m->get_error_no((stmt))
#define mysqlnd_stmt_error(stmt) (stmt)->m->get_error_str((stmt))
#define mysqlnd_stmt_sqlstate(stmt) (stmt)->m->get_sqlstate((stmt))
#endif /* MYSQLND_USE_OPTIMISATIONS */
/*****************************************************************************************************/
PHPAPI const char * mysqlnd_field_type_name(enum mysqlnd_field_types field_type);
/* LOAD DATA LOCAL */
PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn);
PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND * const conn, const char * const funcname);
/* Simple commands */
#define mysqlnd_autocommit(conn, mode) (conn)->m->query((conn),(mode) ? "SET AUTOCOMMIT=1":"SET AUTOCOMMIT=0", 16 TSRMLS_CC)
#define mysqlnd_commit(conn) (conn)->m->query((conn), "COMMIT", sizeof("COMMIT")-1 TSRMLS_CC)
#define mysqlnd_rollback(conn) (conn)->m->query((conn), "ROLLBACK", sizeof("ROLLBACK")-1 TSRMLS_CC)
#define mysqlnd_list_dbs(conn, wild) (conn)->m->list_method((conn), wild? "SHOW DATABASES LIKE %s":"SHOW DATABASES", (wild), NULL TSRMLS_CC)
#define mysqlnd_list_fields(conn, tab,wild) (conn)->m->list_fields((conn), (tab), (wild) TSRMLS_CC)
#define mysqlnd_list_processes(conn) (conn)->m->list_method((conn), "SHOW PROCESSLIST", NULL, NULL TSRMLS_CC)
#define mysqlnd_list_tables(conn, wild) (conn)->m->list_method((conn), wild? "SHOW TABLES LIKE %s":"SHOW TABLES", (wild), NULL TSRMLS_CC)
#define mysqlnd_dump_debug_info(conn) (conn)->m->server_dump_debug_information((conn) TSRMLS_CC)
#define mysqlnd_select_db(conn, db, db_len) (conn)->m->select_db((conn), (db), (db_len) TSRMLS_CC)
#define mysqlnd_ping(conn) (conn)->m->ping((conn) TSRMLS_CC)
#define mysqlnd_kill(conn, pid) (conn)->m->kill_connection((conn), (pid) TSRMLS_CC)
#define mysqlnd_refresh(conn, options) (conn)->m->refresh_server((conn), (options) TSRMLS_CC)
#define mysqlnd_shutdown(conn, level) (conn)->m->shutdown_server((conn), (level) TSRMLS_CC)
#define mysqlnd_get_server_version(conn) (conn)->m->get_server_version((conn))
#define mysqlnd_set_character_set(conn, cs) (conn)->m->set_charset((conn), (cs) TSRMLS_CC)
#define mysqlnd_stat(conn, msg, msg_len) (conn)->m->get_server_statistics((conn), (msg), (msg_len) TSRMLS_CC)
#define mysqlnd_options(conn, opt, value) (conn)->m->set_client_option((conn), (opt), (value) TSRMLS_CC)
#define mysqlnd_set_server_option(conn, op) (conn)->m->set_server_option((conn), (op) TSRMLS_CC)
/* Escaping */
#define mysqlnd_real_escape_string(conn, newstr, escapestr, escapestr_len) \
(conn)->m->escape_string((conn), (newstr), (escapestr), (escapestr_len) TSRMLS_CC)
#define mysqlnd_escape_string(newstr, escapestr, escapestr_len) \
mysqlnd_old_escape_string((newstr), (escapestr), (escapestr_len) TSRMLS_CC)
PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, int escapestr_len TSRMLS_DC);
/* PS */
#define mysqlnd_stmt_init(conn) (conn)->m->stmt_init((conn) TSRMLS_CC)
#define mysqlnd_stmt_store_result(stmt) (!mysqlnd_stmt_field_count((stmt)) ? PASS:((stmt)->m->store_result((stmt) TSRMLS_CC)? PASS:FAIL))
#define mysqlnd_stmt_get_result(stmt) (stmt)->m->get_result((stmt) TSRMLS_CC)
#define mysqlnd_stmt_data_seek(stmt, row) (stmt)->m->seek_data((stmt), (row) TSRMLS_CC)
#define mysqlnd_stmt_prepare(stmt, q, qlen) (stmt)->m->prepare((stmt), (q), (qlen) TSRMLS_CC)
#define mysqlnd_stmt_execute(stmt) (stmt)->m->execute((stmt) TSRMLS_CC)
#define mysqlnd_stmt_send_long_data(s,p,d,l) (s)->m->send_long_data((s), (p), (d), (l) TSRMLS_CC)
#define mysqlnd_stmt_bind_param(stmt,bind) (stmt)->m->bind_param((stmt), (bind) TSRMLS_CC)
#define mysqlnd_stmt_bind_result(stmt,bind) (stmt)->m->bind_result((stmt), (bind) TSRMLS_CC)
#define mysqlnd_stmt_param_metadata(stmt) (stmt)->m->get_parameter_metadata((stmt))
#define mysqlnd_stmt_result_metadata(stmt) (stmt)->m->get_result_metadata((stmt) TSRMLS_CC)
#define mysqlnd_stmt_free_result(stmt) (stmt)->m->free_result((stmt) TSRMLS_CC)
#define mysqlnd_stmt_close(stmt, implicit) (stmt)->m->dtor((stmt), (implicit) TSRMLS_CC)
#define mysqlnd_stmt_reset(stmt) (stmt)->m->reset((stmt) TSRMLS_CC)
#define mysqlnd_stmt_attr_get(stmt, attr, value) (stmt)->m->get_attribute((stmt), (attr), (value) TSRMLS_CC)
#define mysqlnd_stmt_attr_set(stmt, attr, value) (stmt)->m->set_attribute((stmt), (attr), (value) TSRMLS_CC)
#define mysqlnd_stmt_fetch(stmt, fetched) (stmt)->m->fetch((stmt), (fetched) TSRMLS_CC)
/* Performance statistics */
PHPAPI void _mysqlnd_get_client_stats(zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
/* Persistent caching zval allocator */
#define mysqlnd_palloc_init_cache(size) _mysqlnd_palloc_init_cache((size) TSRMLS_CC)
#define mysqlnd_palloc_free_cache(cache) _mysqlnd_palloc_free_cache((cache) TSRMLS_CC)
PHPAPI MYSQLND_ZVAL_PCACHE* _mysqlnd_palloc_init_cache(unsigned int cache_size TSRMLS_DC);
PHPAPI void _mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache TSRMLS_DC);
PHPAPI void mysqlnd_palloc_stats(const MYSQLND_ZVAL_PCACHE * const cache,
zval *return_value);
#define mysqlnd_palloc_rinit(cache) _mysqlnd_palloc_rinit((cache) TSRMLS_CC)
#define mysqlnd_palloc_rshutdown(cache) _mysqlnd_palloc_rshutdown((cache) TSRMLS_CC)
PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache TSRMLS_DC);
PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * cache TSRMLS_DC);
#define mysqlnd_palloc_init_thd_cache(cache) _mysqlnd_palloc_init_thd_cache((cache) TSRMLS_CC)
#define mysqlnd_palloc_free_thd_cache_reference(cache) _mysqlnd_palloc_free_thd_cache_reference((cache) TSRMLS_CC)
PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC);
MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache);
PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC);
/* There two should not be used from outside */
void * mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const cache, zend_bool *allocated TSRMLS_DC);
void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const cache,
enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC);
/* ---------------------- QUERY CACHE ---------------*/
struct st_mysqlnd_qcache {
HashTable *ht;
unsigned int references;
#ifdef ZTS
MUTEX_T LOCK_access;
#endif
};
typedef struct st_mysqlnd_qcache_element {
MYSQLND_RES_BUFFERED *data;
MYSQLND_RES_METADATA *meta;
const char * query;
size_t query_len;
} MYSQLND_QCACHE_ELEMENT;
PHPAPI MYSQLND_QCACHE * mysqlnd_qcache_init_cache();
PHPAPI MYSQLND_QCACHE * mysqlnd_qcache_get_cache_reference(MYSQLND_QCACHE * const cache);
PHPAPI void mysqlnd_qcache_free_cache_reference(MYSQLND_QCACHE **cache);
PHPAPI void mysqlnd_qcache_stats(const MYSQLND_QCACHE * const cache, zval *return_value);
MYSQLND_RES * mysqlnd_qcache_get(MYSQLND_QCACHE * const cache, const char * query,
size_t query_len);
void mysqlnd_qcache_put(MYSQLND_QCACHE * const cache, char * query, size_t query_len,
MYSQLND_RES_BUFFERED * const result, MYSQLND_RES_METADATA * const meta);
ZEND_BEGIN_MODULE_GLOBALS(mysqlnd)
zend_bool collect_statistics;
zend_bool collect_memory_statistics;
char* debug; /* The actual string */
MYSQLND_DEBUG *dbg; /* The DBG object */
long net_cmd_buffer_size;
long net_read_buffer_size;
ZEND_END_MODULE_GLOBALS(mysqlnd)
ZEND_EXTERN_MODULE_GLOBALS(mysqlnd);
#ifdef ZTS
#define MYSQLND_G(v) TSRMG(mysqlnd_globals_id, zend_mysqlnd_globals *, v)
#else
#define MYSQLND_G(v) (mysqlnd_globals.v)
#endif
#endif /* MYSQLND_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

285
ext/mysqlnd/mysqlnd_alloc.c Normal file
View File

@ -0,0 +1,285 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_palloc.h"
#define MYSQLND_SILENT
#define MYSQLND_DONT_DUMP_STATS
#define MYSQLND_ZVALS_MAX_CACHE 5000
#if A0
/* Caching zval allocator */
zval * mysqlnd_alloc_get_zval(MYSQLND_ZVAL_CACHE * const cache);
void mysqlnd_alloc_zval_ptr_dtor(zval **zv, MYSQLND_ZVAL_CACHE * const cache);
MYSQLND_ZVAL_CACHE* mysqlnd_alloc_init_cache();
MYSQLND_ZVAL_CACHE* mysqlnd_alloc_get_cache_reference(MYSQLND_ZVAL_CACHE *cache);
void mysqlnd_alloc_free_cache_reference(MYSQLND_ZVAL_CACHE **cache);
#endif
/*
The cache line is a big contiguous array of zval pointers.
Because the CPU cache will cache starting from an address, and not
before it, then we have to organize our structure according to this.
Thus, if 'last_added' is valid pointer (not NULL) then last_added is
increased. When zval is cached, if there is room, last_added is decreased
and then the zval pointer will be assigned to it. This means that some
positions may become hot points and stay in the cache.
Imagine we have 5 pointers in a line
1. last_added = list_item->ptr_line + cache->max_items;
2. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
3. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
4. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
0x0
0x0
0x0
0x0
0x0
---
empty_position, always 0x0 <-- last_added
5. free_zval -> if (free_items++ != max_items) {// we can add more
*(--last_added) = zval_ptr;
}
(memory addresses increase downwards)
0x0
0x0
0x0
0x0
0xA <-- last_added
---
0x0
6. free_zval -> if (free_items++ != max_items) {// we can add more
*(--last_added) = zval_ptr;
}
0x0
0x0
0x0
0xB <-- last_added
0xA
---
0x0
7. free_zval -> if (free_items++ != max_items) {// we can add more
*(--last_added) = zval_ptr;
}
0x0
0x0
0xC <-- last_added
0xB
0xA
---
0x0
8. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
0x0
0x0
0x0
0xB <-- last_added
0xA
---
0x0
9. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
0x0
0x0
0x0
0x0
0xA <-- last_added
---
0x0
10. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
0x0
0x0
0x0
0x0
0x0
---
0x0 <-- last_added
*/
zval * mysqlnd_alloc_get_zval(MYSQLND_ZVAL_CACHE * const cache)
{
zval *ret = NULL;
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_alloc_get_zval %p] *last_added=%p free_items=%d ", cache, cache? cache->free_list->last_added:NULL, cache->free_items);
#endif
if (cache) {
if ((ret = *cache->free_list->last_added)) {
*cache->free_list->last_added++ = NULL;
--cache->free_items;
++cache->get_hits;
} else {
++cache->get_misses;
}
}
if (!ret) {
ALLOC_ZVAL(ret);
}
INIT_PZVAL(ret);
#ifndef MYSQLND_SILENT
php_printf("ret=%p\n", ret);
#endif
return ret;
}
static
void mysqlnd_alloc_cache_prealloc(MYSQLND_ZVAL_CACHE * const cache, unsigned int count)
{
zval *data;
cache->free_items = count;
while (count--) {
MAKE_STD_ZVAL(data);
ZVAL_NULL(data);
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_alloc_prealloc %p] items=%d data=%p\n", cache, cache->free_items, data);
#endif
*(--cache->free_list->last_added) = data;
}
}
void mysqlnd_alloc_zval_ptr_dtor(zval **zv, MYSQLND_ZVAL_CACHE * const cache)
{
if (!cache || ZVAL_REFCOUNT(*zv) > 1 || cache->max_items == cache->free_items) {
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_alloc_zval_ptr_dtor %p]1 last_added-1=%p *zv=%p\n", cache->free_list->last_added, *zv);
#endif
/* We can't cache zval's with refcount > 1 */
zval_ptr_dtor(zv);
if (cache) {
if (cache->max_items == cache->free_items) {
++cache->put_full_misses;
} else {
++cache->put_refcount_misses;
}
}
} else {
/* refcount is 1 and there is place. Go, cache it! */
++cache->free_items;
zval_dtor(*zv);
ZVAL_NULL(*zv);
*(--cache->free_list->last_added) = *zv;
++cache->put_hits;
}
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_alloc_zval_ptr_dtor %p] free_items=%d\n", cache, cache->free_items);
#endif
}
MYSQLND_ZVAL_CACHE* mysqlnd_alloc_init_cache(void)
{
MYSQLND_ZVAL_CACHE *ret = ecalloc(1, sizeof(MYSQLND_ZVAL_CACHE));
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_alloc_init_cache %p]\n", ret);
#endif
ret->max_items = MYSQLND_ZVALS_MAX_CACHE;
ret->free_items = 0;
ret->references = 1;
/* Let's have always one, so we don't need to do a check in get_zval */
ret->free_list = ecalloc(1, sizeof(struct st_mysqlnd_zval_list));
/* One more for empty position of last_added */
ret->free_list->ptr_line = ecalloc(ret->max_items + 1, sizeof(zval *));
ret->free_list->last_added = ret->free_list->ptr_line + ret->max_items;
mysqlnd_alloc_cache_prealloc(ret, (ret->max_items / 100) * 100);
return ret;
}
MYSQLND_ZVAL_CACHE* mysqlnd_alloc_get_cache_reference(MYSQLND_ZVAL_CACHE *cache)
{
if (cache) {
cache->references++;
}
return cache;
}
static
void mysqlnd_alloc_free_cache(MYSQLND_ZVAL_CACHE *cache)
{
#ifndef MYSQLND_SILENT
uint i = 0;
php_printf("[mysqlnd_alloc_free_cache %p]\n", cache);
#endif
while (*cache->free_list->last_added) {
#ifndef MYSQLND_SILENT
php_printf("\t[free_item %d %p]\n", i++, *cache->free_list->last_added);
#endif
zval_ptr_dtor(cache->free_list->last_added);
cache->free_list->last_added++;
}
#ifndef MYSQLND_DONT_DUMP_STATS
php_printf("CACHE STATS:\n\tGET\n\t\tHITS:%lu\n\t\tMISSES=%lu\n\t\tHIT RATIO=%1.3f\n\t"
"PUT\n\t\tHITS:%lu\n\t\tFULL_MISS=%lu\n\t\tREFC_MISS=%lu\n\t\tHIT RATIO=%1.3f\n\n",
cache->get_hits, cache->get_misses, (1.0*cache->get_hits/(cache->get_hits + cache->get_misses)),
cache->put_hits, cache->put_full_misses, cache->put_refcount_misses,
(1.0 * cache->put_hits / (cache->put_hits + cache->put_full_misses + cache->put_refcount_misses)));
#endif
efree(cache->free_list->ptr_line);
efree(cache->free_list);
efree(cache);
}
void mysqlnd_alloc_free_cache_reference(MYSQLND_ZVAL_CACHE **cache)
{
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_alloc_free_cache_reference %p] refs=%d\n", *cache, (*cache)->references);
#endif
if (*cache && --(*cache)->references == 0) {
mysqlnd_alloc_free_cache(*cache);
}
*cache = NULL;
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,603 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
#include "php.h"
#include "php_globals.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_debug.h"
/* {{{ utf8 functions */
static uint check_mb_utf8_sequence(const char *start, const char *end)
{
zend_uchar c;
if (start >= end) {
return 0;
}
c = (zend_uchar) start[0];
if (c < 0x80) {
return 1; /* single byte character */
}
if (c < 0xC2) {
return 0; /* invalid mb character */
}
if (c < 0xE0) {
if (start + 2 > end) {
return 0; /* too small */
}
if (!(((zend_uchar)start[1] ^ 0x80) < 0x40)) {
return 0;
}
return 2;
}
if (c < 0xF0) {
if (start + 3 > end) {
return 0; /* too small */
}
if (!(((zend_uchar)start[1] ^ 0x80) < 0x40 && ((zend_uchar)start[2] ^ 0x80) < 0x40 &&
(c >= 0xE1 || (zend_uchar)start[1] >= 0xA0))) {
return 0; /* invalid utf8 character */
}
return 3;
}
return 0;
}
static uint check_mb_utf8_valid(const char *start, const char *end)
{
uint len = check_mb_utf8_sequence(start, end);
return (len > 1)? len:0;
}
static uint mysqlnd_mbcharlen_utf8(uint utf8)
{
if (utf8 < 0x80) {
return 1; /* single byte character */
}
if (utf8 < 0xC2) {
return 0; /* invalid multibyte header */
}
if (utf8 < 0xE0) {
return 2; /* double byte character */
}
if (utf8 < 0xF0) {
return 3; /* triple byte character */
}
/* We still don't support characters out of the BMP */
return 0;
}
/* }}} */
/* {{{ big5 functions */
#define valid_big5head(c) (0xA1 <= (uint)(c) && (uint)(c) <= 0xF9)
#define valid_big5tail(c) ((0x40 <= (uint)(c) && (uint)(c) <= 0x7E) || \
(0xA1 <= (uint)(c) && (uint)(c) <= 0xFE))
#define isbig5code(c,d) (isbig5head(c) && isbig5tail(d))
static uint check_mb_big5(const char *start, const char *end)
{
return (valid_big5head(*(start)) && (end - start) > 1 && valid_big5tail(*(start + 1)) ? 2 : 0);
}
static uint mysqlnd_mbcharlen_big5(uint big5)
{
return (valid_big5head(big5)) ? 2 : 1;
}
/* }}} */
/* {{{ cp932 functions */
#define valid_cp932head(c) ((0x81 <= (c) && (c) <= 0x9F) || (0xE0 <= (c) && c <= 0xFC))
#define valid_cp932tail(c) ((0x40 <= (c) && (c) <= 0x7E) || (0x80 <= (c) && c <= 0xFC))
static uint check_mb_cp932(const char *start, const char *end)
{
return (valid_cp932head((zend_uchar)start[0]) && (end - start > 1) &&
valid_cp932tail((zend_uchar)start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_cp932(uint cp932)
{
return (valid_cp932head((zend_uchar)cp932)) ? 2 : 1;
}
/* }}} */
/* {{{ euckr functions */
#define valid_euckr(c) ((0xA1 <= (zend_uchar)(c) && (zend_uchar)(c) <= 0xFE))
static uint check_mb_euckr(const char *start, const char *end)
{
if (end - start <= 1) {
return 0; /* invalid length */
}
if (*(zend_uchar *)start < 0x80) {
return 0; /* invalid euckr character */
}
if (valid_euckr(start[1])) {
return 2;
}
return 0;
}
static uint mysqlnd_mbcharlen_euckr(uint kr)
{
return (valid_euckr(kr)) ? 2 : 1;
}
/* }}} */
/* {{{ eucjpms functions */
#define valid_eucjpms(c) (((c) & 0xFF) >= 0xA1 && ((c) & 0xFF) <= 0xFE)
#define valid_eucjpms_kata(c) (((c) & 0xFF) >= 0xA1 && ((c) & 0xFF) <= 0xDF)
#define valid_eucjpms_ss2(c) (((c) & 0xFF) == 0x8E)
#define valid_eucjpms_ss3(c) (((c) & 0xFF) == 0x8F)
static uint check_mb_eucjpms(const char *start, const char *end)
{
if (*((zend_uchar *)start) < 0x80) {
return 0; /* invalid eucjpms character */
}
if (valid_eucjpms(start[0]) && (end - start) > 1 && valid_eucjpms(start[1])) {
return 2;
}
if (valid_eucjpms_ss2(start[0]) && (end - start) > 1 && valid_eucjpms_kata(start[1])) {
return 2;
}
if (valid_eucjpms_ss3(start[0]) && (end - start) > 2 && valid_eucjpms(start[1]) &&
valid_eucjpms(start[2])) {
return 2;
}
return 0;
}
static uint mysqlnd_mbcharlen_eucjpms(uint jpms)
{
if (valid_eucjpms(jpms) || valid_eucjpms_ss2(jpms)) {
return 2;
}
if (valid_eucjpms_ss3(jpms)) {
return 3;
}
return 1;
}
/* }}} */
/* {{{ gb2312 functions */
#define valid_gb2312_head(c) (0xA1 <= (zend_uchar)(c) && (zend_uchar)(c) <= 0xF7)
#define valid_gb2312_tail(c) (0xA1 <= (zend_uchar)(c) && (zend_uchar)(c) <= 0xFE)
static uint check_mb_gb2312(const char *start, const char *end)
{
return (valid_gb2312_head((uint)start[0]) && end - start > 1 &&
valid_gb2312_tail((uint)start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_gb2312(uint gb)
{
return (valid_gb2312_head(gb)) ? 2 : 1;
}
/* }}} */
/* {{{ gbk functions */
#define valid_gbk_head(c) (0x81<=(zend_uchar)(c) && (zend_uchar)(c)<=0xFE)
#define valid_gbk_tail(c) ((0x40<=(zend_uchar)(c) && (zend_uchar)(c)<=0x7E) || (0x80<=(zend_uchar)(c) && (zend_uchar)(c)<=0xFE))
static uint check_mb_gbk(const char *start, const char *end)
{
return (valid_gbk_head(start[0]) && (end) - (start) > 1 && valid_gbk_tail(start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_gbk(uint gbk)
{
return (valid_gbk_head(gbk) ? 2 : 1);
}
/* }}} */
/* {{{ sjis functions */
#define valid_sjis_head(c) ((0x81 <= (c) && (c) <= 0x9F) && \
(0xE0 <= (c) && (c) <= 0xFC))
#define valid_sjis_tail(c) ((0x40 <= (c) && (c) <= 0x7E) && \
(0x80 <= (c) && (c) <= 0x7C))
static uint check_mb_sjis(const char *start, const char *end)
{
return (valid_sjis_head((zend_uchar)start[0]) && (end - start) > 1 && valid_sjis_tail((zend_uchar)start[1])) ? 2 : 0;
}
static uint mysqlnd_mbcharlen_sjis(uint sjis)
{
return (valid_sjis_head((zend_uchar)sjis)) ? 2 : 1;
}
/* }}} */
/* {{{ ucs2 functions */
static uint check_mb_ucs2(const char *start __attribute((unused)), const char *end __attribute((unused)))
{
return 2; /* always 2 */
}
static uint mysqlnd_mbcharlen_ucs2(uint ucs2 __attribute((unused)))
{
return 2; /* always 2 */
}
/* }}} */
/* {{{ ujis functions */
#define valid_ujis(c) ((0xA1 <= ((c)&0xFF) && ((c)&0xFF) <= 0xFE))
#define valid_ujis_kata(c) ((0xA1 <= ((c)&0xFF) && ((c)&0xFF) <= 0xDF))
#define valid_ujis_ss2(c) (((c)&0xFF) == 0x8E)
#define valid_ujis_ss3(c) (((c)&0xFF) == 0x8F)
static uint check_mb_ujis(const char *start, const char *end)
{
if (*(uchar*)start < 0x80) {
return 0; /* invalid ujis character */
}
if (valid_ujis(*(start)) && valid_ujis(*((start)+1))) {
return 2;
}
if (valid_ujis_ss2(*(start)) && valid_ujis_kata(*((start)+1))) {
return 2;
}
if (valid_ujis_ss3(*(start)) && (end-start) > 2 && valid_ujis(*((start)+1)) && valid_ujis(*((start)+2))) {
return 3;
}
return 0;
}
static uint mysqlnd_mbcharlen_ujis(uint ujis)
{
return (valid_ujis(ujis)? 2: valid_ujis_ss2(ujis)? 2: valid_ujis_ss3(ujis)? 3: 1);
}
/* }}} */
/* {{{ mysqlnd_charsets */
const MYSQLND_CHARSET mysqlnd_charsets[] =
{
{ 1, "big5","big5_chinese_ci", 1, 2, 0, mysqlnd_mbcharlen_big5, check_mb_big5},
{ 3, "dec8", "dec8_swedisch_ci", 1, 1, 0, NULL, NULL},
{ 4, "cp850", "cp850_general_ci", 1, 1, 0, NULL, NULL},
{ 6, "hp8", "hp8_english_ci", 1, 1, 0, NULL, NULL},
{ 7, "koi8r", "koi8r_general_ci", 1, 1, 0, NULL, NULL},
{ 8, "latin1", "latin1_swedish_ci", 1, 1, 0, NULL, NULL},
{ 9, "latin2", "latin2_general_ci", 1, 1, 0, NULL, NULL},
{ 10, "swe7", "swe7_swedish_ci", 1, 1, 0, NULL, NULL},
{ 11, "ascii", "ascii_general_ci", 1, 1, 0, NULL, NULL},
{ 12, "ujis", "ujis_japanese_ci", 1, 3, 0, mysqlnd_mbcharlen_ujis, check_mb_ujis},
{ 13, "sjis", "sjis_japanese_ci", 1, 2, 0, mysqlnd_mbcharlen_sjis, check_mb_sjis},
{ 16, "hebrew", "hebrew_general_ci", 1, 1, 0, NULL, NULL},
{ 18, "tis620", "tis620_thai_ci", 1, 1, 0, NULL, NULL},
{ 19, "euckr", "euckr_korean_ci", 1, 2, 0, mysqlnd_mbcharlen_euckr, check_mb_euckr},
{ 22, "koi8u", "koi8u_general_ci", 1, 1, 0, NULL, NULL},
{ 24, "gb2312", "gb2312_chinese_ci", 1, 2, 0, mysqlnd_mbcharlen_gb2312, check_mb_gb2312},
{ 25, "greek", "greek_general_ci", 1, 1, 0, NULL, NULL},
{ 26, "cp1250", "cp1250_general_ci", 1, 1, 0, NULL, NULL},
{ 28, "gbk", "gbk_chinese_ci", 1, 2, 0, mysqlnd_mbcharlen_gbk, check_mb_gbk},
{ 30, "latin5", "latin5_turkish_ci", 1, 1, 0, NULL, NULL},
{ 32, "armscii8", "armscii8_general_ci", 1, 1, 0, NULL, NULL},
{ 33, "utf8", "utf8_general_ci", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 35, "ucs2", "ucs2_general_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 36, "cp866", "cp866_general_ci", 1, 1, 0, NULL, NULL},
{ 37, "keybcs2", "keybcs2_general_ci", 1, 1, 0, NULL, NULL},
{ 38, "macce", "macce_general_ci", 1, 1, 0, NULL, NULL},
{ 39, "macroman", "macroman_general_ci", 1, 1, 0, NULL, NULL},
{ 40, "cp852", "cp852_general_ci", 1, 1, 0, NULL, NULL},
{ 41, "latin7", "latin7_general_ci", 1, 1, 0, NULL, NULL},
{ 51, "cp1251", "cp1251_general_ci", 1, 1, 0, NULL, NULL},
{ 57, "cp1256", "cp1256_general_ci", 1, 1, 0, NULL, NULL},
{ 59, "cp1257", "cp1257_general_ci", 1, 1, 0, NULL, NULL},
{ 63, "binary", "binary", 1, 1, 0, NULL, NULL},
{ 92, "geostd8", "geostd8_general_ci", 1, 1, 0, NULL, NULL},
{ 95, "cp932", "cp932_japanese_ci", 1, 2, 1, mysqlnd_mbcharlen_cp932, check_mb_cp932},
{ 97, "eucjpms", "eucjpms_japanese_ci", 1, 3, 0, mysqlnd_mbcharlen_eucjpms, check_mb_eucjpms},
{ 2, "latin2", "latin2_czech_cs", 1, 1, 0, NULL, NULL},
{ 5, "latin1", "latin1_german_ci", 1, 1, 0, NULL, NULL},
{ 14, "cp1251", "cp1251_bulgarian_ci", 1, 1, 0, NULL, NULL},
{ 15, "latin1", "latin1_danish_ci", 1, 1, 0, NULL, NULL},
{ 17, "filename", "filename", 1, 5, 1, NULL, NULL},
{ 20, "latin7", "latin7_estonian_cs", 1, 1, 0, NULL, NULL},
{ 21, "latin2", "latin2_hungarian_ci", 1, 1, 0, NULL, NULL},
{ 23, "cp1251", "cp1251_ukrainian_ci", 1, 1, 0, NULL, NULL},
{ 27, "latin2", "latin2_croatian_ci", 1, 1, 0, NULL, NULL},
{ 29, "cp1257", "cp1257_lithunian_ci", 1, 1, 0, NULL, NULL},
{ 31, "latin1", "latin1_german2_ci", 1, 1, 0, NULL, NULL},
{ 34, "cp1250", "cp1250_czech_cs", 1, 1, 0, NULL, NULL},
{ 42, "latin7", "latin7_general_cs", 1, 1, 0, NULL, NULL},
{ 43, "macce", "macce_bin", 1, 1, 0, NULL, NULL},
{ 44, "cp1250", "cp1250_croatian_ci", 1, 1, 0, NULL, NULL},
{ 47, "latin1", "latin1_bin", 1, 1, 0, NULL, NULL},
{ 48, "latin1", "latin1_general_ci", 1, 1, 0, NULL, NULL},
{ 49, "latin1", "latin1_general_cs", 1, 1, 0, NULL, NULL},
{ 50, "cp1251", "cp1251_bin", 1, 1, 0, NULL, NULL},
{ 52, "cp1251", "cp1251_general_cs", 1, 1, 0, NULL, NULL},
{ 53, "macroman", "macroman_bin", 1, 1, 0, NULL, NULL},
{ 58, "cp1257", "cp1257_bin", 1, 1, 0, NULL, NULL},
{ 60, "armascii8", "armascii8_bin", 1, 1, 0, NULL, NULL},
{ 65, "ascii", "ascii_bin", 1, 1, 0, NULL, NULL},
{ 66, "cp1250", "cp1250_bin", 1, 1, 0, NULL, NULL},
{ 67, "cp1256", "cp1256_bin", 1, 1, 0, NULL, NULL},
{ 68, "cp866", "cp866_bin", 1, 1, 0, NULL, NULL},
{ 69, "dec8", "dec8_bin", 1, 1, 0, NULL, NULL},
{ 70, "greek", "greek_bin", 1, 1, 0, NULL, NULL},
{ 71, "hebew", "hebrew_bin", 1, 1, 0, NULL, NULL},
{ 72, "hp8", "hp8_bin", 1, 1, 0, NULL, NULL},
{ 73, "keybcs2", "keybcs2_bin", 1, 1, 0, NULL, NULL},
{ 74, "koi8r", "koi8r_bin", 1, 1, 0, NULL, NULL},
{ 75, "koi8u", "koi8u_bin", 1, 1, 0, NULL, NULL},
{ 77, "latin2", "latin2_bin", 1, 1, 0, NULL, NULL},
{ 78, "latin5", "latin5_bin", 1, 1, 0, NULL, NULL},
{ 79, "latin7", "latin7_bin", 1, 1, 0, NULL, NULL},
{ 80, "cp850", "cp850_bin", 1, 1, 0, NULL, NULL},
{ 81, "cp852", "cp852_bin", 1, 1, 0, NULL, NULL},
{ 82, "swe7", "swe7_bin", 1, 1, 0, NULL, NULL},
{ 93, "geostd8", "geostd8_bin", 1, 1, 0, NULL, NULL},
{ 83, "utf8", "utf8_bin", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 84, "big5", "big5_bin", 1, 2, 0, mysqlnd_mbcharlen_big5, check_mb_big5},
{ 85, "euckr", "euckr_bin", 1, 2, 0, mysqlnd_mbcharlen_euckr, check_mb_euckr},
{ 86, "gb2312", "gb2312_bin", 1, 2, 0, mysqlnd_mbcharlen_gb2312, check_mb_gb2312},
{ 87, "gbk", "gbk_bin", 1, 2, 0, mysqlnd_mbcharlen_gbk, check_mb_gbk},
{ 88, "sjis", "sjis_bin", 1, 2, 0, mysqlnd_mbcharlen_sjis, check_mb_sjis},
{ 89, "tis620", "tis620_bin", 1, 1, 0, NULL, NULL},
{ 90, "ucs2", "ucs2_bin", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 91, "ujis", "ujis_bin", 1, 3, 0, mysqlnd_mbcharlen_ujis, check_mb_ujis},
{ 94, "latin1", "latin1_spanish_ci", 1, 1, 0, NULL, NULL},
{ 96, "cp932", "cp932_bin", 1, 2, 1, mysqlnd_mbcharlen_cp932, check_mb_cp932},
{ 99, "cp1250", "cp1250_polish_ci", 1, 1, 0, NULL, NULL},
{ 98, "eucjpms", "eucjpms_bin", 1, 3, 0, mysqlnd_mbcharlen_eucjpms, check_mb_eucjpms},
{ 128, "ucs2", "ucs2_unicode_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 129, "ucs2", "ucs2_icelandic_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 130, "ucs2", "ucs2_latvian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 131, "ucs2", "ucs2_romanian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 132, "ucs2", "ucs2_slovenian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 133, "ucs2", "ucs2_polish_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 134, "ucs2", "ucs2_estonian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 135, "ucs2", "ucs2_spanish_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 136, "ucs2", "ucs2_swedish_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 137, "ucs2", "ucs2_turkish_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 138, "ucs2", "ucs2_czech_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 139, "ucs2", "ucs2_danish_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 140, "ucs2", "ucs2_lithunian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 141, "ucs2", "ucs2_slovak_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 142, "ucs2", "ucs2_spanish2_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 143, "ucs2", "ucs2_roman_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 144, "ucs2", "ucs2_persian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 145, "ucs2", "ucs2_esperanto_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 146, "ucs2", "ucs2_hungarian_ci", 2, 2, 0, mysqlnd_mbcharlen_ucs2, check_mb_ucs2},
{ 192, "utf8", "utf8_general_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 193, "utf8", "utf8_icelandic_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 194, "utf8", "utf8_latvian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 195, "utf8", "utf8_romanian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 196, "utf8", "utf8_slovenian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 197, "utf8", "utf8_polish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 198, "utf8", "utf8_estonian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 119, "utf8", "utf8_spanish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 200, "utf8", "utf8_swedish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 201, "utf8", "utf8_turkish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 202, "utf8", "utf8_czech_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 203, "utf8", "utf8_danish_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid },
{ 204, "utf8", "utf8_lithunian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid },
{ 205, "utf8", "utf8_slovak_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 206, "utf8", "utf8_spanish2_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 207, "utf8", "utf8_roman_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 208, "utf8", "utf8_persian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 209, "utf8", "utf8_esperanto_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 210, "utf8", "utf8_hungarian_ci", 1, 3, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid},
{ 254, "utf8", "utf8_general_cs", 1, 2, 0, mysqlnd_mbcharlen_utf8, check_mb_utf8_valid },
{ 0, NULL, NULL, 0, 0, 0, NULL, NULL}
};
/* }}} */
/* {{{ mysqlnd_find_charset_nr */
PHPAPI const MYSQLND_CHARSET * mysqlnd_find_charset_nr(uint charsetnr)
{
const MYSQLND_CHARSET * c = mysqlnd_charsets;
do {
if (c->nr == charsetnr) {
return c;
}
++c;
} while (c[0].nr != 0);
return NULL;
}
/* }}} */
/* {{{ mysqlnd_find_charset_name */
PHPAPI const MYSQLND_CHARSET * mysqlnd_find_charset_name(const char * const name)
{
const MYSQLND_CHARSET *c = mysqlnd_charsets;
do {
if (!strcasecmp(c->name, name)) {
return c;
}
++c;
} while (c[0].nr != 0);
return NULL;
}
/* }}} */
/* {{{ mysqlnd_cset_escape_quotes */
PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const cset, char *newstr,
const char *escapestr, int escapestr_len TSRMLS_DC)
{
const char *newstr_s = newstr;
const char *newstr_e = newstr + 2 * escapestr_len;
const char *end = escapestr + escapestr_len;
zend_bool escape_overflow = FALSE;
DBG_ENTER("mysqlnd_cset_escape_quotes");
for (;escapestr < end; escapestr++) {
uint len = 0;
/* check unicode characters */
if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
/* check possible overflow */
if ((newstr + len) > newstr_e) {
escape_overflow = TRUE;
break;
}
/* copy mb char without escaping it */
while (len--) {
*newstr++ = *escapestr++;
}
escapestr--;
continue;
}
if (*escapestr == '\'') {
if (newstr + 2 > newstr_e) {
escape_overflow = TRUE;
break;
}
*newstr++ = '\'';
*newstr++ = '\'';
} else {
if (newstr + 1 > newstr_e) {
escape_overflow = TRUE;
break;
}
*newstr++ = *escapestr;
}
}
*newstr = '\0';
if (escape_overflow) {
DBG_RETURN((ulong)~0);
}
DBG_RETURN((ulong)(newstr - newstr_s));
}
/* }}} */
/* {{{ mysqlnd_cset_escape_slashes */
PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr,
const char *escapestr, int escapestr_len TSRMLS_DC)
{
const char *newstr_s = newstr;
const char *newstr_e = newstr + 2 * escapestr_len;
const char *end = escapestr + escapestr_len;
zend_bool escape_overflow = FALSE;
DBG_ENTER("mysqlnd_cset_escape_slashes");
for (;escapestr < end; escapestr++) {
char esc = '\0';
uint len = 0;
/* check unicode characters */
if (cset->char_maxlen > 1 && (len = cset->mb_valid(escapestr, end))) {
/* check possible overflow */
if ((newstr + len) > newstr_e) {
escape_overflow = TRUE;
break;
}
/* copy mb char without escaping it */
while (len--) {
*newstr++ = *escapestr++;
}
escapestr--;
continue;
}
if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
esc = *escapestr;
} else {
switch (*escapestr) {
case 0:
esc = '0';
break;
case '\n':
esc = 'n';
break;
case '\r':
esc = 'r';
break;
case '\\':
case '\'':
case '"':
esc = *escapestr;
break;
case '\032':
esc = 'Z';
break;
}
}
if (esc) {
if (newstr + 2 > newstr_e) {
escape_overflow = TRUE;
break;
}
/* copy escaped character */
*newstr++ = '\\';
*newstr++ = esc;
} else {
if (newstr + 1 > newstr_e) {
escape_overflow = TRUE;
break;
}
/* copy non escaped character */
*newstr++ = *escapestr;
}
}
*newstr = '\0';
if (escape_overflow) {
DBG_RETURN((ulong)~0);
}
DBG_RETURN((ulong)(newstr - newstr_s));
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,35 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
PHPAPI ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char *newstr,
const char *escapestr, int escapestr_len TSRMLS_DC);
PHPAPI ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr,
const char *escapestr, int escapestr_len TSRMLS_DC);
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

1345
ext/mysqlnd/mysqlnd_debug.c Normal file

File diff suppressed because it is too large Load Diff

145
ext/mysqlnd/mysqlnd_debug.h Normal file
View File

@ -0,0 +1,145 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_DEBUG_H
#define MYSQLND_DEBUG_H
#include "zend_stack.h"
#define MYSQLND_DEBUG_MEMORY 1
struct st_mysqlnd_debug_methods
{
enum_func_status (*open)(MYSQLND_DEBUG *self, zend_bool reopen);
void (*set_mode)(MYSQLND_DEBUG *self, const char * const mode);
enum_func_status (*log)(MYSQLND_DEBUG *self, unsigned int line, const char * const file,
unsigned int level, const char * type, const char *message);
enum_func_status (*log_va)(MYSQLND_DEBUG *self, unsigned int line, const char * const file,
unsigned int level, const char * type, const char *format, ...);
zend_bool (*func_enter)(MYSQLND_DEBUG *self, unsigned int line, const char * const file,
char * func_name, uint func_name_len);
enum_func_status (*func_leave)(MYSQLND_DEBUG *self, unsigned int line, const char * const file);
enum_func_status (*close)(MYSQLND_DEBUG *self);
enum_func_status (*free)(MYSQLND_DEBUG *self);
};
struct st_mysqlnd_debug
{
php_stream *stream;
#ifdef ZTS
TSRMLS_D;
#endif
unsigned int flags;
unsigned int nest_level_limit;
int pid;
char * file_name;
zend_stack call_stack;
HashTable not_filtered_functions;
struct st_mysqlnd_debug_methods *m;
};
MYSQLND_DEBUG *mysqlnd_debug_init(TSRMLS_D);
#define MYSQLND_MEM_D TSRMLS_DC ZEND_FILE_LINE_DC ZEND_FILE_LINE_ORIG_DC
void * _mysqlnd_emalloc(size_t size MYSQLND_MEM_D);
void * _mysqlnd_pemalloc(size_t size, zend_bool persistent MYSQLND_MEM_D);
void * _mysqlnd_ecalloc(uint nmemb, size_t size MYSQLND_MEM_D);
void * _mysqlnd_pecalloc(uint nmemb, size_t size, zend_bool persistent MYSQLND_MEM_D);
void * _mysqlnd_erealloc(void *ptr, size_t new_size MYSQLND_MEM_D);
void * _mysqlnd_perealloc(void *ptr, size_t new_size, zend_bool persistent MYSQLND_MEM_D);
void _mysqlnd_efree(void *ptr MYSQLND_MEM_D);
void _mysqlnd_pefree(void *ptr, zend_bool persistent MYSQLND_MEM_D);
void * _mysqlnd_malloc(size_t size MYSQLND_MEM_D);
void * _mysqlnd_calloc(uint nmemb, size_t size MYSQLND_MEM_D);
void * _mysqlnd_realloc(void *ptr, size_t new_size MYSQLND_MEM_D);
void _mysqlnd_free(void *ptr MYSQLND_MEM_D);
char * mysqlnd_get_backtrace(TSRMLS_D);
#if PHP_DEBUG && !defined(PHP_WIN32)
#define DBG_INF(msg) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "info : ", (msg)); } while (0)
#define DBG_ERR(msg) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "error: ", (msg)); } while (0)
#define DBG_INF_FMT(...) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log_va(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "info : ", __VA_ARGS__); } while (0)
#define DBG_ERR_FMT(...) do { if (dbg_skip_trace == FALSE) MYSQLND_G(dbg)->m->log_va(MYSQLND_G(dbg), __LINE__, __FILE__, -1, "error: ", __VA_ARGS__); } while (0)
#define DBG_ENTER(func_name) zend_bool dbg_skip_trace = TRUE; if (MYSQLND_G(dbg)) dbg_skip_trace = !MYSQLND_G(dbg)->m->func_enter(MYSQLND_G(dbg), __LINE__, __FILE__, func_name, strlen(func_name));
#define DBG_RETURN(value) do { if (MYSQLND_G(dbg)) MYSQLND_G(dbg)->m->func_leave(MYSQLND_G(dbg), __LINE__, __FILE__); return (value); } while (0)
#define DBG_VOID_RETURN do { if (MYSQLND_G(dbg)) MYSQLND_G(dbg)->m->func_leave(MYSQLND_G(dbg), __LINE__, __FILE__); return; } while (0)
#else
static inline void DBG_INF(char *msg) {}
static inline void DBG_ERR(char *msg) {}
static inline void DBG_INF_FMT(char *format, ...) {}
static inline void DBG_ERR_FMT(char *format, ...) {}
static inline void DBG_ENTER(char *func_name) {}
#define DBG_RETURN(value) return (value)
#define DBG_VOID_RETURN return;
#endif
#if MYSQLND_DEBUG_MEMORY
#define mnd_emalloc(size) _mysqlnd_emalloc((size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_pemalloc(size, pers) _mysqlnd_pemalloc((size), (pers) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_ecalloc(nmemb, size) _mysqlnd_ecalloc((nmemb), (size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_pecalloc(nmemb, size, p) _mysqlnd_pecalloc((nmemb), (size), (p) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_erealloc(ptr, new_size) _mysqlnd_erealloc((ptr), (new_size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_perealloc(ptr, new_size, p) _mysqlnd_perealloc((ptr), (new_size), (p) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_efree(ptr) _mysqlnd_efree((ptr) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_pefree(ptr, pers) _mysqlnd_pefree((ptr), (pers) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_malloc(size) _mysqlnd_malloc((size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_calloc(nmemb, size) _mysqlnd_calloc((nmemb), (size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_realloc(ptr, new_size) _mysqlnd_realloc((ptr), (new_size) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#define mnd_free(ptr) _mysqlnd_free((ptr) TSRMLS_CC ZEND_FILE_LINE_CC ZEND_FILE_LINE_EMPTY_CC)
#else
#define mnd_emalloc(size) emalloc((size))
#define mnd_pemalloc(size, pers) pemalloc((size), (pers))
#define mnd_ecalloc(nmemb, size) ecalloc((nmemb), (size))
#define mnd_pecalloc(nmemb, size, p) pecalloc((nmemb), (size), (p))
#define mnd_erealloc(ptr, new_size) erealloc((ptr), (new_size))
#define mnd_perealloc(ptr, new_size, p) perealloc((ptr), (new_size), (p))
#define mnd_efree(ptr) efree((ptr))
#define mnd_pefree(ptr, pers) pefree((ptr), (pers))
#define mnd_malloc(size) malloc((size))
#define mnd_calloc(nmemb, size) calloc((nmemb), (size))
#define mnd_realloc(ptr, new_size) realloc((ptr), (new_size))
#define mnd_free(ptr) free((ptr))
#endif
#endif /* MYSQLND_DEBUG_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,367 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_ENUM_N_DEF_H
#define MYSQLND_ENUM_N_DEF_H
#define MYSQLND_ERRMSG_SIZE 512
#define MYSQLND_SQLSTATE_LENGTH 5
#define MYSQLND_SQLSTATE_NULL "00000"
#define MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED 16
#define MYSQLND_SERVER_QUERY_NO_INDEX_USED 32
#define MYSQLND_NO_DATA 100
#define MYSQLND_DATA_TRUNCATED 101
#define SHA1_MAX_LENGTH 20
#define SCRAMBLE_LENGTH 20
#define SCRAMBLE_LENGTH_323 8
#define CLIENT_LONG_PASSWORD 1 /* new more secure passwords */
#define CLIENT_FOUND_ROWS 2 /* Found instead of affected rows */
#define CLIENT_LONG_FLAG 4 /* Get all column flags */
#define CLIENT_CONNECT_WITH_DB 8 /* One can specify db on connect */
#define CLIENT_NO_SCHEMA 16 /* Don't allow database.table.column */
#define CLIENT_COMPRESS 32 /* Can use compression protocol */
#define CLIENT_ODBC 64 /* Odbc client */
#define CLIENT_LOCAL_FILES 128 /* Can use LOAD DATA LOCAL */
#define CLIENT_IGNORE_SPACE 256 /* Ignore spaces before '(' */
#define CLIENT_PROTOCOL_41 512 /* New 4.1 protocol */
#define CLIENT_INTERACTIVE 1024 /* This is an interactive client */
#define CLIENT_SSL 2048 /* Switch to SSL after handshake */
#define CLIENT_IGNORE_SIGPIPE 4096 /* IGNORE sigpipes */
#define CLIENT_TRANSACTIONS 8192 /* Client knows about transactions */
#define CLIENT_RESERVED 16384 /* Old flag for 4.1 protocol */
#define CLIENT_SECURE_CONNECTION 32768 /* New 4.1 authentication */
#define CLIENT_MULTI_STATEMENTS (1UL << 16) /* Enable/disable multi-stmt support */
#define CLIENT_MULTI_RESULTS (1UL << 17) /* Enable/disable multi-results */
typedef enum mysqlnd_extension
{
MYSQLND_MYSQL = 0,
MYSQLND_MYSQLI,
} enum_mysqlnd_extension;
enum
{
MYSQLND_FETCH_ASSOC = 1,
MYSQLND_FETCH_NUM = 2,
MYSQLND_FETCH_BOTH = 1|2,
};
/* Follow libmysql convention */
typedef enum func_status
{
PASS = 0,
FAIL = 1,
} enum_func_status;
typedef enum mysqlnd_query_type
{
QUERY_UPSERT,
QUERY_SELECT,
QUERY_LOAD_LOCAL
} enum_mysqlnd_query_type;
typedef enum mysqlnd_res_type
{
MYSQLND_RES_NORMAL = 1,
MYSQLND_RES_PS_BUF,
MYSQLND_RES_PS_UNBUF
} enum_mysqlnd_res_type;
typedef enum mysqlnd_option
{
MYSQL_OPT_CONNECT_TIMEOUT,
MYSQL_OPT_COMPRESS,
MYSQL_OPT_NAMED_PIPE,
MYSQL_INIT_COMMAND,
MYSQL_READ_DEFAULT_FILE,
MYSQL_READ_DEFAULT_GROUP,
MYSQL_SET_CHARSET_DIR,
MYSQL_SET_CHARSET_NAME,
MYSQL_OPT_LOCAL_INFILE,
MYSQL_OPT_PROTOCOL,
MYSQL_SHARED_MEMORY_BASE_NAME,
MYSQL_OPT_READ_TIMEOUT,
MYSQL_OPT_WRITE_TIMEOUT,
MYSQL_OPT_USE_RESULT,
MYSQL_OPT_USE_REMOTE_CONNECTION,
MYSQL_OPT_USE_EMBEDDED_CONNECTION,
MYSQL_OPT_GUESS_CONNECTION,
MYSQL_SET_CLIENT_IP,
MYSQL_SECURE_AUTH,
MYSQL_REPORT_DATA_TRUNCATION,
MYSQL_OPT_RECONNECT,
MYSQL_OPT_SSL_VERIFY_SERVER_CERT,
#if PHP_MAJOR_VERSION >= 6
MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE = 200,
#endif
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
MYSQLND_OPT_INT_AND_YEAR_AS_INT = 201,
#endif
MYSQLND_OPT_NET_CMD_BUFFER_SIZE = 202,
MYSQLND_OPT_NET_READ_BUFFER_SIZE = 203,
} enum_mysqlnd_option;
typedef enum mysqlnd_field_types
{
MYSQL_TYPE_DECIMAL,
MYSQL_TYPE_TINY,
MYSQL_TYPE_SHORT,
MYSQL_TYPE_LONG,
MYSQL_TYPE_FLOAT,
MYSQL_TYPE_DOUBLE,
MYSQL_TYPE_NULL,
MYSQL_TYPE_TIMESTAMP,
MYSQL_TYPE_LONGLONG,
MYSQL_TYPE_INT24,
MYSQL_TYPE_DATE,
MYSQL_TYPE_TIME,
MYSQL_TYPE_DATETIME,
MYSQL_TYPE_YEAR,
MYSQL_TYPE_NEWDATE,
MYSQL_TYPE_VARCHAR,
MYSQL_TYPE_BIT,
MYSQL_TYPE_NEWDECIMAL=246,
MYSQL_TYPE_ENUM=247,
MYSQL_TYPE_SET=248,
MYSQL_TYPE_TINY_BLOB=249,
MYSQL_TYPE_MEDIUM_BLOB=250,
MYSQL_TYPE_LONG_BLOB=251,
MYSQL_TYPE_BLOB=252,
MYSQL_TYPE_VAR_STRING=253,
MYSQL_TYPE_STRING=254,
MYSQL_TYPE_GEOMETRY=255
} enum_mysqlnd_field_types;
/* Please update this if there is a new type after MYSQL_TYPE_GEOMETRY */
#define MYSQL_TYPE_LAST MYSQL_TYPE_GEOMETRY
typedef enum mysqlnd_server_option
{
MYSQL_OPTION_MULTI_STATEMENTS_ON,
MYSQL_OPTION_MULTI_STATEMENTS_OFF
} enum_mysqlnd_server_option;
#define FIELD_TYPE_DECIMAL MYSQL_TYPE_DECIMAL
#define FIELD_TYPE_NEWDECIMAL MYSQL_TYPE_NEWDECIMAL
#define FIELD_TYPE_TINY MYSQL_TYPE_TINY
#define FIELD_TYPE_SHORT MYSQL_TYPE_SHORT
#define FIELD_TYPE_LONG MYSQL_TYPE_LONG
#define FIELD_TYPE_FLOAT MYSQL_TYPE_FLOAT
#define FIELD_TYPE_DOUBLE MYSQL_TYPE_DOUBLE
#define FIELD_TYPE_NULL MYSQL_TYPE_NULL
#define FIELD_TYPE_TIMESTAMP MYSQL_TYPE_TIMESTAMP
#define FIELD_TYPE_LONGLONG MYSQL_TYPE_LONGLONG
#define FIELD_TYPE_INT24 MYSQL_TYPE_INT24
#define FIELD_TYPE_DATE MYSQL_TYPE_DATE
#define FIELD_TYPE_TIME MYSQL_TYPE_TIME
#define FIELD_TYPE_DATETIME MYSQL_TYPE_DATETIME
#define FIELD_TYPE_YEAR MYSQL_TYPE_YEAR
#define FIELD_TYPE_NEWDATE MYSQL_TYPE_NEWDATE
#define FIELD_TYPE_ENUM MYSQL_TYPE_ENUM
#define FIELD_TYPE_SET MYSQL_TYPE_SET
#define FIELD_TYPE_TINY_BLOB MYSQL_TYPE_TINY_BLOB
#define FIELD_TYPE_MEDIUM_BLOB MYSQL_TYPE_MEDIUM_BLOB
#define FIELD_TYPE_LONG_BLOB MYSQL_TYPE_LONG_BLOB
#define FIELD_TYPE_BLOB MYSQL_TYPE_BLOB
#define FIELD_TYPE_VAR_STRING MYSQL_TYPE_VAR_STRING
#define FIELD_TYPE_STRING MYSQL_TYPE_STRING
#define FIELD_TYPE_CHAR MYSQL_TYPE_TINY
#define FIELD_TYPE_INTERVAL MYSQL_TYPE_ENUM
#define FIELD_TYPE_GEOMETRY MYSQL_TYPE_GEOMETRY
#define FIELD_TYPE_BIT MYSQL_TYPE_BIT
#define NOT_NULL_FLAG 1
#define PRI_KEY_FLAG 2
#define UNIQUE_KEY_FLAG 4
#define MULTIPLE_KEY_FLAG 8
#define BLOB_FLAG 16
#define UNSIGNED_FLAG 32
#define ZEROFILL_FLAG 64
#define BINARY_FLAG 128
#define ENUM_FLAG 256
#define AUTO_INCREMENT_FLAG 512
#define TIMESTAMP_FLAG 1024
#define SET_FLAG 2048
#define NO_DEFAULT_VALUE_FLAG 4096
#define PART_KEY_FLAG 16384
#define GROUP_FLAG 32768
#define NUM_FLAG 32768
#define IS_PRI_KEY(n) ((n) & PRI_KEY_FLAG)
#define IS_NOT_NULL(n) ((n) & NOT_NULL_FLAG)
#define IS_BLOB(n) ((n) & BLOB_FLAG)
#define IS_NUM(t) ((t) <= FIELD_TYPE_INT24 || (t) == FIELD_TYPE_YEAR || (t) == FIELD_TYPE_NEWDECIMAL)
/* see mysqlnd_charset.c for more information */
#define MYSQLND_BINARY_CHARSET_NR 63
/*
/-----> CONN_CLOSE <---------------\
| ^ \
| | \
CONN_READY -> CONN_QUERY_SENT -> CONN_FETCHING_DATA
^ |
\-------------------------------------/
*/
typedef enum mysqlnd_connection_state
{
CONN_ALLOCED = 0,
CONN_READY,
CONN_QUERY_SENT,
CONN_SENDING_LOAD_DATA,
CONN_FETCHING_DATA,
CONN_NEXT_RESULT_PENDING,
CONN_QUIT_SENT, /* object is "destroyed" at this stage */
} enum_mysqlnd_connection_state;
typedef enum mysqlnd_stmt_state
{
MYSQLND_STMT_INITTED = 0,
MYSQLND_STMT_PREPARED,
MYSQLND_STMT_EXECUTED,
MYSQLND_STMT_WAITING_USE_OR_STORE,
MYSQLND_STMT_USE_OR_STORE_CALLED,
MYSQLND_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */
} enum_mysqlnd_stmt_state;
typedef enum param_bind_flags
{
MYSQLND_PARAM_BIND_BLOB_USED = 1
} enum_param_bind_flags;
/* PS */
enum mysqlnd_stmt_attr
{
STMT_ATTR_UPDATE_MAX_LENGTH,
STMT_ATTR_CURSOR_TYPE,
STMT_ATTR_PREFETCH_ROWS
};
enum myslqnd_cursor_type
{
CURSOR_TYPE_NO_CURSOR= 0,
CURSOR_TYPE_READ_ONLY= 1,
CURSOR_TYPE_FOR_UPDATE= 2,
CURSOR_TYPE_SCROLLABLE= 4
};
typedef enum mysqlnd_connection_close_type
{
MYSQLND_CLOSE_EXPLICIT = 0,
MYSQLND_CLOSE_IMPLICIT,
MYSQLND_CLOSE_DISCONNECTED,
MYSQLND_CLOSE_LAST /* for checking, should always be last */
} enum_connection_close_type;
typedef enum mysqlnd_collected_stats
{
STAT_BYTES_SENT,
STAT_BYTES_RECEIVED,
STAT_PACKETS_SENT,
STAT_PACKETS_RECEIVED,
STAT_PROTOCOL_OVERHEAD_IN,
STAT_PROTOCOL_OVERHEAD_OUT,
STAT_RSET_QUERY,
STAT_NON_RSET_QUERY,
STAT_NO_INDEX_USED,
STAT_BAD_INDEX_USED,
STAT_BUFFERED_SETS,
STAT_UNBUFFERED_SETS,
STAT_PS_BUFFERED_SETS,
STAT_PS_UNBUFFERED_SETS,
STAT_FLUSHED_NORMAL_SETS,
STAT_FLUSHED_PS_SETS,
STAT_PS_PREPARED_NEVER_EXECUTED,
STAT_PS_PREPARED_ONCE_USED,
STAT_ROWS_FETCHED_FROM_SERVER_NORMAL,
STAT_ROWS_FETCHED_FROM_SERVER_PS,
STAT_ROWS_BUFFERED_FROM_CLIENT_NORMAL,
STAT_ROWS_BUFFERED_FROM_CLIENT_PS,
STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_BUF,
STAT_ROWS_FETCHED_FROM_CLIENT_NORMAL_UNBUF,
STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF,
STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF,
STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR,
STAT_ROWS_SKIPPED_NORMAL,
STAT_ROWS_SKIPPED_PS,
STAT_COPY_ON_WRITE_SAVED,
STAT_COPY_ON_WRITE_PERFORMED,
STAT_CMD_BUFFER_TOO_SMALL,
STAT_CONNECT_SUCCESS,
STAT_CONNECT_FAILURE,
STAT_CONNECT_REUSED,
STAT_RECONNECT,
STAT_PCONNECT_SUCCESS,
STAT_OPENED_CONNECTIONS,
STAT_OPENED_PERSISTENT_CONNECTIONS,
STAT_CLOSE_EXPLICIT,
STAT_CLOSE_IMPLICIT,
STAT_CLOSE_DISCONNECT,
STAT_CLOSE_IN_MIDDLE,
STAT_FREE_RESULT_EXPLICIT,
STAT_FREE_RESULT_IMPLICIT,
STAT_STMT_CLOSE_EXPLICIT,
STAT_STMT_CLOSE_IMPLICIT,
STAT_MEM_EMALLOC_COUNT,
STAT_MEM_EMALLOC_AMMOUNT,
STAT_MEM_ECALLOC_COUNT,
STAT_MEM_ECALLOC_AMMOUNT,
STAT_MEM_EREALLOC_COUNT,
STAT_MEM_EREALLOC_AMMOUNT,
STAT_MEM_EFREE_COUNT,
STAT_MEM_MALLOC_COUNT,
STAT_MEM_MALLOC_AMMOUNT,
STAT_MEM_CALLOC_COUNT,
STAT_MEM_CALLOC_AMMOUNT,
STAT_MEM_REALLOC_COUNT,
STAT_MEM_REALLOC_AMMOUNT,
STAT_MEM_FREE_COUNT,
STAT_LAST /* Should be always the last */
} enum_mysqlnd_collected_stats;
#define MYSQLND_DEFAULT_PREFETCH_ROWS (ulong) 1
#endif /* MYSQLND_ENUM_N_DEF_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,121 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
#ifndef MYSQLND_LIBMYSQL_COMPAT_H
#define MYSQLND_LIBMYSQL_COMPAT_H
/* Global types and definitions*/
#define MYSQL_NO_DATA MYSQLND_NO_DATA
#define MYSQL_DATA_TRUNCATED MYSQLND_DATA_TRUNCATED
#define MYSQL_STMT MYSQLND_STMT
#define MYSQL_FIELD MYSQLND_FIELD
#define MYSQL_RES MYSQLND_RES
#define MYSQL_ROW MYSQLND_ROW
#define MYSQL MYSQLND
#define my_bool zend_bool
#define my_ulonglong mynd_ulonglong
#define MYSQL_VERSION_ID MYSQLND_VERSION_ID
#define MYSQL_SERVER_VERSION MYSQLND_VERSION
#define MYSQL_ERRMSG_SIZE MYSQLND_ERRMSG_SIZE
#define SQLSTATE_LENGTH MYSQLND_SQLSTATE_LENGTH
#define SERVER_QUERY_NO_GOOD_INDEX_USED MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED
#define SERVER_QUERY_NO_INDEX_USED MYSQLND_SERVER_QUERY_NO_INDEX_USED
/* functions */
#define mysql_affected_rows(r) mysqlnd_affected_rows((r))
#define mysql_autocommit(r,m) mysqlnd_autocommit((r),(m))
#define mysql_change_user(r,a,b,c) mysqlnd_change_user((r), (a), (b), (c))
#define mysql_character_set_name(c) mysqlnd_character_set_name((c))
#define mysql_close(r) mysqlnd_close((r), MYSQLND_CLOSE_EXPLICIT)
#define mysql_commit(r) mysqlnd_commit((r))
#define mysql_data_seek(r,o) mysqlnd_data_seek((r),(o))
#define mysql_debug(x) mysqlnd_debug((x))
#define mysql_dump_debug_info(r) mysqlnd_dump_debug_info((r))
#define mysql_errno(r) mysqlnd_errno((r))
#define mysql_error(r) mysqlnd_error((r))
#define mysql_escape_string(a,b,c) mysqlnd_escape_string((a), (b), (c))
#define mysql_fetch_field(r) mysqlnd_fetch_field((r))
#define mysql_fetch_field_direct(r,o) mysqlnd_fetch_field_direct((r), (o))
#define mysql_fetch_lengths(r) mysqlnd_fetch_lengths((r))
#define mysql_fetch_row(r) mysqlnd_fetch_row((r))
#define mysql_field_count(r) mysqlnd_field_count((r))
#define mysql_field_seek(r,o) mysqlnd_field_seek((r), (o))
#define mysql_field_tell(r) mysqlnd_field_tell((r))
#define mysql_init(a) mysqlnd_init((a))
#define mysql_insert_id(r) mysqlnd_insert_id((r))
#define mysql_kill(r,n) mysqlnd_kill((r), (n))
#define mysql_list_dbs(c, wild) mysqlnd_list_dbs((c), (wild))
#define mysql_list_fields(c, tab, wild) mysqlnd_list_fields((c), (tab), (wild))
#define mysql_list_processes(c) mysqlnd_list_processes((c))
#define mysql_list_tables(c, wild) mysqlnd_list_tables((c), (wild))
#define mysql_more_results(r) mysqlnd_more_results((r))
#define mysql_next_result(r) mysqlnd_next_result((r))
#define mysql_num_fields(r) mysqlnd_num_fields((r))
#define mysql_num_rows(r) mysqlnd_num_rows((r))
#define mysql_ping(r) mysqlnd_ping((r))
#define mysql_real_escape_string(r,a,b,c) mysqlnd_real_escape_string((r), (a), (b), (c))
#define mysql_real_query(r,a,b) mysqlnd_query((r), (a), (b))
#define mysql_rollback(r) mysqlnd_rollback((r))
#define mysql_select_db(r,a) mysqlnd_select_db((r), (a) ,strlen((a)))
#define mysql_set_server_option(r,o) mysqlnd_set_server_option((r), (o))
#define mysql_set_character_set(r,a) mysqlnd_set_character_set((r), (a))
#define mysql_sqlstate(r) mysqlnd_sqlstate((r))
#define mysql_stmt_affected_rows(s) mysqlnd_stmt_affected_rows((s))
#define mysql_stmt_field_count(s) mysqlnd_stmt_field_count((s))
#define mysql_stmt_param_count(s) mysqlnd_stmt_param_count((s))
#define mysql_stmt_num_rows(s) mysqlnd_stmt_num_rows((s))
#define mysql_stmt_insert_id(s) mysqlnd_stmt_insert_id((s))
#define mysql_stmt_close(s) mysqlnd_stmt_close((s))
#define mysql_stmt_errno(s) mysqlnd_stmt_errno((s))
#define mysql_stmt_error(s) mysqlnd_stmt_error((s))
#define mysql_stmt_sqlstate(s) mysqlnd_stmt_sqlstate((s))
#define mysql_stmt_prepare(s,q,l) mysqlnd_stmt_prepare((s), (q), (l))
#define mysql_stmt_execute(s) mysqlnd_stmt_execute((s))
#define mysql_stmt_reset(s) mysqlnd_stmt_reset((s))
#define mysql_stmt_store_result(s) mysqlnd_stmt_store_result((s))
#define mysql_stmt_free_result(s) mysqlnd_stmt_free_result((s))
#define mysql_stmt_data_seek(s,r) mysqlnd_stmt_data_seek((s), (r))
#define mysql_stmt_send_long_data(s,p,d,l) mysqlnd_stmt_send_long_data((s), (p), (d), (l))
#define mysql_stmt_attr_get(s,a,v) mysqlnd_stmt_attr_get((s), (a), (v))
#define mysql_stmt_attr_set(s,a,v) mysqlnd_stmt_attr_set((s), (a), (v))
#define mysql_stmt_param_metadata(s) mysqlnd_stmt_param_metadata((s))
#define mysql_stmt_result_metadata(s) mysqlnd_stmt_result_metadata((s))
#define mysql_thread_safe() mysqlnd_thread_safe()
#define mysql_info(r) mysqlnd_info((r))
#define mysql_options(r,a,b) mysqlnd_options((r), (a), (b))
#define mysql_stmt_init(r) mysqlnd_stmt_init((r))
#define mysql_free_result(r) mysqlnd_free_result((r), FALSE)
#define mysql_store_result(r) mysqlnd_store_result((r))
#define mysql_use_result(r) mysqlnd_use_result((r))
#define mysql_thread_id(r) mysqlnd_thread_id((r))
#define mysql_get_client_info() mysqlnd_get_client_info()
#define mysql_get_client_version() mysqlnd_get_client_version()
#define mysql_get_host_info(r) mysqlnd_get_host_info((r))
#define mysql_get_proto_info(r) mysqlnd_get_proto_info((r))
#define mysql_get_server_info(r) mysqlnd_get_server_info((r))
#define mysql_get_server_version(r) mysqlnd_get_server_version((r))
#define mysql_warning_count(r) mysqlnd_warning_count((r))
#define mysql_eof(r) (((r)->unbuf && (r)->unbuf->eof_reached) || (r)->data)
#endif /* MYSQLND_LIBMYSQL_COMPAT_H */

View File

@ -0,0 +1,263 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
#include "php.h"
#include "php_globals.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_debug.h"
enum_func_status mysqlnd_simple_command_handle_response(MYSQLND *conn,
enum php_mysql_packet_type ok_packet,
zend_bool silent, enum php_mysqlnd_server_command command
TSRMLS_DC);
#define ALLOC_CALLBACK_ARGS(a, b, c)\
if (c) {\
a = (zval ***)safe_emalloc(c, sizeof(zval **), 0);\
for (i = b; i < c; i++) {\
a[i] = mnd_emalloc(sizeof(zval *));\
MAKE_STD_ZVAL(*a[i]);\
}\
}
#define FREE_CALLBACK_ARGS(a, b, c)\
if (a) {\
for (i=b; i < c; i++) {\
zval_ptr_dtor(a[i]);\
mnd_efree(a[i]);\
}\
mnd_efree(a);\
}
/* {{{ mysqlnd_local_infile_init */
static
int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS_DC)
{
MYSQLND_INFILE_INFO *info;
php_stream_context *context = NULL;
DBG_ENTER("mysqlnd_local_infile_init");
*ptr= info= ((MYSQLND_INFILE_INFO *)mnd_ecalloc(1, sizeof(MYSQLND_INFILE_INFO)));
/* check open_basedir */
if (PG(open_basedir)) {
if (php_check_open_basedir_ex(filename, 0 TSRMLS_CC) == -1) {
strcpy(info->error_msg, "open_basedir restriction in effect. Unable to open file");
info->error_no = CR_UNKNOWN_ERROR;
DBG_RETURN(1);
}
}
info->filename = filename;
info->fd = php_stream_open_wrapper_ex((char *)filename, "r", 0, NULL, context);
if (info->fd == NULL) {
snprintf((char *)info->error_msg, sizeof(info->error_msg), "Can't find file '%-.64s'.", filename);
info->error_no = MYSQLND_EE_FILENOTFOUND;
DBG_RETURN(1);
}
DBG_RETURN(0);
}
/* }}} */
/* {{{ mysqlnd_local_infile_read */
static
int mysqlnd_local_infile_read(void *ptr, char *buf, uint buf_len TSRMLS_DC)
{
MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
int count;
DBG_ENTER("mysqlnd_local_infile_read");
count = (int)php_stream_read(info->fd, buf, buf_len);
if (count < 0) {
strcpy(info->error_msg, "Error reading file");
info->error_no = CR_UNKNOWN_ERROR;
}
DBG_RETURN(count);
}
/* }}} */
/* {{{ mysqlnd_local_infile_error */
static
int mysqlnd_local_infile_error(void *ptr, char *error_buf, uint error_buf_len TSRMLS_DC)
{
MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
DBG_ENTER("mysqlnd_local_infile_error");
if (info) {
strncpy(error_buf, info->error_msg, error_buf_len);
DBG_INF_FMT("have info, %d", info->error_no);
DBG_RETURN(info->error_no);
}
strncpy(error_buf, "Unknown error", error_buf_len);
DBG_INF_FMT("no info, %d", CR_UNKNOWN_ERROR);
DBG_RETURN(CR_UNKNOWN_ERROR);
}
/* }}} */
/* {{{ mysqlnd_local_infile_end */
static
void mysqlnd_local_infile_end(void *ptr TSRMLS_DC)
{
MYSQLND_INFILE_INFO *info = (MYSQLND_INFILE_INFO *)ptr;
if (info) {
/* php_stream_close segfaults on NULL */
if (info->fd) {
php_stream_close(info->fd);
info->fd = NULL;
}
mnd_efree(info);
}
}
/* }}} */
/* {{{ mysqlnd_local_infile_default */
PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn)
{
conn->infile.local_infile_init = mysqlnd_local_infile_init;
conn->infile.local_infile_read = mysqlnd_local_infile_read;
conn->infile.local_infile_error = mysqlnd_local_infile_error;
conn->infile.local_infile_end = mysqlnd_local_infile_end;
}
/* }}} */
/* {{{ mysqlnd_set_local_infile_handler */
PHPAPI void mysqlnd_set_local_infile_handler(MYSQLND * const conn, const char * const funcname)
{
if (!conn->infile.callback) {
MAKE_STD_ZVAL(conn->infile.callback);
} else {
zval_dtor(conn->infile.callback);
}
ZVAL_STRING(conn->infile.callback, (char*) funcname, 1);
}
/* }}} */
static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA of local file";
/* {{{ mysqlnd_handle_local_infile */
enum_func_status
mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC)
{
char *buf;
char empty_packet[MYSQLND_HEADER_SIZE];
enum_func_status result = FAIL;
uint buflen = 4096;
void *info = NULL;
int bufsize;
size_t ret;
MYSQLND_INFILE infile;
DBG_ENTER("mysqlnd_handle_local_infile");
if (!(conn->options.flags & CLIENT_LOCAL_FILES)) {
php_error_docref(NULL TSRMLS_CC, E_WARNING, "LOAD DATA LOCAL INFILE forbidden");
/* write empty packet to server */
ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC);
*is_warning = TRUE;
goto infile_error;
}
infile = conn->infile;
/* allocate buffer for reading data */
buf = (char *)mnd_ecalloc(1, buflen);
*is_warning = FALSE;
/* init handler: allocate read buffer and open file */
if (infile.local_infile_init(&info, (char *)filename, conn->infile.userdata TSRMLS_CC)) {
*is_warning = TRUE;
/* error occured */
strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
conn->error_info.error_no =
infile.local_infile_error(info, conn->error_info.error,
sizeof(conn->error_info.error) TSRMLS_CC);
/* write empty packet to server */
ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC);
goto infile_error;
}
/* read data */
while ((bufsize = infile.local_infile_read (info, buf + MYSQLND_HEADER_SIZE,
buflen - MYSQLND_HEADER_SIZE TSRMLS_CC)) > 0) {
if ((ret = mysqlnd_stream_write_w_header(conn, buf, bufsize TSRMLS_CC)) < 0) {
DBG_ERR_FMT("Error during read : %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
goto infile_error;
}
}
/* send empty packet for eof */
if ((ret = mysqlnd_stream_write_w_header(conn, empty_packet, 0 TSRMLS_CC)) < 0) {
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
goto infile_error;
}
/* error during read occured */
if (bufsize < 0) {
*is_warning = TRUE;
DBG_ERR_FMT("Bufsize < 0, warning, %d %s %s", CR_SERVER_LOST, UNKNOWN_SQLSTATE, lost_conn);
strcpy(conn->error_info.sqlstate, UNKNOWN_SQLSTATE);
conn->error_info.error_no = infile.local_infile_error(info, conn->error_info.error,
sizeof(conn->error_info.error) TSRMLS_CC);
goto infile_error;
}
result = PASS;
infile_error:
/* get response from server and update upsert values */
if (FAIL == mysqlnd_simple_command_handle_response(conn, PROT_OK_PACKET, FALSE, COM_QUERY TSRMLS_CC)) {
result = FAIL;
goto infile_error;
}
(*conn->infile.local_infile_end)(info TSRMLS_CC);
mnd_efree(buf);
DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL");
DBG_RETURN(result);
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,565 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_palloc.h"
#include "mysqlnd_debug.h"
/* Used in mysqlnd_debug.c */
char * mysqlnd_palloc_zval_ptr_dtor_name = "mysqlnd_palloc_zval_ptr_dtor";
char * mysqlnd_palloc_get_zval_name = "mysqlnd_palloc_get_zval";
#ifdef ZTS
#define LOCK_PCACHE(cache) tsrm_mutex_lock((cache)->LOCK_access)
#define UNLOCK_PCACHE(cache) tsrm_mutex_unlock((cache)->LOCK_access)
#else
#define LOCK_PCACHE(cache)
#define UNLOCK_PCACHE(cache)
#endif
#if PHP_MAJOR_VERSION < 6
#define IS_UNICODE_DISABLED (1)
#else
#define IS_UNICODE_DISABLED (!UG(unicode))
#endif
/* {{{ _mysqlnd_palloc_init_cache */
PHPAPI MYSQLND_ZVAL_PCACHE* _mysqlnd_palloc_init_cache(unsigned int cache_size TSRMLS_DC)
{
MYSQLND_ZVAL_PCACHE *ret = calloc(1, sizeof(MYSQLND_ZVAL_PCACHE));
unsigned int i;
DBG_ENTER("_mysqlnd_palloc_init_cache");
DBG_INF_FMT("cache=%p size=%u", ret, cache_size);
#ifdef ZTS
ret->LOCK_access = tsrm_mutex_alloc();
#endif
ret->max_items = cache_size;
ret->free_items = cache_size;
ret->references = 1;
/* 1. First initialize the free list part of the structure */
/* One more for empty position of last_added - always 0x0, bounds checking */
ret->free_list.ptr_line = calloc(ret->max_items + 1, sizeof(mysqlnd_zval *));
ret->free_list.last_added = ret->free_list.ptr_line + ret->max_items;
/* 3. Allocate and initialize our zvals and initialize the free list */
ret->block = calloc(ret->max_items, sizeof(mysqlnd_zval));
ret->last_in_block = &(ret->block[ret->max_items]);
for (i = 0; i < ret->max_items; i++) {
/* 1. Initialize */
INIT_PZVAL(&(ret->block[i].zv));
ZVAL_NULL(&(ret->block[i].zv));
/* Assure it will never be freed before MSHUTDOWN */
ZVAL_ADDREF(&(ret->block[i].zv));
/* 2. Add to the free list */
*(--ret->free_list.last_added) = &(ret->block[i]);
}
DBG_RETURN(ret);
}
/* }}} */
/* {{{ mysqlnd_palloc_get_cache_reference */
MYSQLND_ZVAL_PCACHE* mysqlnd_palloc_get_cache_reference(MYSQLND_ZVAL_PCACHE * const cache)
{
if (cache) {
LOCK_PCACHE(cache);
cache->references++;
UNLOCK_PCACHE(cache);
}
return cache;
}
/* }}} */
/* {{{ mysqlnd_palloc_free_cache */
/*
As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with
copy_ctor but scrap what they point to with zval_dtor() and then just free our
pre-allocated block. Precondition is that we ZVAL_NULL() the zvals when we put them
to the free list after usage. We ZVAL_NULL() them when we allocate them in the
constructor of the cache.
*/
void _mysqlnd_palloc_free_cache(MYSQLND_ZVAL_PCACHE *cache TSRMLS_DC)
{
DBG_ENTER("_mysqlnd_palloc_free_cache");
DBG_INF_FMT("cache=%p", cache);
#ifdef ZTS
tsrm_mutex_free(cache->LOCK_access);
#endif
/* Data in pointed by 'block' was cleaned in RSHUTDOWN */
mnd_free(cache->block);
mnd_free(cache->free_list.ptr_line);
mnd_free(cache);
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ _mysqlnd_palloc_init_thd_cache */
PHPAPI MYSQLND_THD_ZVAL_PCACHE* _mysqlnd_palloc_init_thd_cache(MYSQLND_ZVAL_PCACHE * const cache TSRMLS_DC)
{
MYSQLND_THD_ZVAL_PCACHE *ret = calloc(1, sizeof(MYSQLND_THD_ZVAL_PCACHE));
DBG_ENTER("_mysqlnd_palloc_init_thd_cache");
DBG_INF_FMT("ret = %p", ret);
ret->parent = mysqlnd_palloc_get_cache_reference(cache);
#ifdef ZTS
ret->thread_id = tsrm_thread_id();
#endif
ret->references = 1;
/* 1. Initialize the GC list */
ret->gc_list.ptr_line = calloc(cache->max_items, sizeof(mysqlnd_zval *));
/* Backward and forward looping is possible */
ret->gc_list.last_added = ret->gc_list.ptr_line;
DBG_RETURN(ret);
}
/* }}} */
/* {{{ mysqlnd_palloc_get_thd_cache_reference */
MYSQLND_THD_ZVAL_PCACHE* mysqlnd_palloc_get_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE * const cache)
{
if (cache) {
++cache->references;
mysqlnd_palloc_get_cache_reference(cache->parent);
}
return cache;
}
/* }}} */
/* {{{ mysqlnd_palloc_free_cache */
/*
As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with
copy_ctor but scrap what they point to with zval_dtor() and then just free our
pre-allocated block. Precondition is that we ZVAL_NULL() the zvals when we put them
to the free list after usage. We ZVAL_NULL() them when we allocate them in the
constructor of the cache.
*/
static
void mysqlnd_palloc_free_thd_cache(MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC)
{
DBG_ENTER("mysqlnd_palloc_free_thd_cache");
DBG_INF_FMT("cache=%p", cache);
mnd_free(cache->gc_list.ptr_line);
mnd_free(cache);
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ _mysqlnd_palloc_free_thd_cache_reference */
PHPAPI void _mysqlnd_palloc_free_thd_cache_reference(MYSQLND_THD_ZVAL_PCACHE **cache TSRMLS_DC)
{
DBG_ENTER("_mysqlnd_palloc_free_thd_cache_reference");
if (*cache) {
DBG_INF_FMT("cache=%p refs=%d", *cache, (*cache)->references);
--(*cache)->parent->references;
if (--(*cache)->references == 0) {
mysqlnd_palloc_free_thd_cache(*cache TSRMLS_CC);
}
*cache = NULL;
}
DBG_VOID_RETURN;
}
/* }}} */
/*
The cache line is a big contiguous array of zval pointers.
Because the CPU cache will cache starting from an address, and not
before it, then we have to organize our structure according to this.
Thus, if 'last_added' is valid pointer (not NULL) then last_added is
increased. When zval is cached, if there is room, last_added is decreased
and then the zval pointer will be assigned to it. This means that some
positions may become hot points and stay in the cache.
Imagine we have 5 pointers in a line
1. last_added = list_item->ptr_line + cache->max_items;
2. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
3. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
4. get_zval -> *last_added = NULL. Use MAKE_STD_ZVAL
0x0
0x0
0x0
0x0
0x0
---
empty_position, always 0x0 <-- last_added
5. free_zval -> if (free_items++ != max_items) {// we can add more
*(--last_added) = zval_ptr;
}
(memory addresses increase downwards)
0x0
0x0
0x0
0x0
0xA <-- last_added
---
0x0
6. free_zval -> if (free_items++ != max_items) {// we can add more
*(--last_added) = zval_ptr;
}
0x0
0x0
0x0
0xB <-- last_added
0xA
---
0x0
7. free_zval -> if (free_items++ != max_items) {// we can add more
*(--last_added) = zval_ptr;
}
0x0
0x0
0xC <-- last_added
0xB
0xA
---
0x0
8. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
0x0
0x0
0x0
0xB <-- last_added
0xA
---
0x0
9. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
0x0
0x0
0x0
0x0
0xA <-- last_added
---
0x0
10. get_zval -> *last_added != NULL. -> p = *last_added; *last_added++ = NULL;
0x0
0x0
0x0
0x0
0x0
---
0x0 <-- last_added
*/
/* {{{ mysqlnd_palloc_get_zval */
void *mysqlnd_palloc_get_zval(MYSQLND_THD_ZVAL_PCACHE * const thd_cache, zend_bool *allocated TSRMLS_DC)
{
void *ret = NULL;
DBG_ENTER("mysqlnd_palloc_get_zval");
DBG_INF_FMT("cache=%p *last_added=%p free_items=%d",
thd_cache, thd_cache? thd_cache->parent->free_list.last_added:NULL,
thd_cache->parent->free_items);
if (thd_cache) {
MYSQLND_ZVAL_PCACHE *cache = thd_cache->parent;
LOCK_PCACHE(cache);
if ((ret = *cache->free_list.last_added)) {
*cache->free_list.last_added++ = NULL;
*allocated = FALSE;
#ifdef ZTS
((mysqlnd_zval *) ret)->thread_id = thd_cache->thread_id;
#endif
--cache->free_items;
++cache->get_hits;
} else {
++cache->get_misses;
}
UNLOCK_PCACHE(cache);
}
if (!ret) {
/*
We allocate a bit more. The user of this function will use it, but at
end it will use only the zval part. Because the zval part is first then
when freeing the zval part the whole allocated block will be cleaned, not
only the zval part (by the Engine when destructing the zval).
*/
ALLOC_ZVAL(ret);
INIT_PZVAL((zval *) ret);
*allocated = TRUE;
} else {
/* This will set the refcount to 1, increase it, to keep the variable */
INIT_PZVAL(&((mysqlnd_zval *) ret)->zv);
ZVAL_ADDREF(&(((mysqlnd_zval *)ret)->zv));
}
DBG_INF_FMT("allocated=%d ret=%p", *allocated, ret);
DBG_RETURN(ret);
}
/* }}} */
/* {{{ mysqlnd_palloc_zval_ptr_dtor */
void mysqlnd_palloc_zval_ptr_dtor(zval **zv, MYSQLND_THD_ZVAL_PCACHE * const thd_cache,
enum_mysqlnd_res_type type, zend_bool *copy_ctor_called TSRMLS_DC)
{
MYSQLND_ZVAL_PCACHE *cache;
DBG_ENTER("mysqlnd_palloc_zval_ptr_dtor");
DBG_INF_FMT("cache=%p parent_block=%p last_in_block=%p *zv=%p refc=%d type=%d ",
thd_cache,
thd_cache->parent? thd_cache->parent->block:NULL,
thd_cache->parent? thd_cache->parent->last_in_block:NULL,
*zv, ZVAL_REFCOUNT(*zv), type);
*copy_ctor_called = FALSE;
/* Check whether cache is used and the zval is from the cache */
if (!thd_cache || !(cache = thd_cache->parent) || ((char *)*zv < (char *)thd_cache->parent->block ||
(char *)*zv > (char *)thd_cache->parent->last_in_block)) {
/*
This zval is not from the cache block.
Thus the refcount is -1 than of a zval from the cache,
because the zvals from the cache are owned by it.
*/
if (type == MYSQLND_RES_PS_BUF || type == MYSQLND_RES_PS_UNBUF) {
; /* do nothing, zval_ptr_dtor will do the job*/
} else if (ZVAL_REFCOUNT(*zv) > 1) {
/*
Not a prepared statement, then we have to
call copy_ctor and then zval_ptr_dtor()
In Unicode mode the destruction of the zvals should not call
zval_copy_ctor() because then we will leak.
I suppose we can use UG(unicode) in mysqlnd.c when freeing a result set
to check if we need to call copy_ctor().
If the type is IS_UNICODE, which can happen with PHP6, then we don't
need to copy_ctor, as the data doesn't point to our internal buffers.
If it's string (in PHP5 always) and in PHP6 if data is binary, then
it still points to internal buffers and has to be copied.
*/
if (Z_TYPE_PP(zv) == IS_STRING) {
zval_copy_ctor(*zv);
}
*copy_ctor_called = TRUE;
} else {
if (Z_TYPE_PP(zv) == IS_STRING) {
ZVAL_NULL(*zv);
}
}
zval_ptr_dtor(zv);
DBG_VOID_RETURN;
}
/* The zval is from our cache */
/* refcount is always > 1, because we call ZVAL_ADDREF(). Thus test refcount > 2 */
if (ZVAL_REFCOUNT(*zv) > 2) {
/*
Because the zval is first element in mysqlnd_zval structure, then we can
do upcasting from zval to mysqlnd_zval here. Because we know that this
zval is part of our pre-allocated block.
Now check whether this zval points to ZE allocated memory or to our
buffers. If it points to the internal buffers, call copy_ctor()
which will do estrndup for strings. And nothing for null, int, double.
This branch will be skipped for PS, because there is no need to copy
what is pointed by them, as they don't point to the internal buffers.
*/
if (((mysqlnd_zval *)*zv)->point_type == MYSQLND_POINTS_INT_BUFFER) {
zval_copy_ctor(*zv);
*copy_ctor_called = TRUE;
((mysqlnd_zval *)*zv)->point_type = MYSQLND_POINTS_EXT_BUFFER;
}
/*
This will decrease the counter of the user-level (mysqlnd). When the engine
layer (the script) has finished working this this zval, when the variable is
no more used, out of scope whatever, then it will try zval_ptr_dtor() but
and the refcount will reach 1 and the engine won't try to destruct the
memory allocated by us.
*/
zval_ptr_dtor(zv);
/*
Unfortunately, we can't return this variable to the free_list
because it's still used. And this cleaning up will happen at request
shutdown :(.
*/
LOCK_PCACHE(cache);
++cache->put_misses;
*(thd_cache->gc_list.last_added++) = (mysqlnd_zval *)*zv;
UNLOCK_PCACHE(cache);
} else {
/* No user reference */
if (((mysqlnd_zval *)*zv)->point_type == MYSQLND_POINTS_EXT_BUFFER) {
/* PS are here and also in Unicode mode, for non-binary */
zval_dtor(*zv);
}
LOCK_PCACHE(cache);
++cache->put_hits;
++cache->free_items;
((mysqlnd_zval *)*zv)->point_type = MYSQLND_POINTS_FREE;
ZVAL_DELREF(*zv); /* Make it 1 */
ZVAL_NULL(*zv);
#ifdef ZTS
memset(&((mysqlnd_zval *)*zv)->thread_id, 0, sizeof(THREAD_T));
#endif
*(--cache->free_list.last_added) = (mysqlnd_zval *)*zv;
UNLOCK_PCACHE(cache);
}
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ _mysqlnd_palloc_rinit */
PHPAPI MYSQLND_THD_ZVAL_PCACHE * _mysqlnd_palloc_rinit(MYSQLND_ZVAL_PCACHE * cache TSRMLS_DC)
{
return mysqlnd_palloc_init_thd_cache(cache);
}
/* }}} */
/* {{{ _mysqlnd_palloc_rshutdown */
PHPAPI void _mysqlnd_palloc_rshutdown(MYSQLND_THD_ZVAL_PCACHE * thd_cache TSRMLS_DC)
{
MYSQLND_ZVAL_PCACHE *cache;
mysqlnd_zval **p;
DBG_ENTER("_mysqlnd_palloc_rshutdown");
DBG_INF_FMT("cache=%p", thd_cache);
if (!thd_cache || !(cache = thd_cache->parent)) {
return;
}
/*
Keep in mind that for pthreads pthread_equal() should be used to be
fully standard compliant. However, the PHP code all-around, incl. the
the Zend MM uses direct comparison.
*/
p = thd_cache->gc_list.ptr_line;
while (p < thd_cache->gc_list.last_added) {
zval_dtor(&(*p)->zv);
p++;
}
p = thd_cache->gc_list.ptr_line;
LOCK_PCACHE(cache);
while (p < thd_cache->gc_list.last_added) {
(*p)->point_type = MYSQLND_POINTS_FREE;
*(--cache->free_list.last_added) = *p;
++cache->free_items;
#ifdef ZTS
memset(&((*p)->thread_id), 0, sizeof(THREAD_T));
#endif
p++;
}
UNLOCK_PCACHE(cache);
mysqlnd_palloc_free_thd_cache_reference(&thd_cache);
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_palloc_rshutdown */
PHPAPI void mysqlnd_palloc_stats(const MYSQLND_ZVAL_PCACHE * const cache, zval *return_value)
{
if (cache) {
#if PHP_MAJOR_VERSION >= 6
TSRMLS_FETCH();
#endif
LOCK_PCACHE(cache);
array_init(return_value);
#if PHP_MAJOR_VERSION >= 6
if (UG(unicode)) {
UChar *ustr;
int ulen;
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "put_hits", sizeof("put_hits") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "put_misses", sizeof("put_misses") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "get_hits", sizeof("get_hits") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "get_misses", sizeof("get_misses") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "size", sizeof("size") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "free_items", sizeof("free_items") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, "references", sizeof("references") TSRMLS_CC);
add_u_assoc_long_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen + 1, cache->put_hits);
efree(ustr);
} else
#endif
{
add_assoc_long_ex(return_value, "put_hits", sizeof("put_hits"), cache->put_hits);
add_assoc_long_ex(return_value, "put_misses", sizeof("put_misses"), cache->put_misses);
add_assoc_long_ex(return_value, "get_hits", sizeof("get_hits"), cache->get_hits);
add_assoc_long_ex(return_value, "get_misses", sizeof("get_misses"), cache->get_misses);
add_assoc_long_ex(return_value, "size", sizeof("size"), cache->max_items);
add_assoc_long_ex(return_value, "free_items", sizeof("free_items"), cache->free_items);
add_assoc_long_ex(return_value, "references", sizeof("references"), cache->references);
}
UNLOCK_PCACHE(cache);
} else {
ZVAL_NULL(return_value);
}
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,114 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_PALLOC_H
#define MYSQLND_PALLOC_H
/* Used in mysqlnd_debug.c */
extern char * mysqlnd_palloc_zval_ptr_dtor_name;
extern char * mysqlnd_palloc_get_zval_name;
/* Session caching allocator */
struct st_mysqlnd_zval_list {
zval **ptr_line;
zval **last_added;
};
typedef struct st_mysqlnd_zval_cache MYSQLND_ZVAL_CACHE;
struct st_mysqlnd_zval_cache {
struct st_mysqlnd_zval_list *free_list;
unsigned int free_items;
unsigned int max_items;
unsigned int references;
unsigned long get_hits;
unsigned long get_misses;
unsigned long put_hits;
unsigned long put_full_misses;
unsigned long put_refcount_misses;
};
enum mysqlnd_zval_ptr_type
{
MYSQLND_POINTS_INT_BUFFER,
MYSQLND_POINTS_EXT_BUFFER,
MYSQLND_POINTS_FREE
};
/* Persistent caching allocator */
typedef struct st_mysqlnd_zval {
/* Should be first */
zval zv;
enum mysqlnd_zval_ptr_type point_type;
#ifdef ZTS
THREAD_T thread_id;
#endif
} mysqlnd_zval;
typedef struct st_mysqlnd_ndzval_list {
mysqlnd_zval **ptr_line; /* we allocate this, all are pointers to the block */
mysqlnd_zval **last_added; /* this points to the ptr_line, and moves left-right. It's our stack */
} mysqlnd_ndzval_list;
struct st_mysqlnd_zval_pcache {
mysqlnd_zval *block;
mysqlnd_zval *last_in_block;
mysqlnd_ndzval_list free_list; /* Fetch from here */
#ifdef ZTS
MUTEX_T LOCK_access;
#endif
unsigned int references;
/* These are just for statistics and not used for operational purposes */
unsigned int free_items;
unsigned int max_items;
unsigned long get_hits;
unsigned long get_misses;
unsigned long put_hits;
unsigned long put_misses;
};
struct st_mysqlnd_thread_zval_pcache {
struct st_mysqlnd_zval_pcache *parent;
unsigned int references;
#ifdef ZTS
THREAD_T thread_id;
#endif
mysqlnd_ndzval_list gc_list; /* GC these from time to time */
};
#endif /* MYSQLND_PALLOC_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,515 @@
/* Copyright Abandoned 1996 TCX DataKonsult AB & Monty Program KB & Detron HB
This file is public domain and comes with NO WARRANTY of any kind */
/*
Parts of the original, which are not applicable to mysqlnd have been removed.
With small modifications, mostly casting but adding few more macros by
Andrey Hristov <andrey@mysql.com> . The additions are in the public domain and
were added to improve the header file, to get it more consistent.
*/
/* Comes from global.h as OFFSET, renamed to STRUCT_OFFSET */
#define STRUCT_OFFSET(t, f) ((size_t)(char *)&((t *)0)->f)
#ifndef __attribute
#if !defined(__GNUC__)
#define __attribute(A)
#endif
#endif
#ifdef __CYGWIN__
/* We use a Unix API, so pretend it's not Windows */
#undef WIN
#undef WIN32
#undef _WIN
#undef _WIN32
#undef _WIN64
#undef __WIN__
#undef __WIN32__
#endif /* __CYGWIN__ */
#if defined(_WIN32) || defined(_WIN64) || defined(__WIN32__) || defined(WIN32)
# include <ext/mysqlnd/config-win.h>
#else
# include "ext/mysqlnd/php_mysqlnd_config.h"
#endif /* _WIN32... */
#ifdef HAVE_SYS_TYPES_H
#include <sys/types.h>
#endif
#ifdef HAVE_STDINT_H
#include <stdint.h>
#endif
#if SIZEOF_LONG_LONG > 4 && !defined(_LONG_LONG)
#define _LONG_LONG 1 /* For AIX string library */
#endif
/* Go around some bugs in different OS and compilers */
#if defined(_HPUX_SOURCE) && defined(HAVE_SYS_STREAM_H)
#include <sys/stream.h> /* HPUX 10.20 defines ulong here. UGLY !!! */
#define HAVE_ULONG
#endif
#if SIZEOF_LONG_LONG > 4
#define HAVE_LONG_LONG 1
#endif
/* Typdefs for easyier portability */
#ifndef HAVE_INT8
#ifndef HAVE_INT8_T
typedef signed char int8; /* Signed integer >= 8 bits */
#else
typedef int8_t int8; /* Signed integer >= 8 bits */
#endif
#endif
#ifndef HAVE_UINT8
#ifndef HAVE_UINT8_T
typedef unsigned char uint8; /* Unsigned integer >= 8 bits */
#else
typedef uint8_t uint8; /* Signed integer >= 8 bits */
#endif
#endif
#ifndef HAVE_INT16
#ifndef HAVE_INT16_T
typedef signed short int16; /* Signed integer >= 16 bits */
#else
typedef int16_t int16; /* Signed integer >= 16 bits */
#endif
#endif
#ifndef HAVE_UINT16
#ifndef HAVE_UINT16_T
typedef unsigned short uint16; /* Signed integer >= 16 bits */
#else
typedef uint16_t uint16; /* Signed integer >= 16 bits */
#endif
#endif
#ifndef HAVE_UCHAR
typedef unsigned char uchar; /* Short for unsigned char */
#endif
#if defined(HAVE_INT32_T) && defined(HAVE_UINT32_T)
typedef int32_t int32;
typedef uint32_t uint32;
#elif SIZEOF_INT == 4
#ifndef HAVE_INT32
typedef signed int int32;
#endif
#ifndef HAVE_UINT32
typedef unsigned int uint32;
#endif
#elif SIZEOF_LONG == 4
#ifndef HAVE_INT32
typedef signed long int32;
#endif
#ifndef HAVE_UINT32
typedef unsigned long uint32;
#endif
#else
error "Neither int or long is of 4 bytes width"
#endif
#if !defined(HAVE_ULONG) && !defined(__USE_MISC) && !defined(ulong)
typedef unsigned long ulong; /* Short for unsigned long */
#endif
#ifndef longlong_defined
#if defined(HAVE_LONG_LONG) && SIZEOF_LONG != 8
typedef unsigned long long int ulonglong; /* ulong or unsigned long long */
typedef long long int longlong;
#else
typedef unsigned long ulonglong; /* ulong or unsigned long long */
typedef long longlong;
#endif
#endif
#define int1store(T,A) do { *((zend_uchar*) (T)) = (A); } while(0)
#define uint1korr(A) (*(((uint8*)(A))))
/* Bit values are sent in reverted order of bytes, compared to normal !!! */
#define bit_uint2korr(A) ((uint16) (((uint16) (((uchar*) (A))[1])) +\
((uint16) (((uchar*) (A))[0]) << 8)))
#define bit_uint3korr(A) ((uint32) (((uint32) (((uchar*) (A))[2])) +\
(((uint32) (((uchar*) (A))[1])) << 8) +\
(((uint32) (((uchar*) (A))[0])) << 16)))
#define bit_uint4korr(A) ((uint32) (((uint32) (((uchar*) (A))[3])) +\
(((uint32) (((uchar*) (A))[2])) << 8) +\
(((uint32) (((uchar*) (A))[1])) << 16) +\
(((uint32) (((uchar*) (A))[0])) << 24)))
#define bit_uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[4])) +\
(((uint32) ((uchar) (A)[3])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16) +\
(((uint32) ((uchar) (A)[1])) << 24)) +\
(((ulonglong) ((uchar) (A)[0])) << 32))
#define bit_uint6korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[5])) +\
(((uint32) (((uchar*) (A))[4])) << 8) +\
(((uint32) (((uchar*) (A))[3])) << 16) +\
(((uint32) (((uchar*) (A))[2])) << 24)) +\
(((ulonglong) (((uint32) (((uchar*) (A))[1])) +\
(((uint32) (((uchar*) (A))[0]) << 8)))) << 32))
#define bit_uint7korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[6])) +\
(((uint32) (((uchar*) (A))[5])) << 8) +\
(((uint32) (((uchar*) (A))[4])) << 16) +\
(((uint32) (((uchar*) (A))[3])) << 24)) +\
(((ulonglong) (((uint32) (((uchar*) (A))[2])) +\
(((uint32) (((uchar*) (A))[1])) << 8) +\
(((uint32) (((uchar*) (A))[0])) << 16))) << 32))
#define bit_uint8korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[7])) +\
(((uint32) (((uchar*) (A))[6])) << 8) +\
(((uint32) (((uchar*) (A))[5])) << 16) +\
(((uint32) (((uchar*) (A))[4])) << 24)) +\
(((ulonglong) (((uint32) (((uchar*) (A))[3])) +\
(((uint32) (((uchar*) (A))[2])) << 8) +\
(((uint32) (((uchar*) (A))[1])) << 16) +\
(((uint32) (((uchar*) (A))[0])) << 24))) << 32))
/*
** Define-funktions for reading and storing in machine independent format
** (low byte first)
*/
/* Optimized store functions for Intel x86, non-valid for WIN64 */
#if defined(__i386__) && !defined(_WIN64)
#define sint2korr(A) (*((int16 *) (A)))
#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
(((uint32) 255L << 24) | \
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])) : \
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])))
#define sint4korr(A) (*((long *) (A)))
#define uint2korr(A) (*((uint16 *) (A)))
#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16))
#define uint4korr(A) (*((unsigned long *) (A)))
#define uint8korr(A) (*((ulonglong *) (A)))
#define sint8korr(A) (*((longlong *) (A)))
#define int2store(T,A) *((uint16*) (T))= (uint16) (A)
#define int3store(T,A) { \
*(T)= (uchar) ((A));\
*(T+1)=(uchar) (((uint) (A) >> 8));\
*(T+2)=(uchar) (((A) >> 16)); }
#define int4store(T,A) *((long *) (T))= (long) (A)
#define int5store(T,A) { \
*((uchar *)(T))= (uchar)((A));\
*(((uchar *)(T))+1)=(uchar) (((A) >> 8));\
*(((uchar *)(T))+2)=(uchar) (((A) >> 16));\
*(((uchar *)(T))+3)=(uchar) (((A) >> 24)); \
*(((uchar *)(T))+4)=(uchar) (((A) >> 32)); }
/* From Andrey Hristov, based on int5store() */
#define int6store(T,A) { \
*(((uchar *)(T)))= (uchar)((A));\
*(((uchar *)(T))+1))=(uchar) (((A) >> 8));\
*(((uchar *)(T))+2))=(uchar) (((A) >> 16));\
*(((uchar *)(T))+3))=(uchar) (((A) >> 24)); \
*(((uchar *)(T))+4))=(uchar) (((A) >> 32)); \
*(((uchar *)(T))+5))=(uchar) (((A) >> 40)); }
#define int8store(T,A) *((ulonglong *) (T))= (ulonglong) (A)
typedef union {
double v;
long m[2];
} doubleget_union;
#define doubleget(V,M) { ((doubleget_union *)&(V))->m[0] = *((long*) (M)); \
((doubleget_union *)&(V))->m[1] = *(((long*) (M))+1); }
#define doublestore(T,V) { *((long *) (T)) = ((doubleget_union *)&(V))->m[0]; \
*(((long *) (T))+1) = ((doubleget_union *)&(V))->m[1]; }
#define float4get(V,M) { *((float *) &(V)) = *((float*) (M)); }
#define float8get(V,M) doubleget((V),(M))
/* From Andrey Hristov based on doubleget */
#define floatget(V,M) memcpy((char*) &(V),(char*) (M),sizeof(float))
#define floatstore float4store
#define float4store(V,M) memcpy((char*) (V),(char*) (&M),sizeof(float))
#define float8store(V,M) doublestore((V),(M))
#endif /* __i386__ */
#ifndef sint2korr
#define sint2korr(A) (int16) (((int16) ((uchar) (A)[0])) +\
((int16) ((int16) (A)[1]) << 8))
#define sint3korr(A) ((int32) ((((uchar) (A)[2]) & 128) ? \
(((uint32) 255L << 24) | \
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])) : \
(((uint32) (uchar) (A)[2]) << 16) |\
(((uint32) (uchar) (A)[1]) << 8) | \
((uint32) (uchar) (A)[0])))
#define sint4korr(A) (int32) (((int32) ((uchar) (A)[0])) +\
(((int32) ((uchar) (A)[1]) << 8)) +\
(((int32) ((uchar) (A)[2]) << 16)) +\
(((int32) ((int16) (A)[3]) << 24)))
#define sint8korr(A) (longlong) uint8korr(A)
#define uint2korr(A) (uint16) (((uint16) ((uchar) (A)[0])) +\
((uint16) ((uchar) (A)[1]) << 8))
#define uint3korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16))
#define uint4korr(A) (uint32) (((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16) +\
(((uint32) ((uchar) (A)[3])) << 24))
#define bit_uint5korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16) +\
(((uint32) ((uchar) (A)[3])) << 24)) +\
(((ulonglong) ((uchar) (A)[4])) << 32))
/* From Andrey Hristov, based on uint5korr */
#define bit_uint6korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[5])) +\
(((uint32) (((uchar*) (A))[4])) << 8) +\
(((uint32) (((uchar*) (A))[3])) << 16) +\
(((uint32) (((uchar*) (A))[2])) << 24)) +\
(((ulonglong) (((uint32) (((uchar*) (A))[1])) +\
(((uint32) (((uchar*) (A))[0]) << 8)))) << 32))
#define bit_uint7korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[6])) +\
(((uint32) (((uchar*) (A))[5])) << 8) +\
(((uint32) (((uchar*) (A))[4])) << 16) +\
(((uint32) (((uchar*) (A))[3])) << 24)) +\
(((ulonglong) (((uint32) (((uchar*) (A))[2])) +\
(((uint32) (((uchar*) (A))[1])) << 8) +\
(((uint32) (((uchar*) (A))[0])) << 16))) << 32))
#define bit_uint8korr(A) ((ulonglong)(((uint32) (((uchar*) (A))[7])) +\
(((uint32) (((uchar*) (A))[6])) << 8) +\
(((uint32) (((uchar*) (A))[5])) << 16) +\
(((uint32) (((uchar*) (A))[4])) << 24)) +\
(((ulonglong) (((uint32) (((uchar*) (A))[3])) +\
(((uint32) (((uchar*) (A))[2])) << 8) +\
(((uint32) (((uchar*) (A))[1])) << 16) +\
(((uint32) (((uchar*) (A))[0])) << 24))) << 32))
#define uint8korr(A) ((ulonglong)(((uint32) ((uchar) (A)[0])) +\
(((uint32) ((uchar) (A)[1])) << 8) +\
(((uint32) ((uchar) (A)[2])) << 16) +\
(((uint32) ((uchar) (A)[3])) << 24)) +\
(((ulonglong) (((uint32) ((uchar) (A)[4])) +\
(((uint32) ((uchar) (A)[5])) << 8) +\
(((uint32) ((uchar) (A)[6])) << 16) +\
(((uint32) ((uchar) (A)[7])) << 24))) << 32))
#define int2store(T,A) do { uint def_temp= (uint) (A) ;\
*((uchar*) (T)) = (uchar)(def_temp); \
*((uchar*) (T+1)) = (uchar)((def_temp >> 8)); } while (0)
#define int3store(T,A) do { /*lint -save -e734 */\
*(((char *)(T))) = (char) ((A));\
*(((char *)(T))+1) = (char) (((A) >> 8));\
*(((char *)(T))+2) = (char) (((A) >> 16)); \
/*lint -restore */} while (0)
#define int4store(T,A) do { \
*(((char *)(T))) = (char) ((A));\
*(((char *)(T))+1) = (char) (((A) >> 8));\
*(((char *)(T))+2) = (char) (((A) >> 16));\
*(((char *)(T))+3) = (char) (((A) >> 24)); } while (0)
#define int5store(T,A) do { \
*(((char *)(T))) = (char)((A));\
*(((char *)(T))+1) = (char)(((A) >> 8));\
*(((char *)(T))+2) = (char)(((A) >> 16));\
*(((char *)(T))+3) = (char)(((A) >> 24)); \
*(((char *)(T))+4) = (char)(((A) >> 32)); } while (0)
/* Based on int5store() from Andrey Hristov */
#define int6store(T,A) do { \
*(((char *)(T))) = (char)((A));\
*(((char *)(T))+1) = (char)(((A) >> 8));\
*(((char *)(T))+2) = (char)(((A) >> 16));\
*(((char *)(T))+3) = (char)(((A) >> 24)); \
*(((char *)(T))+4) = (char)(((A) >> 32)); \
*(((char *)(T))+5) = (char)(((A) >> 40)); } while (0)
#define int8store(T,A) { uint def_temp= (uint) (A), def_temp2= (uint) ((A) >> 32); \
int4store((T),def_temp); \
int4store((T+4),def_temp2); \
}
#ifdef WORDS_BIGENDIAN
#define float4store(T,A) do { \
*(((char *)(T))) = (char) ((char *) &A)[3];\
*(((char *)(T))+1) = (char) ((char *) &A)[2];\
*(((char *)(T))+2) = (char) ((char *) &A)[1];\
*(((char *)(T))+3) = (char) ((char *) &A)[0]; } while (0)
#define float4get(V,M) do { float def_temp;\
((char*) &def_temp)[0] = (M)[3];\
((char*) &def_temp)[1] = (M)[2];\
((char*) &def_temp)[2] = (M)[1];\
((char*) &def_temp)[3] = (M)[0];\
(V)=def_temp; } while (0)
#define float8store(T,V) do { \
*(((char *)(T))) = (char) ((char *) &(V))[7];\
*(((char *)(T))+1) = (char) ((char *) &(V))[6];\
*(((char *)(T))+2) = (char) ((char *) &(V))[5];\
*(((char *)(T))+3) = (char) ((char *) &(V))[4];\
*(((char *)(T))+4) = (char) ((char *) &(V))[3];\
*(((char *)(T))+5) = (char) ((char *) &(V))[2];\
*(((char *)(T))+6) = (char) ((char *) &(V))[1];\
*(((char *)(T))+7) = (char) ((char *) &(V))[0]; } while (0)
#define float8get(V,M) do { double def_temp;\
((char*) &def_temp)[0] = (M)[7];\
((char*) &def_temp)[1] = (M)[6];\
((char*) &def_temp)[2] = (M)[5];\
((char*) &def_temp)[3] = (M)[4];\
((char*) &def_temp)[4] = (M)[3];\
((char*) &def_temp)[5] = (M)[2];\
((char*) &def_temp)[6] = (M)[1];\
((char*) &def_temp)[7] = (M)[0];\
(V) = def_temp; \
} while (0)
#else
#define float4get(V,M) memcpy((char*) &(V),(char*) (M),sizeof(float))
#define float4store(V,M) memcpy((char*) (V),(char*) (&M),sizeof(float))
#if defined(__FLOAT_WORD_ORDER) && (__FLOAT_WORD_ORDER == __BIG_ENDIAN)
#define doublestore(T,V) do { \
*(((char *)(T)))= ((char *) &(V))[4];\
*(((char *)(T))+1)=(char) ((char *) &(V))[5];\
*(((char *)(T))+2)=(char) ((char *) &(V))[6];\
*(((char *)(T))+3)=(char) ((char *) &(V))[7];\
*(((char *)(T))+4)=(char) ((char *) &(V))[0];\
*(((char *)(T))+5)=(char) ((char *) &(V))[1];\
*(((char *)(T))+6)=(char) ((char *) &(V))[2];\
*(((char *)(T))+7)=(char) ((char *) &(V))[3];} while (0)
#define doubleget(V,M) do { double def_temp;\
((char*) &def_temp)[0]=(M)[4];\
((char*) &def_temp)[1]=(M)[5];\
((char*) &def_temp)[2]=(M)[6];\
((char*) &def_temp)[3]=(M)[7];\
((char*) &def_temp)[4]=(M)[0];\
((char*) &def_temp)[5]=(M)[1];\
((char*) &def_temp)[6]=(M)[2];\
((char*) &def_temp)[7]=(M)[3];\
(V) = def_temp; } while (0)
#endif /* __FLOAT_WORD_ORDER */
#define float8get(V,M) doubleget((V),(M))
#define float8store(V,M) doublestore((V),(M))
#endif /* WORDS_BIGENDIAN */
#endif /* sint2korr */
/* Define-funktions for reading and storing in machine format from/to
short/long to/from some place in memory V should be a (not
register) variable, M is a pointer to byte */
#ifdef WORDS_BIGENDIAN
#define ushortget(V,M) { V = (uint16) (((uint16) ((uchar) (M)[1]))+\
((uint16) ((uint16) (M)[0]) << 8)); }
#define shortget(V,M) { V = (short) (((short) ((uchar) (M)[1]))+\
((short) ((short) (M)[0]) << 8)); }
#define longget(V,M) do { int32 def_temp;\
((char*) &def_temp)[0]=(M)[0];\
((char*) &def_temp)[1]=(M)[1];\
((char*) &def_temp)[2]=(M)[2];\
((char*) &def_temp)[3]=(M)[3];\
(V)=def_temp; } while (0)
#define ulongget(V,M) do { uint32 def_temp;\
((char*) &def_temp)[0]=(M)[0];\
((char*) &def_temp)[1]=(M)[1];\
((char*) &def_temp)[2]=(M)[2];\
((char*) &def_temp)[3]=(M)[3];\
(V)=def_temp; } while (0)
#define shortstore(T,A) do { \
uint def_temp=(uint) (A) ;\
*(((char *)(T))+1)=(char)(def_temp); \
*(((char *)(T))+0)=(char)(def_temp >> 8); } while (0)
#define longstore(T,A) do { \
*(((char *)(T))+3)=(char)((A));\
*(((char *)(T))+2)=(char)(((A) >> 8));\
*(((char *)(T))+1)=(char)(((A) >> 16));\
*(((char *)(T))+0)=(char)(((A) >> 24)); } while (0)
#define doubleget(V,M) memcpy((char*) &(V),(char*) (M), sizeof(double))
#define doublestore(T,V) memcpy((char*) (T),(char*) &(V), sizeof(double))
#define longlongget(V,M) memcpy((char*) &(V),(char*) (M), sizeof(ulonglong))
#define longlongstore(T,V) memcpy((char*) (T),(char*) &(V), sizeof(ulonglong))
#else
#define ushortget(V,M) { V = uint2korr((M)); }
#define shortget(V,M) { V = sint2korr((M)); }
#define longget(V,M) { V = sint4korr((M)); }
#define ulongget(V,M) { V = uint4korr((M)); }
#define shortstore(T,V) int2store((T),(V))
#define longstore(T,V) int4store((T),(V))
#ifndef doubleget
#define doubleget(V,M) memcpy((char*) &(V),(char*) (M),sizeof(double))
#define doublestore(T,V) memcpy((char*) (T),(char*) &(V),sizeof(double))
#endif /* doubleget */
#define longlongget(V,M) memcpy((char*) &(V),(char*) (M),sizeof(ulonglong))
#define longlongstore(T,V) memcpy((char*) (T),(char*) &(V),sizeof(ulonglong))
#endif /* WORDS_BIGENDIAN */
#ifdef PHP_WIN32
#define MYSQLND_LLU_SPEC "%I64u"
#define MYSQLND_LL_SPEC "%I64d"
#ifndef L64
#define L64(x) x##i64
#endif
typedef unsigned __int64 my_uint64;
typedef __int64 my_int64;
typedef unsigned __int64 mynd_ulonglong;
typedef __int64 mynd_longlong;
#else
#define MYSQLND_LLU_SPEC "%llu"
#define MYSQLND_LL_SPEC "%lld"
#ifndef L64
#define L64(x) x##LL
#endif
#ifndef HAVE_UINT64_T
typedef unsigned long long my_uint64;
typedef unsigned long long mynd_ulonglong;
#else
typedef uint64_t my_uint64;
typedef uint64_t mynd_ulonglong;
#endif
#ifndef HAVE_INT64_T
typedef long long my_int64;
typedef long long mynd_longlong;
#else
typedef int64_t my_int64;
typedef int64_t mynd_longlong;
#endif
#endif
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

191
ext/mysqlnd/mysqlnd_priv.h Normal file
View File

@ -0,0 +1,191 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_PRIV_H
#define MYSQLND_PRIV_H
#ifdef ZTS
#include "TSRM.h"
#endif
#ifndef TRUE
#define TRUE 1
#endif
#ifndef FALSE
#define FALSE 0
#endif
#ifndef pestrndup
#define pestrndup(s, length, persistent) ((persistent)?zend_strndup((s),(length)):estrndup((s),(length)))
#endif
#define MYSQLND_CLASS_METHODS_START(class) static \
struct st_##class##_methods mysqlnd_##class##_methods = {
#define MYSQLND_CLASS_METHODS_END }
#define MYSQLND_METHOD(class, method) php_##class##_##method##_pub
#define MYSQLND_METHOD_PRIVATE(class, method) php_##class##_##method##_priv
#if PHP_MAJOR_VERSION < 6
#define mysqlnd_array_init(arg, field_count) \
{ \
ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg));\
zend_hash_init(Z_ARRVAL_P(arg), (field_count), NULL, ZVAL_PTR_DTOR, 0); \
Z_TYPE_P(arg) = IS_ARRAY;\
}
#else
#define mysqlnd_array_init(arg, field_count) \
{ \
ALLOC_HASHTABLE_REL(Z_ARRVAL_P(arg));\
zend_u_hash_init(Z_ARRVAL_P(arg), (field_count), NULL, ZVAL_PTR_DTOR, 0, 0);\
Z_TYPE_P(arg) = IS_ARRAY;\
}
#endif
#define SERVER_STATUS_IN_TRANS 1 /* Transaction has started */
#define SERVER_STATUS_AUTOCOMMIT 2 /* Server in auto_commit mode */
#define SERVER_MORE_RESULTS_EXISTS 8 /* Multi query - next query exists */
/*
The server was able to fulfill the clients request and opened a
read-only non-scrollable cursor for a query. This flag comes
in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
*/
#define SERVER_STATUS_CURSOR_EXISTS 64
/*
This flag is sent when a read-only cursor is exhausted, in reply to
COM_STMT_FETCH command.
*/
#define SERVER_STATUS_LAST_ROW_SENT 128
#define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */
#define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512
/* Client Error codes */
#define CR_UNKNOWN_ERROR 2000
#define CR_CONNECTION_ERROR 2002
#define CR_SERVER_GONE_ERROR 2006
#define CR_OUT_OF_MEMORY 2008
#define CR_SERVER_LOST 2013
#define CR_COMMANDS_OUT_OF_SYNC 2014
#define CR_CANT_FIND_CHARSET 2019
#define CR_MALFORMED_PACKET 2027
#define CR_NOT_IMPLEMENTED 2054
#define CR_NO_PREPARE_STMT 2030
#define CR_PARAMS_NOT_BOUND 2031
#define CR_INVALID_PARAMETER_NO 2034
#define CR_INVALID_BUFFER_USE 2035
#define MYSQLND_EE_FILENOTFOUND 7890
#define UNKNOWN_SQLSTATE "HY000"
#define MAX_CHARSET_LEN 32
#define SET_ERROR_AFF_ROWS(s) (s)->upsert_status.affected_rows = (mynd_ulonglong) ~0
/* Error handling */
#define SET_NEW_MESSAGE(buf, buf_len, message, len, persistent) \
{\
if ((buf)) { \
pefree((buf), (persistent)); \
} \
(buf) = (message); \
(buf_len) = (len); \
/* Transfer ownership*/ \
(message) = NULL; \
}
#define SET_EMPTY_MESSAGE(buf, buf_len, persistent) \
{\
if ((buf)) { \
pefree((buf), (persistent)); \
(buf) = NULL; \
} \
(buf_len) = 0; \
}
#define SET_EMPTY_ERROR(error_info) \
{ \
error_info.error_no = 0; \
error_info.error[0] = '\0'; \
strncpy(error_info.sqlstate, "00000", sizeof("00000") - 1); \
}
#define SET_CLIENT_ERROR(error_info, a, b, c) \
{ \
error_info.error_no = a; \
strncpy(error_info.sqlstate, b, sizeof(error_info.sqlstate)); \
strncpy(error_info.error, c, sizeof(error_info.error)); \
}
#define SET_STMT_ERROR(stmt, a, b, c) SET_CLIENT_ERROR(stmt->error_info, a, b, c)
/* PS stuff */
typedef void (*ps_field_fetch_func)(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool everything_as_unicode TSRMLS_DC);
struct st_mysqlnd_perm_bind {
ps_field_fetch_func func;
/* should be signed int */
int pack_len;
unsigned int php_type;
zend_bool is_possibly_blob;
zend_bool can_ret_as_str_in_uni;
};
extern struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
extern const char * mysqlnd_out_of_sync;
extern const char * mysqlnd_server_gone;
enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC);
void _mysqlnd_init_ps_subsystem();/* This one is private, mysqlnd_library_init() will call it */
void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row, zend_bool as_unicode,
unsigned int byte_count TSRMLS_DC);
int mysqlnd_set_sock_no_delay(php_stream *stream);
#endif /* MYSQLND_PRIV_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

1740
ext/mysqlnd/mysqlnd_ps.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,854 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_debug.h"
#define MYSQLND_SILENT
typedef int8 my_int8;
typedef uint8 my_uint8;
typedef int16 my_int16;
typedef uint16 my_uint16;
typedef int32 my_int32;
typedef uint32 my_uint32;
enum mysqlnd_timestamp_type
{
MYSQLND_TIMESTAMP_NONE= -2,
MYSQLND_TIMESTAMP_ERROR= -1,
MYSQLND_TIMESTAMP_DATE= 0,
MYSQLND_TIMESTAMP_DATETIME= 1,
MYSQLND_TIMESTAMP_TIME= 2
};
struct st_mysqlnd_time
{
unsigned int year, month, day, hour, minute, second;
unsigned long second_part;
zend_bool neg;
enum mysqlnd_timestamp_type time_type;
};
struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST + 1];
#define MYSQLND_PS_SKIP_RESULT_W_LEN -1
#define MYSQLND_PS_SKIP_RESULT_STR -2
/* {{{ ps_fetch_from_1_to_8_bytes */
void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row, zend_bool as_unicode,
unsigned int byte_count TSRMLS_DC)
{
char tmp[22];
size_t tmp_len = 0;
zend_bool is_bit = field->type == MYSQL_TYPE_BIT;
if (field->flags & UNSIGNED_FLAG) {
my_uint64 uval = 0;
switch (byte_count) {
case 8:uval = is_bit? (my_uint64) bit_uint8korr(*row):(my_uint64) uint8korr(*row);break;
case 7:uval = bit_uint7korr(*row);break;
case 6:uval = bit_uint6korr(*row);break;
case 5:uval = bit_uint5korr(*row);break;
case 4:uval = is_bit? (my_uint64) bit_uint4korr(*row):(my_uint64) uint4korr(*row);break;
case 3:uval = is_bit? (my_uint64) bit_uint3korr(*row):(my_uint64) uint3korr(*row);break;
case 2:uval = is_bit? (my_uint64) bit_uint2korr(*row):(my_uint64) uint2korr(*row);break;
case 1:uval = (my_uint64) uint1korr(*row);break;
}
#if SIZEOF_LONG==4
if (uval > INT_MAX) {
tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
} else
#endif /* #if SIZEOF_LONG==4 */
{
if (byte_count < 8 || uval <= L64(9223372036854775807)) {
ZVAL_LONG(zv, uval);
} else {
tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval);
}
}
} else {
/* SIGNED */
my_int64 lval = 0;
switch (byte_count) {
case 8:lval = (my_int64) sint8korr(*row);break;
/*
7, 6 and 5 are not possible.
BIT is only unsigned, thus only uint5|6|7 macroses exist
*/
case 4:lval = (my_int64) sint4korr(*row);break;
case 3:lval = (my_int64) sint3korr(*row);break;
case 2:lval = (my_int64) sint2korr(*row);break;
case 1:lval = (my_int64) *(my_int8*)*row;break;
}
#if SIZEOF_LONG==4
if ((L64(2147483647) < (my_int64) lval) || (L64(-2147483648) > (my_int64) lval)) {
tmp_len = sprintf((char *)&tmp, MYSQLND_LL_SPEC, lval);
} else
#endif /* SIZEOF */
{
ZVAL_LONG(zv, lval);
}
}
if (tmp_len) {
#if PHP_MAJOR_VERSION >= 6
if (as_unicode) {
ZVAL_UTF8_STRINGL(zv, tmp, tmp_len, ZSTR_DUPLICATE);
} else
#endif
{
ZVAL_STRINGL(zv, tmp, tmp_len, 1);
}
}
(*row)+= byte_count;
}
/* }}} */
/* {{{ ps_fetch_null */
static
void ps_fetch_null(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
ZVAL_NULL(zv);
}
/* }}} */
/* {{{ ps_fetch_int8 */
static
void ps_fetch_int8(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 1 TSRMLS_CC);
#if 0
if (field->flags & UNSIGNED_FLAG) {
ZVAL_LONG(zv, *(my_uint8*)*row);
} else {
ZVAL_LONG(zv, *(my_int8*)*row);
}
(*row)++;
#endif
}
/* }}} */
/* {{{ ps_fetch_int16 */
static
void ps_fetch_int16(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 2 TSRMLS_CC);
#if 0
if (field->flags & UNSIGNED_FLAG) {
ZVAL_LONG(zv, (my_uint16) sint2korr(*row));
} else {
ZVAL_LONG(zv, (my_int16) sint2korr(*row));
}
(*row)+= 2;
#endif
}
/* }}} */
/* {{{ ps_fetch_int32 */
static
void ps_fetch_int32(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 4 TSRMLS_CC);
#if 0
if (field->flags & UNSIGNED_FLAG) {
my_uint32 uval;
/* unsigned int (11) */
uval= (my_uint32) sint4korr(*row);
#if SIZEOF_LONG==4
if (uval > INT_MAX) {
char *tmp, *p;
int j=10;
tmp= mnd_emalloc(11);
p= &tmp[9];
do {
*p-- = (uval % 10) + 48;
uval = uval / 10;
} while (--j > 0);
tmp[10]= '\0';
/* unsigned int > INT_MAX is 10 digits - ALWAYS */
#if PHP_MAJOR_VERSION >= 6
if (!as_unicode) {
#endif
ZVAL_STRING(zv, tmp, 0);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, tmp, 10, ZSTR_AUTOFREE);
}
#endif /* PHP_MAJOR_VERSION >= 6 */
} else
#endif /* #if SIZEOF_LONG==4 */
{
ZVAL_LONG(zv, uval);
}
} else {
ZVAL_LONG(zv, (my_int32) sint4korr(*row));
}
(*row)+= 4;
#endif /* 0 */
}
/* }}} */
/* {{{ ps_fetch_int64 */
static
void ps_fetch_int64(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, 8 TSRMLS_CC);
#if 0
my_uint64 llval = (my_uint64) sint8korr(*row);
zend_bool uns = field->flags & UNSIGNED_FLAG? TRUE:FALSE;
#if SIZEOF_LONG==8
if (uns == TRUE && llval > 9223372036854775807L) {
#elif SIZEOF_LONG==4
if ((uns == TRUE && llval > L64(2147483647)) ||
(uns == FALSE && ((L64( 2147483647) < (my_int64) llval) ||
(L64(-2147483648) > (my_int64) llval))))
{
#endif
char tmp[22];
/* even though lval is declared as unsigned, the value
* may be negative. Therefor we cannot use MYSQLND_LLU_SPEC and must
* use MYSQLND_LL_SPEC.
*/
sprintf((char *)&tmp, uns == TRUE? MYSQLND_LLU_SPEC : MYSQLND_LL_SPEC, llval);
#if PHP_MAJOR_VERSION >= 6
if (!as_unicode) {
#endif
ZVAL_STRING(zv, tmp, 1);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRING(zv, tmp, ZSTR_DUPLICATE);
}
#endif
} else {
/* This cast is safe, as we have checked the values above */
ZVAL_LONG(zv, (long) llval);
}
(*row)+= 8;
#endif /* 0 */
}
/* }}} */
/* {{{ ps_fetch_float */
static
void ps_fetch_float(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
float value;
float4get(value, *row);
ZVAL_DOUBLE(zv, value);
(*row)+= 4;
}
/* }}} */
/* {{{ ps_fetch_double */
static
void ps_fetch_double(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
double value;
float8get(value, *row);
ZVAL_DOUBLE(zv, value);
(*row)+= 8;
}
/* }}} */
/* {{{ ps_fetch_time */
static
void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
struct st_mysqlnd_time t;
unsigned int length; /* First byte encodes the length*/
char *to;
if ((length = php_mysqlnd_net_field_length(row))) {
zend_uchar *to= *row;
t.time_type = MYSQLND_TIMESTAMP_TIME;
t.neg = (zend_bool) to[0];
t.day = (unsigned long) sint4korr(to+1);
t.hour = (unsigned int) to[5];
t.minute = (unsigned int) to[6];
t.second = (unsigned int) to[7];
t.second_part = (length > 8) ? (unsigned long) sint4korr(to+8) : 0;
t.year = t.month= 0;
if (t.day) {
/* Convert days to hours at once */
t.hour += t.day*24;
t.day = 0;
}
(*row) += length;
} else {
memset(&t, 0, sizeof(t));
t.time_type = MYSQLND_TIMESTAMP_TIME;
}
/*
QQ : How to make this unicode without copying two times the buffer -
Unicode equivalent of spprintf?
*/
length = spprintf(&to, 0, "%s%02u:%02u:%02u",
(t.neg ? "-" : ""), t.hour, t.minute, t.second);
#if PHP_MAJOR_VERSION >= 6
if (!as_unicode) {
#endif
ZVAL_STRINGL(zv, to, length, 1);
mnd_efree(to);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
}
#endif
}
/* }}} */
/* {{{ ps_fetch_date */
static
void ps_fetch_date(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
struct st_mysqlnd_time t = {0};
unsigned int length; /* First byte encodes the length*/
char *to;
if ((length = php_mysqlnd_net_field_length(row))) {
zend_uchar *to= *row;
t.time_type= MYSQLND_TIMESTAMP_DATE;
t.neg= 0;
t.second_part = t.hour = t.minute = t.second = 0;
t.year = (unsigned int) sint2korr(to);
t.month = (unsigned int) to[2];
t.day = (unsigned int) to[3];
(*row)+= length;
} else {
memset(&t, 0, sizeof(t));
t.time_type = MYSQLND_TIMESTAMP_DATE;
}
/*
QQ : How to make this unicode without copying two times the buffer -
Unicode equivalent of spprintf?
*/
length = spprintf(&to, 0, "%04u-%02u-%02u", t.year, t.month, t.day);
#if PHP_MAJOR_VERSION >= 6
if (!as_unicode) {
#endif
ZVAL_STRINGL(zv, to, length, 1);
mnd_efree(to);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
}
#endif
}
/* }}} */
/* {{{ ps_fetch_datetime */
static
void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
struct st_mysqlnd_time t;
unsigned int length; /* First byte encodes the length*/
char *to;
if ((length = php_mysqlnd_net_field_length(row))) {
zend_uchar *to= *row;
t.time_type = MYSQLND_TIMESTAMP_DATETIME;
t.neg = 0;
t.year = (unsigned int) sint2korr(to);
t.month = (unsigned int) to[2];
t.day = (unsigned int) to[3];
if (length > 4) {
t.hour = (unsigned int) to[4];
t.minute = (unsigned int) to[5];
t.second = (unsigned int) to[6];
} else {
t.hour = t.minute = t.second= 0;
}
t.second_part = (length > 7) ? (unsigned long) sint4korr(to+7) : 0;
(*row)+= length;
} else {
memset(&t, 0, sizeof(t));
t.time_type = MYSQLND_TIMESTAMP_DATETIME;
}
/*
QQ : How to make this unicode without copying two times the buffer -
Unicode equivalent of spprintf?
*/
length = spprintf(&to, 0, "%04u-%02u-%02u %02u:%02u:%02u",
t.year, t.month, t.day, t.hour, t.minute, t.second);
#if PHP_MAJOR_VERSION >= 6
if (!as_unicode) {
#endif
ZVAL_STRINGL(zv, to, length, 1);
mnd_efree(to);
#if PHP_MAJOR_VERSION >= 6
} else {
ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE);
}
#endif
}
/* }}} */
/* {{{ ps_fetch_string */
static
void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
/*
For now just copy, before we make it possible
to write \0 to the row buffer
*/
unsigned long length= php_mysqlnd_net_field_length(row);
#if PHP_MAJOR_VERSION < 6
ZVAL_STRINGL(zv, (char *)*row, length, 1);
#else
if (field->charsetnr == MYSQLND_BINARY_CHARSET_NR) {
ZVAL_STRINGL(zv, (char *)*row, length, 1);
} else {
ZVAL_UTF8_STRINGL(zv, (char*)*row, length, ZSTR_DUPLICATE);
}
#endif
(*row) += length;
}
/* }}} */
/* {{{ ps_fetch_bit */
static
void ps_fetch_bit(zval *zv, const MYSQLND_FIELD * const field,
uint pack_len, zend_uchar **row,
zend_bool as_unicode TSRMLS_DC)
{
unsigned long length= php_mysqlnd_net_field_length(row);
ps_fetch_from_1_to_8_bytes(zv, field, pack_len, row, as_unicode, length TSRMLS_CC);
}
/* }}} */
/* {{{ _mysqlnd_init_ps_subsystem */
void _mysqlnd_init_ps_subsystem()
{
memset(mysqlnd_ps_fetch_functions, 0, sizeof(mysqlnd_ps_fetch_functions));
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].func = ps_fetch_null;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].pack_len = 0;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].php_type = IS_NULL;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NULL].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].func = ps_fetch_int8;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].pack_len = 1;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].func = ps_fetch_int16;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].pack_len = 2;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SHORT].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].func = ps_fetch_int16;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].pack_len = 2;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_YEAR].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].func = ps_fetch_int32;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].pack_len = 4;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_INT24].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].func = ps_fetch_int32;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].pack_len = 4;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].func = ps_fetch_int64;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].pack_len= 8;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONGLONG].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].func = ps_fetch_float;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].pack_len = 4;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].php_type = IS_DOUBLE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_FLOAT].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].func = ps_fetch_double;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].pack_len = 8;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].php_type = IS_DOUBLE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DOUBLE].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].func = ps_fetch_time;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIME].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].func = ps_fetch_date;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATE].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].func = ps_fetch_date;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].pack_len = MYSQLND_PS_SKIP_RESULT_W_LEN;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDATE].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].func = ps_fetch_datetime;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].php_type= IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DATETIME].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].func = ps_fetch_datetime;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].pack_len= MYSQLND_PS_SKIP_RESULT_W_LEN;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].php_type= IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TIMESTAMP].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_TINY_BLOB].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BLOB].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].php_type= IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_MEDIUM_BLOB].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_LONG_BLOB].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].func = ps_fetch_bit;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].pack_len = 8;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].php_type = IS_LONG;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_BIT].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VAR_STRING].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_VARCHAR].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_STRING].is_possibly_blob = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_DECIMAL].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_NEWDECIMAL].can_ret_as_str_in_uni = TRUE;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_ENUM].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].pack_len = MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_SET].php_type = IS_STRING;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].func = ps_fetch_string;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].pack_len= MYSQLND_PS_SKIP_RESULT_STR;
mysqlnd_ps_fetch_functions[MYSQL_TYPE_GEOMETRY].php_type= IS_STRING;
}
/* }}} */
/* {{{ mysqlnd_stmt_execute_store_params */
void
mysqlnd_stmt_execute_store_params(MYSQLND_STMT *stmt, zend_uchar **buf, zend_uchar **p,
size_t *buf_len, unsigned int null_byte_offset TSRMLS_DC)
{
unsigned int i = 0;
unsigned left = (*buf_len - (*p - *buf));
unsigned int data_size = 0;
/* 1. Store type information */
if (stmt->send_types_to_server) {
/* 2 bytes per type, and leave 20 bytes for future use */
if (left < ((stmt->param_count * 2) + 20)) {
unsigned int offset = *p - *buf;
zend_uchar *tmp_buf;
*buf_len = offset + stmt->param_count * 2 + 20;
tmp_buf = mnd_emalloc(*buf_len);
memcpy(tmp_buf, *buf, offset);
*buf = tmp_buf;
/* Update our pos pointer */
*p = *buf + offset;
}
for (i = 0; i < stmt->param_count; i++) {
/* our types are not unsigned */
#if SIZEOF_LONG==8
if (stmt->param_bind[i].type == MYSQL_TYPE_LONG) {
stmt->param_bind[i].type = MYSQL_TYPE_LONGLONG;
}
#endif
int2store(*p, stmt->param_bind[i].type);
*p+= 2;
}
}
/* 2. Store data */
/* 2.1 Calculate how much space we need */
for (i = 0; i < stmt->param_count; i++) {
if (stmt->param_bind[i].zv &&
Z_TYPE_P(stmt->param_bind[i].zv) == IS_NULL) {
continue;
}
switch (stmt->param_bind[i].type) {
case MYSQL_TYPE_DOUBLE:
data_size += 8;
break;
#if SIZEOF_LONG==8
case MYSQL_TYPE_LONGLONG:
data_size += 8;
break;
#elif SIZEOF_LONG==4
case MYSQL_TYPE_LONG:
data_size += 4;
break;
#else
#error "Should not happen"
#endif
case MYSQL_TYPE_LONG_BLOB:
if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) {
/*
User hasn't sent anything, we will send empty string.
Empty string has length of 0, encoded in 1 byte. No real
data will follow after it.
*/
data_size++;
}
break;
case MYSQL_TYPE_VAR_STRING:
data_size += 8; /* max 8 bytes for size */
convert_to_string_ex(&stmt->param_bind[i].zv);
data_size += Z_STRLEN_P(stmt->param_bind[i].zv);
break;
}
}
/* 2.2 Enlarge the buffer, if needed */
left = (*buf_len - (*p - *buf));
if (left < data_size) {
unsigned int offset = *p - *buf;
zend_uchar *tmp_buf;
*buf_len = offset + data_size + 10; /* Allocate + 10 for safety */
tmp_buf = mnd_emalloc(*buf_len);
memcpy(tmp_buf, *buf, offset);
*buf = tmp_buf;
/* Update our pos pointer */
*p = *buf + offset;
}
/* 2.3 Store the actual data */
for (i = 0; i < stmt->param_count; i++) {
zval *data = stmt->param_bind[i].zv;
/* Handle long data */
if (stmt->param_bind[i].zv && Z_TYPE_P(data) == IS_NULL) {
(*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
} else {
switch (stmt->param_bind[i].type) {
case MYSQL_TYPE_DOUBLE:
convert_to_double_ex(&data);
float8store(*p, Z_DVAL_P(data));
(*p) += 8;
break;
#if SIZEOF_LONG==8
case MYSQL_TYPE_LONGLONG:
convert_to_long_ex(&data);
int8store(*p, Z_LVAL_P(data));
(*p) += 8;
break;
#elif SIZEOF_LONG==4
case MYSQL_TYPE_LONG:
convert_to_long_ex(&data);
int4store(*p, Z_LVAL_P(data));
(*p) += 4;
break;
#else
#error "Should not happen"
#endif
case MYSQL_TYPE_LONG_BLOB:
if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
} else {
/* send_long_data() not called, send empty string */
*p = php_mysqlnd_net_store_length(*p, 0);
}
break;
case MYSQL_TYPE_VAR_STRING:
/*
If the user uses refs, it could be that the type has
has changed and we need to convert, again. Which is noop,
if the type hasn't changed.
*/
convert_to_string_ex(&stmt->param_bind[i].zv);
{
unsigned int len = Z_STRLEN_P(data);
/* to is after p. The latter hasn't been moved */
*p = php_mysqlnd_net_store_length(*p, len);
memcpy(*p, Z_STRVAL_P(data), len);
(*p) += len;
}
break;
default:
/* Won't happen, but set to NULL */
(*buf + null_byte_offset)[i/8] |= (zend_uchar) (1 << (i & 7));
break;
}
}
}
}
/* }}} */
/* {{{ mysqlnd_stmt_execute_generate_request */
zend_uchar* mysqlnd_stmt_execute_generate_request(MYSQLND_STMT *stmt, size_t *request_len,
zend_bool *free_buffer TSRMLS_DC)
{
zend_uchar *p = stmt->cmd_buffer.buffer,
*cmd_buffer = stmt->cmd_buffer.buffer;
size_t cmd_buffer_length = stmt->cmd_buffer.length;
unsigned int null_byte_offset,
null_count= (stmt->param_count + 7) / 8;
int4store(p, stmt->stmt_id);
p += 4;
/* flags is 4 bytes, we store just 1 */
int1store(p, (zend_uchar) stmt->flags);
p++;
/* Make it all zero */
int4store(p, 0);
int1store(p, 1); /* and send 1 for iteration count */
p+= 4;
null_byte_offset = p - cmd_buffer;
memset(p, 0, null_count);
p += null_count;
int1store(p, stmt->send_types_to_server);
p++;
mysqlnd_stmt_execute_store_params(stmt, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC);
*free_buffer = (cmd_buffer != stmt->cmd_buffer.buffer);
*request_len = (p - cmd_buffer);
return cmd_buffer;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,141 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_statistics.h"
#define MYSQLND_SILENT
#ifdef ZTS
#define LOCK_QCACHE(cache) tsrm_mutex_lock((cache)->LOCK_access)
#define UNLOCK_QCACHE(cache) tsrm_mutex_unlock((cache)->LOCK_access)
#else
#define LOCK_QCACHE(cache)
#define UNLOCK_QCACHE(cache)
#endif
/* {{{ mysqlnd_qcache_init_cache */
PHPAPI MYSQLND_QCACHE * mysqlnd_qcache_init_cache()
{
MYSQLND_QCACHE *cache = calloc(1, sizeof(MYSQLND_QCACHE));
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_qcache_init_cache %p]\n", cache);
#endif
cache->references = 1;
#ifdef ZTS
cache->LOCK_access = tsrm_mutex_alloc();
#endif
cache->ht = malloc(sizeof(HashTable));
zend_hash_init(cache->ht, 10 /* init_elements */, NULL, NULL, TRUE /*pers*/);
return cache;
}
/* }}} */
/* {{{ mysqlnd_qcache_get_cache_reference */
PHPAPI MYSQLND_QCACHE * mysqlnd_qcache_get_cache_reference(MYSQLND_QCACHE * const cache)
{
if (cache) {
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_qcache_get_cache_reference %p will become %d]\n", cache, cache->references+1);
#endif
LOCK_QCACHE(cache);
cache->references++;
UNLOCK_QCACHE(cache);
}
return cache;
}
/* }}} */
/* {{{ mysqlnd_qcache_free_cache */
/*
As this call will happen on MSHUTDOWN(), then we don't need to copy the zvals with
copy_ctor but scrap what they point to with zval_dtor() and then just free our
pre-allocated block. Precondition is that we ZVAL_NULL() the zvals when we put them
to the free list after usage. We ZVAL_NULL() them when we allocate them in the
constructor of the cache.
*/
static
void mysqlnd_qcache_free_cache(MYSQLND_QCACHE *cache)
{
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_qcache_free_cache %p]\n", cache);
#endif
#ifdef ZTS
tsrm_mutex_free(cache->LOCK_access);
#endif
zend_hash_destroy(cache->ht);
free(cache->ht);
free(cache);
}
/* }}} */
/* {{{ mysqlnd_qcache_free_cache_reference */
PHPAPI void mysqlnd_qcache_free_cache_reference(MYSQLND_QCACHE **cache)
{
if (*cache) {
zend_bool to_free;
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_qcache_free_cache_reference %p] refs=%d\n", *cache, (*cache)->references);
#endif
LOCK_QCACHE(*cache);
to_free = --(*cache)->references == 0;
/* Unlock before destroying */
UNLOCK_QCACHE(*cache);
if (to_free) {
mysqlnd_qcache_free_cache(*cache);
}
*cache = NULL;
}
}
/* }}} */
/* {{{ mysqlnd_qcache_free_cache_reference */
PHPAPI void mysqlnd_qcache_stats(const MYSQLND_QCACHE * const cache, zval *return_value)
{
if (cache) {
LOCK_QCACHE(cache);
array_init(return_value);
add_assoc_long_ex(return_value, "references", sizeof("references"), cache->references);
UNLOCK_QCACHE(cache);
} else {
ZVAL_NULL(return_value);
}
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

1194
ext/mysqlnd/mysqlnd_result.c Normal file

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,48 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_RESULT_H
#define MYSQLND_RESULT_H
MYSQLND_RES *mysqlnd_result_init(unsigned int field_count, MYSQLND_THD_ZVAL_PCACHE *cache TSRMLS_DC);
void mysqlnd_unbuffered_free_last_data(MYSQLND_RES *result TSRMLS_DC);
enum_func_status
mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
MYSQLND_RES_METADATA *meta,
zend_bool binary_protocol,
zend_bool update_max_length,
zend_bool to_cache TSRMLS_DC);
enum_func_status mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT *stmt TSRMLS_DC);
#endif /* MYSQLND_RESULT_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,440 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_result.h"
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_debug.h"
#include "ext/standard/basic_functions.h"
/* {{{ php_mysqlnd_free_field_metadata */
static
void php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent TSRMLS_DC)
{
if (meta) {
if (meta->root) {
mnd_pefree(meta->root, persistent);
meta->root = NULL;
}
if (meta->def) {
mnd_pefree(meta->def, persistent);
meta->def = NULL;
}
}
}
/* }}} */
/* {{{ mysqlnd_handle_numeric */
/*
The following code is stolen from ZE - HANDLE_NUMERIC() macro from zend_hash.c
and modified for the needs of mysqlnd.
*/
static
zend_bool mysqlnd_is_key_numeric(char *key, size_t length, long *idx)
{
register char *tmp=key;
if (*tmp=='-') {
tmp++;
}
if ((*tmp>='0' && *tmp<='9')) {
do { /* possibly a numeric index */
char *end=key+length-1;
if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */
break;
}
while (tmp<end) {
if (!(*tmp>='0' && *tmp<='9')) {
break;
}
tmp++;
}
if (tmp==end && *tmp=='\0') { /* a numeric index */
if (*key=='-') {
*idx = strtol(key, NULL, 10);
if (*idx!=LONG_MIN) {
return TRUE;
}
} else {
*idx = strtol(key, NULL, 10);
if (*idx!=LONG_MAX) {
return TRUE;
}
}
}
} while (0);
}
return FALSE;
}
/* }}} */
#if PHP_MAJOR_VERSION >= 6
/* {{{ mysqlnd_unicode_is_key_numeric */
static
zend_bool mysqlnd_unicode_is_key_numeric(UChar *key, size_t length, long *idx)
{
register UChar *tmp=key;
if (*tmp==0x2D /*'-'*/) {
tmp++;
}
if ((*tmp>=0x30 /*'0'*/ && *tmp<=0x39 /*'9'*/)) { /* possibly a numeric index */
do {
UChar *end=key+length-1;
if (*tmp++==0x30 && length>2) { /* don't accept numbers with leading zeros */
break;
}
while (tmp<end) {
if (!(*tmp>=0x30 /*'0'*/ && *tmp<=0x39 /*'9'*/)) {
break;
}
tmp++;
}
if (tmp==end && *tmp==0) { /* a numeric index */
if (*key==0x2D /*'-'*/) {
*idx = zend_u_strtol(key, NULL, 10);
if (*idx!=LONG_MIN) {
return TRUE;
}
} else {
*idx = zend_u_strtol(key, NULL, 10);
if (*idx!=LONG_MAX) {
return TRUE;
}
}
}
} while (0);
}
return FALSE;
}
/* }}} */
#endif
/* {{{ mysqlnd_res_meta::read_metadata */
static enum_func_status
MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const meta,
MYSQLND *conn TSRMLS_DC)
{
int i = 0;
php_mysql_packet_res_field field_packet;
DBG_ENTER("mysqlnd_res_meta::read_metadata");
PACKET_INIT_ALLOCA(field_packet, PROT_RSET_FLD_PACKET);
for (;i < meta->field_count; i++) {
long idx;
if (meta->fields[i].root) {
/* We re-read metadata for PS */
mnd_efree(meta->fields[i].root);
meta->fields[i].root = NULL;
}
field_packet.metadata = &(meta->fields[i]);
if (FAIL == PACKET_READ_ALLOCA(field_packet, conn)) {
PACKET_FREE_ALLOCA(field_packet);
DBG_RETURN(FAIL);
}
if (field_packet.stupid_list_fields_eof == TRUE) {
break;
}
if (mysqlnd_ps_fetch_functions[meta->fields[i].type].func == NULL) {
DBG_ERR_FMT("Unknown type %d sent by the server. Please send a report to the developers",
meta->fields[i].type);
php_error_docref(NULL TSRMLS_CC, E_WARNING,
"Unknown type %d sent by the server. "
"Please send a report to the developers",
meta->fields[i].type);
PACKET_FREE_ALLOCA(field_packet);
DBG_RETURN(FAIL);
}
if (meta->fields[i].type == MYSQL_TYPE_BIT) {
size_t field_len;
DBG_INF("BIT");
++meta->bit_fields_count;
/* .length is in bits */
field_len = meta->fields[i].length / 8;
/*
If there is rest, add one byte :
8 bits = 1 byte but 9 bits = 2 bytes
*/
if (meta->fields[i].length % 8) {
++field_len;
}
switch (field_len) {
case 8:
case 7:
case 6:
case 5:
meta->bit_fields_total_len += 20;/* 21 digis, no sign*/
break;
case 4:
meta->bit_fields_total_len += 10;/* 2 000 000 000*/
break;
case 3:
meta->bit_fields_total_len += 8;/* 12 000 000*/
break;
case 2:
meta->bit_fields_total_len += 5;/* 32 500 */
break;
case 1:
meta->bit_fields_total_len += 3;/* 120 */
break;
}
}
#if PHP_MAJOR_VERSION >= 6
if (UG(unicode)) {
UChar *ustr;
int ulen;
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen,
meta->fields[i].name,
meta->fields[i].name_length TSRMLS_CC);
if ((meta->zend_hash_keys[i].is_numeric =
mysqlnd_unicode_is_key_numeric(ustr, ulen + 1, &idx)))
{
meta->zend_hash_keys[i].key = idx;
mnd_efree(ustr);
} else {
meta->zend_hash_keys[i].ustr.u = ustr;
meta->zend_hash_keys[i].ulen = ulen;
meta->zend_hash_keys[i].key = zend_u_get_hash_value(IS_UNICODE, ZSTR(ustr), ulen + 1);
}
} else
#endif
{
/* For BC we have to check whether the key is numeric and use it like this */
if ((meta->zend_hash_keys[i].is_numeric =
mysqlnd_is_key_numeric(field_packet.metadata->name,
field_packet.metadata->name_length + 1,
&idx)))
{
meta->zend_hash_keys[i].key = idx;
} else {
meta->zend_hash_keys[i].key =
zend_get_hash_value(field_packet.metadata->name,
field_packet.metadata->name_length + 1);
}
}
}
PACKET_FREE_ALLOCA(field_packet);
DBG_RETURN(PASS);
}
/* }}} */
/* {{{ mysqlnd_res_meta::free */
static void
MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA *meta, zend_bool persistent TSRMLS_DC)
{
int i;
MYSQLND_FIELD *fields;
DBG_ENTER("mysqlnd_res_meta::free");
DBG_INF_FMT("persistent=%d", persistent);
if ((fields = meta->fields)) {
DBG_INF("Freeing fields metadata");
i = meta->field_count;
while (i--) {
php_mysqlnd_free_field_metadata(fields++, persistent TSRMLS_CC);
}
mnd_pefree(meta->fields, persistent);
meta->fields = NULL;
}
if (meta->zend_hash_keys) {
DBG_INF("Freeing zend_hash_keys");
#if PHP_MAJOR_VERSION >= 6
if (UG(unicode)) {
for (i = 0; i < meta->field_count; i++) {
if (meta->zend_hash_keys[i].ustr.v) {
mnd_pefree(meta->zend_hash_keys[i].ustr.v, persistent);
}
}
}
#endif
mnd_pefree(meta->zend_hash_keys, persistent);
meta->zend_hash_keys = NULL;
}
DBG_INF("Freeing metadata structure");
mnd_pefree(meta, persistent);
DBG_VOID_RETURN;
}
/* }}} */
/* {{{ mysqlnd_res::clone_metadata */
static MYSQLND_RES_METADATA *
MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * const meta,
zend_bool persistent TSRMLS_DC)
{
unsigned int i;
/* +1 is to have empty marker at the end */
MYSQLND_RES_METADATA *new_meta = mnd_pemalloc(sizeof(MYSQLND_RES_METADATA), persistent);
MYSQLND_FIELD *new_fields = mnd_pecalloc(meta->field_count + 1, sizeof(MYSQLND_FIELD), persistent);
MYSQLND_FIELD *orig_fields = meta->fields;
size_t len = meta->field_count * sizeof(struct mysqlnd_field_hash_key);
DBG_ENTER("mysqlnd_res_meta::clone_metadata");
DBG_INF_FMT("persistent=%d", persistent);
new_meta->zend_hash_keys = mnd_pemalloc(len, persistent);
memcpy(new_meta->zend_hash_keys, meta->zend_hash_keys, len);
new_meta->m = meta->m;
/*
This will copy also the strings and the root, which we will have
to adjust in the loop
*/
memcpy(new_fields, orig_fields, (meta->field_count) * sizeof(MYSQLND_FIELD));
for (i = 0; i < meta->field_count; i++) {
/* First copy the root, then field by field adjust the pointers */
new_fields[i].root = mnd_pemalloc(orig_fields[i].root_len, persistent);
memcpy(new_fields[i].root, orig_fields[i].root, new_fields[i].root_len);
if (orig_fields[i].name && orig_fields[i].name != mysqlnd_empty_string) {
new_fields[i].name = new_fields[i].root +
(orig_fields[i].name - orig_fields[i].root);
}
if (orig_fields[i].org_name && orig_fields[i].org_name != mysqlnd_empty_string) {
new_fields[i].org_name = new_fields[i].root +
(orig_fields[i].org_name - orig_fields[i].root);
}
if (orig_fields[i].table && orig_fields[i].table != mysqlnd_empty_string) {
new_fields[i].table = new_fields[i].root +
(orig_fields[i].table - orig_fields[i].root);
}
if (orig_fields[i].org_table && orig_fields[i].org_table != mysqlnd_empty_string) {
new_fields[i].org_table = new_fields[i].root +
(orig_fields[i].org_table - orig_fields[i].root);
}
if (orig_fields[i].db && orig_fields[i].db != mysqlnd_empty_string) {
new_fields[i].db = new_fields[i].root + (orig_fields[i].db - orig_fields[i].root);
}
if (orig_fields[i].catalog && orig_fields[i].catalog != mysqlnd_empty_string) {
new_fields[i].catalog = new_fields[i].root + (orig_fields[i].catalog - orig_fields[i].root);
}
/* def is not on the root, if allocated at all */
if (orig_fields[i].def) {
new_fields[i].def = mnd_pemalloc(orig_fields[i].def_length + 1, persistent);
/* copy the trailing \0 too */
memcpy(new_fields[i].def, orig_fields[i].def, orig_fields[i].def_length + 1);
}
#if PHP_MAJOR_VERSION >= 6
if (new_meta->zend_hash_keys[i].ustr.u) {
new_meta->zend_hash_keys[i].ustr.u =
eustrndup(new_meta->zend_hash_keys[i].ustr.u, new_meta->zend_hash_keys[i].ulen);
}
#endif
}
new_meta->current_field = 0;
new_meta->field_count = meta->field_count;
new_meta->fields = new_fields;
DBG_RETURN(new_meta);
}
/* }}} */
/* {{{ mysqlnd_res_meta::fetch_field */
static MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res_meta, fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res_meta::fetch_field");
if (meta->current_field >= meta->field_count) {
DBG_RETURN(NULL);
}
DBG_RETURN(&meta->fields[meta->current_field++]);
}
/* }}} */
/* {{{ mysqlnd_res_meta::fetch_field_direct */
static MYSQLND_FIELD *
MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct)(const MYSQLND_RES_METADATA * const meta,
MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC)
{
DBG_ENTER("mysqlnd_res_meta::fetch_field_direct");
DBG_INF_FMT("fieldnr=%d", fieldnr);
DBG_RETURN(&meta->fields[fieldnr]);
}
/* }}} */
/* {{{ mysqlnd_res_meta::field_tell */
static MYSQLND_FIELD_OFFSET
MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const meta)
{
return meta->current_field;
}
/* }}} */
MYSQLND_CLASS_METHODS_START(mysqlnd_res_meta)
MYSQLND_METHOD(mysqlnd_res_meta, fetch_field),
MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct),
MYSQLND_METHOD(mysqlnd_res_meta, field_tell),
MYSQLND_METHOD(mysqlnd_res_meta, read_metadata),
MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata),
MYSQLND_METHOD(mysqlnd_res_meta, free),
MYSQLND_CLASS_METHODS_END;
/* {{{ mysqlnd_result_meta_init */
MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count TSRMLS_DC)
{
MYSQLND_RES_METADATA *ret;
DBG_ENTER("mysqlnd_result_meta_init");
/* +1 is to have empty marker at the end */
ret = mnd_ecalloc(1, sizeof(MYSQLND_RES_METADATA));
ret->field_count = field_count;
ret->fields = ecalloc(field_count + 1, sizeof(MYSQLND_FIELD));
ret->zend_hash_keys = ecalloc(field_count, sizeof(struct mysqlnd_field_hash_key));
ret->m = & mysqlnd_mysqlnd_res_meta_methods;
DBG_INF_FMT("meta=%p", ret);
DBG_RETURN(ret);
}
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,40 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_RESULT_META_H
#define MYSQLND_RESULT_META_H
MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count TSRMLS_DC);
#endif /* MYSQLND_RESULT_META_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,155 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#include "php.h"
#include "mysqlnd.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_statistics.h"
#include "mysqlnd_debug.h"
#define STR_W_LEN(str) str, (sizeof(str) - 1)
/* {{{ mysqlnd_stats_values_names
*/
const MYSQLND_STRING mysqlnd_stats_values_names[STAT_LAST] =
{
{ STR_W_LEN("bytes_sent") },
{ STR_W_LEN("bytes_received") },
{ STR_W_LEN("packets_sent") },
{ STR_W_LEN("packets_received") },
{ STR_W_LEN("protocol_overhead_in") },
{ STR_W_LEN("protocol_overhead_out") },
{ STR_W_LEN("result_set_queries") },
{ STR_W_LEN("non_result_set_queries") },
{ STR_W_LEN("no_index_used") },
{ STR_W_LEN("bad_index_used") },
{ STR_W_LEN("buffered_sets") },
{ STR_W_LEN("unbuffered_sets") },
{ STR_W_LEN("ps_buffered_sets") },
{ STR_W_LEN("ps_unbuffered_sets") },
{ STR_W_LEN("flushed_normal_sets") },
{ STR_W_LEN("flushed_ps_sets") },
{ STR_W_LEN("ps_prepared_never_executed") },
{ STR_W_LEN("ps_prepared_once_executed") },
{ STR_W_LEN("rows_fetched_from_server_normal") },
{ STR_W_LEN("rows_fetched_from_server_ps") },
{ STR_W_LEN("rows_buffered_from_client_normal") },
{ STR_W_LEN("rows_buffered_from_client_ps") },
{ STR_W_LEN("rows_fetched_from_client_normal_buffered") },
{ STR_W_LEN("rows_fetched_from_client_normal_unbuffered") },
{ STR_W_LEN("rows_fetched_from_client_ps_buffered") },
{ STR_W_LEN("rows_fetched_from_client_ps_unbuffered") },
{ STR_W_LEN("rows_fetched_from_client_ps_cursor") },
{ STR_W_LEN("rows_skipped_normal") },
{ STR_W_LEN("rows_skipped_ps") },
{ STR_W_LEN("copy_on_write_saved") },
{ STR_W_LEN("copy_on_write_performed") },
{ STR_W_LEN("command_buffer_too_small") },
{ STR_W_LEN("connect_success") },
{ STR_W_LEN("connect_failure") },
{ STR_W_LEN("connection_reused") },
{ STR_W_LEN("reconnect") },
{ STR_W_LEN("pconnect_success") },
{ STR_W_LEN("active_connections") },
{ STR_W_LEN("active_persistent_connections") },
{ STR_W_LEN("explicit_close") },
{ STR_W_LEN("implicit_close") },
{ STR_W_LEN("disconnect_close") },
{ STR_W_LEN("in_middle_of_command_close") },
{ STR_W_LEN("explicit_free_result") },
{ STR_W_LEN("implicit_free_result") },
{ STR_W_LEN("explicit_stmt_close") },
{ STR_W_LEN("implicit_stmt_close") },
{ STR_W_LEN("mem_emalloc_count") },
{ STR_W_LEN("mem_emalloc_ammount") },
{ STR_W_LEN("mem_ecalloc_count") },
{ STR_W_LEN("mem_ecalloc_ammount") },
{ STR_W_LEN("mem_erealloc_count") },
{ STR_W_LEN("mem_erealloc_ammount") },
{ STR_W_LEN("mem_efree_count") },
{ STR_W_LEN("mem_malloc_count") },
{ STR_W_LEN("mem_malloc_ammount") },
{ STR_W_LEN("mem_calloc_count") },
{ STR_W_LEN("mem_calloc_ammount") },
{ STR_W_LEN("mem_realloc_calloc") },
{ STR_W_LEN("mem_realloc_ammount") },
{ STR_W_LEN("mem_free_count") }
};
/* }}} */
/* {{{ mysqlnd_fill_stats_hash */
void
mysqlnd_fill_stats_hash(const MYSQLND_STATS * const stats, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
{
unsigned int i;
mysqlnd_array_init(return_value, STAT_LAST);
for (i = 0; i < STAT_LAST; i++) {
char tmp[22];
sprintf((char *)&tmp, MYSQLND_LLU_SPEC, stats->values[i]);
#if PHP_MAJOR_VERSION >= 6
if (UG(unicode)) {
UChar *ustr, *tstr;
int ulen, tlen;
zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, mysqlnd_stats_values_names[i].s,
mysqlnd_stats_values_names[i].l + 1 TSRMLS_CC);
zend_string_to_unicode(UG(utf8_conv), &tstr, &tlen, tmp, strlen(tmp) + 1 TSRMLS_CC);
add_u_assoc_unicode_ex(return_value, IS_UNICODE, ZSTR(ustr), ulen, tstr, 1);
efree(ustr);
efree(tstr);
} else
#endif
{
add_assoc_string_ex(return_value, mysqlnd_stats_values_names[i].s,
mysqlnd_stats_values_names[i].l + 1, tmp, 1);
}
}
}
/* }}} */
/* {{{ _mysqlnd_get_client_stats */
PHPAPI void _mysqlnd_get_client_stats(zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
{
MYSQLND_STATS stats, *stats_ptr = mysqlnd_global_stats;
DBG_ENTER("_mysqlnd_get_client_stats");
if (!stats_ptr) {
memset(&stats, 0, sizeof(stats));
stats_ptr = &stats;
}
mysqlnd_fill_stats_hash(stats_ptr, return_value TSRMLS_CC ZEND_FILE_LINE_CC);
DBG_VOID_RETURN;
}
/* }}} */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,209 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_STATISTICS_H
#define MYSQLND_STATISTICS_H
extern MYSQLND_STATS *mysqlnd_global_stats;
typedef struct st_mysqlnd_string
{
char *s;
size_t l;
} MYSQLND_STRING;
extern const MYSQLND_STRING mysqlnd_stats_values_names[];
#ifdef ZTS
#define MYSQLND_INC_GLOBAL_STATISTIC(statistic) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
mysqlnd_global_stats->values[(statistic)]++; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
}\
}
#define MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(statistic1, value1, statistic2, value2) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global stats increase w value [%s] [%s]", mysqlnd_stats_values_names[statistic1], mysqlnd_stats_values_names[statistic2]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
mysqlnd_global_stats->values[(statistic1)] += (value1); \
mysqlnd_global_stats->values[(statistic2)] += (value2); \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
}\
}
#define MYSQLND_DEC_CONN_STATISTIC(conn_stats, statistic) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global&conn stat decrease [%s]", mysqlnd_stats_values_names[statistic]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
mysqlnd_global_stats->values[(statistic)]--; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic)]--; \
} \
}\
}
#define MYSQLND_INC_CONN_STATISTIC(conn_stats, statistic) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global&Conn stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
mysqlnd_global_stats->values[(statistic)]++; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic)]++; \
} \
}\
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn_stats, statistic, value) \
{ \
if (MYSQLND_G(collect_statistics)) { \
my_uint64 v = (my_uint64) (value); \
DBG_INF_FMT("Global&Conn stat increase w value [%s]", mysqlnd_stats_values_names[statistic]); \
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
mysqlnd_global_stats->values[(statistic)] += v; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic)]+= v; \
} \
}\
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats, statistic1, value1, statistic2, value2, statistic3, value3) \
{ \
if (MYSQLND_G(collect_statistics)) { \
my_uint64 v1 = (my_uint64) (value1); \
my_uint64 v2 = (my_uint64) (value2); \
my_uint64 v3 = (my_uint64) (value3); \
\
tsrm_mutex_lock(mysqlnd_global_stats->LOCK_access); \
mysqlnd_global_stats->values[(statistic1)]+= v1; \
mysqlnd_global_stats->values[(statistic2)]+= v2; \
mysqlnd_global_stats->values[(statistic3)]+= v3; \
tsrm_mutex_unlock(mysqlnd_global_stats->LOCK_access); \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic1)]+= v1; \
((MYSQLND_STATS *) conn_stats)->values[(statistic2)]+= v2; \
((MYSQLND_STATS *) conn_stats)->values[(statistic3)]+= v3; \
} \
} \
}
#else /* NON-ZTS */
#define MYSQLND_INC_GLOBAL_STATISTIC(statistic) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
mysqlnd_global_stats->values[(statistic)]++; \
} \
}
#define MYSQLND_INC_GLOBAL_STATISTIC2_W_VALUE(statistic1, value1, statistic2, value2) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global stats increase w value [%s] [%s]", \
mysqlnd_stats_values_names[statistic1], mysqlnd_stats_values_names[statistic2]); \
mysqlnd_global_stats->values[(statistic1)] += (value1); \
mysqlnd_global_stats->values[(statistic2)] += (value2); \
}\
}
#define MYSQLND_DEC_CONN_STATISTIC(conn_stats, statistic) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global&Conn stat decrease [%s]", mysqlnd_stats_values_names[statistic]); \
mysqlnd_global_stats->values[(statistic)]--; \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic)]--; \
} \
} \
}
#define MYSQLND_INC_CONN_STATISTIC(conn_stats, statistic) \
{ \
if (MYSQLND_G(collect_statistics)) { \
DBG_INF_FMT("Global&Conn stat increase [%s]", mysqlnd_stats_values_names[statistic]); \
mysqlnd_global_stats->values[(statistic)]++; \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic)]++; \
} \
} \
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn_stats, statistic, value) \
{ \
my_uint64 v = (my_uint64) (value); \
DBG_INF_FMT("Global&Conn stats increase w value [%s]", mysqlnd_stats_values_names[statistic]); \
if (MYSQLND_G(collect_statistics)) { \
mysqlnd_global_stats->values[(statistic)] += v; \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic)] += v; \
} \
} \
}
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE3(conn_stats, statistic1, value1, statistic2, value2, statistic3, value3) \
{ \
if (MYSQLND_G(collect_statistics)) { \
my_uint64 v1 = (my_uint64) (value1); \
my_uint64 v2 = (my_uint64) (value2); \
my_uint64 v3 = (my_uint64) (value3); \
\
mysqlnd_global_stats->values[(statistic1)]+= v1; \
mysqlnd_global_stats->values[(statistic2)]+= v2; \
mysqlnd_global_stats->values[(statistic3)]+= v3; \
if ((conn_stats)) { \
((MYSQLND_STATS *) conn_stats)->values[(statistic1)]+= v1; \
((MYSQLND_STATS *) conn_stats)->values[(statistic2)]+= v2; \
((MYSQLND_STATS *) conn_stats)->values[(statistic3)]+= v3; \
} \
} \
}
#endif
void mysqlnd_fill_stats_hash(const MYSQLND_STATS * const stats, zval *return_value
TSRMLS_DC ZEND_FILE_LINE_DC);
#endif /* MYSQLND_STATISTICS_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

View File

@ -0,0 +1,540 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_STRUCTS_H
#define MYSQLND_STRUCTS_H
typedef struct st_mysqlnd_cmd_buffer
{
zend_uchar *buffer;
size_t length;
} MYSQLND_CMD_BUFFER;
typedef struct st_mysqlnd_field
{
char *name; /* Name of column */
char *org_name; /* Original column name, if an alias */
char *table; /* Table of column if column was a field */
char *org_table; /* Org table name, if table was an alias */
char *db; /* Database for table */
char *catalog; /* Catalog for table */
char *def; /* Default value (set by mysql_list_fields) */
unsigned long length; /* Width of column (create length) */
unsigned long max_length; /* Max width for selected set */
unsigned int name_length;
unsigned int org_name_length;
unsigned int table_length;
unsigned int org_table_length;
unsigned int db_length;
unsigned int catalog_length;
unsigned int def_length;
unsigned int flags; /* Diverse flags */
unsigned int decimals; /* Number of decimals in field */
unsigned int charsetnr; /* Character set */
enum mysqlnd_field_types type; /* Type of field. See mysql_com.h for types */
char *root;
size_t root_len;
} MYSQLND_FIELD;
typedef struct st_mysqlnd_upsert_result
{
unsigned int warning_count;
unsigned int server_status;
mynd_ulonglong affected_rows;
mynd_ulonglong last_insert_id;
} mysqlnd_upsert_status;
typedef struct st_mysqlnd_error_info
{
char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no;
} mysqlnd_error_info;
typedef struct st_mysqlnd_zval_pcache MYSQLND_ZVAL_PCACHE;
typedef struct st_mysqlnd_thread_zval_pcache MYSQLND_THD_ZVAL_PCACHE;
typedef struct st_mysqlnd_qcache MYSQLND_QCACHE;
typedef struct st_mysqlnd_infile_info
{
php_stream *fd;
int error_no;
char error_msg[MYSQLND_ERRMSG_SIZE + 1];
const char *filename;
} MYSQLND_INFILE_INFO;
/* character set information */
typedef struct st_mysqlnd_charset
{
uint nr;
char *name;
char *collation;
uint char_minlen;
uint char_maxlen;
uint dangerous_for_escape_backslash;
uint (*mb_charlen)(uint c);
uint (*mb_valid)(const char *start, const char *end);
} MYSQLND_CHARSET;
/* local infile handler */
typedef struct st_mysqlnd_infile
{
int (*local_infile_init)(void **ptr, char *filename, void **userdata TSRMLS_DC);
int (*local_infile_read)(void *ptr, char *buf, uint buf_len TSRMLS_DC);
int (*local_infile_error)(void *ptr, char *error_msg, uint error_msg_len TSRMLS_DC);
void (*local_infile_end)(void *ptr TSRMLS_DC);
zval *callback;
void *userdata;
} MYSQLND_INFILE;
typedef struct st_mysqlnd_option
{
/* timeouts */
uint timeout_connect;
uint timeout_read;
uint timeout_write;
ulong flags;
/* init commands - we need to send them to server directly after connect */
uint num_commands;
char **init_commands;
/* configuration file information */
char *cfg_file;
char *cfg_section;
/* SSL information */
char *ssl_key;
char *ssl_cert;
char *ssl_ca;
char *ssl_capath;
char *ssl_cipher;
zend_bool use_ssl;
char *charset_name;
/* maximum allowed packet size for communication */
ulong max_allowed_packet;
zend_bool numeric_and_datetime_as_unicode;
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
zend_bool int_and_year_as_int;
#endif
unsigned int net_read_buffer_size;
} MYSQLND_OPTION;
typedef struct st_mysqlnd_connection MYSQLND;
typedef struct st_mysqlnd_res MYSQLND_RES;
typedef char** MYSQLND_ROW; /* return data as array of strings */
typedef struct st_mysqlnd_stmt MYSQLND_STMT;
typedef unsigned int MYSQLND_FIELD_OFFSET;
typedef struct st_mysqlnd_param_bind MYSQLND_PARAM_BIND;
typedef struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND;
typedef struct st_mysqlnd_result_metadata MYSQLND_RES_METADATA;
typedef struct st_mysqlnd_buffered_result MYSQLND_RES_BUFFERED;
typedef struct st_mysqlnd_unbuffered_result MYSQLND_RES_UNBUFFERED;
typedef struct st_mysqlnd_debug MYSQLND_DEBUG;
typedef MYSQLND_RES* (*mysqlnd_stmt_use_or_store_func)(MYSQLND_STMT * const TSRMLS_DC);
typedef enum_func_status (*mysqlnd_fetch_row_func)(MYSQLND_RES *result,
void *param,
unsigned int flags,
zend_bool *fetched_anything
TSRMLS_DC);
typedef struct st_mysqlnd_stats
{
my_uint64 values[STAT_LAST];
#ifdef ZTS
MUTEX_T LOCK_access;
#endif
} MYSQLND_STATS;
typedef struct st_mysqlnd_net
{
php_stream *stream;
/* sequence for simple checking of correct packets */
zend_uchar packet_no;
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
zend_uchar last_command;
#endif
/* cmd buffer */
MYSQLND_CMD_BUFFER cmd_buffer;
} MYSQLND_NET;
struct st_mysqlnd_conn_methods
{
ulong (*escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, int escapestr_len TSRMLS_DC);
enum_func_status (*set_charset)(MYSQLND * const conn, const char * const charset TSRMLS_DC);
enum_func_status (*query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC);
MYSQLND_RES * (*use_result)(MYSQLND * const conn TSRMLS_DC);
MYSQLND_RES * (*store_result)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*next_result)(MYSQLND * const conn TSRMLS_DC);
zend_bool (*more_results)(const MYSQLND * const conn);
MYSQLND_STMT * (*stmt_init)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*shutdown_server)(MYSQLND * const conn, unsigned long level TSRMLS_DC);
enum_func_status (*refresh_server)(MYSQLND * const conn, unsigned long options TSRMLS_DC);
enum_func_status (*ping)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*kill_connection)(MYSQLND *conn, unsigned int pid TSRMLS_DC);
enum_func_status (*select_db)(MYSQLND * const conn, const char * const db, unsigned int db_len TSRMLS_DC);
enum_func_status (*server_dump_debug_information)(MYSQLND * const conn TSRMLS_DC);
enum_func_status (*change_user)(MYSQLND * const conn, const char * user, const char * passwd, const char * db TSRMLS_DC);
unsigned int (*get_error_no)(const MYSQLND * const conn);
const char * (*get_error_str)(const MYSQLND * const conn);
const char * (*get_sqlstate)(const MYSQLND * const conn);
mynd_ulonglong (*get_thread_id)(const MYSQLND * const conn);
void (*get_statistics)(const MYSQLND * const conn, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
unsigned long (*get_server_version)(const MYSQLND * const conn);
const char * (*get_server_information)(const MYSQLND * const conn);
enum_func_status (*get_server_statistics)(MYSQLND *conn, char **message, unsigned int * message_len TSRMLS_DC);
const char * (*get_host_information)(const MYSQLND * const conn);
unsigned int (*get_protocol_information)(const MYSQLND * const conn);
const char * (*get_last_message)(const MYSQLND * const conn);
const char * (*charset_name)(const MYSQLND * const conn);
MYSQLND_RES * (*list_fields)(MYSQLND *conn, const char *table, const char *achtung_wild TSRMLS_DC);
MYSQLND_RES * (*list_method)(MYSQLND *conn, const char *query, const char *achtung_wild, char *par1 TSRMLS_DC);
mynd_ulonglong (*get_last_insert_id)(const MYSQLND * const conn);
mynd_ulonglong (*get_affected_rows)(const MYSQLND * const conn);
unsigned int (*get_warning_count)(const MYSQLND * const conn);
unsigned int (*get_field_count)(const MYSQLND * const conn);
enum_func_status (*set_server_option)(MYSQLND * const conn, enum_mysqlnd_server_option option TSRMLS_DC);
enum_func_status (*set_client_option)(MYSQLND * const conn, enum_mysqlnd_option option, const char * const value TSRMLS_DC);
void (*free_contents)(MYSQLND *conn TSRMLS_DC); /* private */
enum_func_status (*close)(MYSQLND *conn, enum_connection_close_type close_type TSRMLS_DC);
void (*dtor)(MYSQLND *conn TSRMLS_DC); /* private */
MYSQLND * (*get_reference)(MYSQLND * const conn);
enum_func_status (*free_reference)(MYSQLND * const conn TSRMLS_DC);
};
struct st_mysqlnd_res_methods
{
mysqlnd_fetch_row_func fetch_row;
mysqlnd_fetch_row_func fetch_row_normal_buffered; /* private */
mysqlnd_fetch_row_func fetch_row_normal_unbuffered; /* private */
MYSQLND_RES * (*use_result)(MYSQLND_RES * const result, zend_bool ps_protocol TSRMLS_DC);
MYSQLND_RES * (*store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps TSRMLS_DC);
void (*fetch_into)(MYSQLND_RES *result, unsigned int flags, zval *return_value, enum_mysqlnd_extension ext TSRMLS_DC ZEND_FILE_LINE_DC);
void (*fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
void (*fetch_field_data)(MYSQLND_RES *result, unsigned int offset, zval *return_value TSRMLS_DC);
mynd_ulonglong (*num_rows)(const MYSQLND_RES * const result);
unsigned int (*num_fields)(const MYSQLND_RES * const result);
enum_func_status (*skip_result)(MYSQLND_RES * const result TSRMLS_DC);
enum_func_status (*seek_data)(MYSQLND_RES * result, mynd_ulonglong row TSRMLS_DC);
MYSQLND_FIELD_OFFSET (*seek_field)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET field_offset);
MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES * const result);
MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES * const result TSRMLS_DC);
MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC);
enum_func_status (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC);
unsigned long * (*fetch_lengths)(MYSQLND_RES * const result);
void (*free_result_buffers)(MYSQLND_RES * result TSRMLS_DC); /* private */
enum_func_status (*free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
void (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
void (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
};
struct st_mysqlnd_res_meta_methods
{
MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES_METADATA * const meta TSRMLS_DC);
MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES_METADATA * const meta, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC);
MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES_METADATA * const meta);
enum_func_status (*read_metadata)(MYSQLND_RES_METADATA * const meta, MYSQLND *conn TSRMLS_DC);
MYSQLND_RES_METADATA * (*clone_metadata)(const MYSQLND_RES_METADATA * const meta, zend_bool persistent TSRMLS_DC);
void (*free_metadata)(MYSQLND_RES_METADATA *meta, zend_bool persistent TSRMLS_DC);
};
struct st_mysqlnd_stmt_methods
{
enum_func_status (*prepare)(MYSQLND_STMT * const stmt, const char * const query, unsigned int query_len TSRMLS_DC);
enum_func_status (*execute)(MYSQLND_STMT * const stmt TSRMLS_DC);
MYSQLND_RES * (*use_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
MYSQLND_RES * (*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
MYSQLND_RES * (*get_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*free_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*seek_data)(const MYSQLND_STMT * const stmt, mynd_ulonglong row TSRMLS_DC);
enum_func_status (*reset)(MYSQLND_STMT * const stmt TSRMLS_DC);
enum_func_status (*close)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC); /* private */
enum_func_status (*dtor)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC); /* use this for mysqlnd_stmt_close */
enum_func_status (*fetch)(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything TSRMLS_DC);
enum_func_status (*bind_param)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC);
enum_func_status (*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC);
enum_func_status (*send_long_data)(MYSQLND_STMT * const stmt, unsigned int param_num,
const char * const data, unsigned long length TSRMLS_DC);
MYSQLND_RES * (*get_parameter_metadata)(MYSQLND_STMT * const stmt);
MYSQLND_RES * (*get_result_metadata)(MYSQLND_STMT * const stmt TSRMLS_DC);
mynd_ulonglong (*get_last_insert_id)(const MYSQLND_STMT * const stmt);
mynd_ulonglong (*get_affected_rows)(const MYSQLND_STMT * const stmt);
mynd_ulonglong (*get_num_rows)(const MYSQLND_STMT * const stmt);
unsigned int (*get_param_count)(const MYSQLND_STMT * const stmt);
unsigned int (*get_field_count)(const MYSQLND_STMT * const stmt);
unsigned int (*get_warning_count)(const MYSQLND_STMT * const stmt);
unsigned int (*get_error_no)(const MYSQLND_STMT * const stmt);
const char * (*get_error_str)(const MYSQLND_STMT * const stmt);
const char * (*get_sqlstate)(const MYSQLND_STMT * const stmt);
enum_func_status (*get_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, void * const value TSRMLS_DC);
enum_func_status (*set_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, const void * const value TSRMLS_DC);
};
struct st_mysqlnd_connection
{
/* Operation related */
MYSQLND_NET net;
/* Information related */
char *host;
char *unix_socket;
char *user;
char *passwd;
unsigned int *passwd_len;
char *scheme;
mynd_ulonglong thread_id;
char *server_version;
char *host_info;
unsigned char *scramble;
const MYSQLND_CHARSET *charset;
const MYSQLND_CHARSET *greet_charset;
MYSQLND_INFILE infile;
unsigned int protocol_version;
unsigned long max_packet_size;
unsigned int port;
unsigned long client_flag;
unsigned long server_capabilities;
int tmp_int;
/* For UPSERT queries */
mysqlnd_upsert_status upsert_status;
char *last_message;
unsigned int last_message_len;
/* If error packet, we use these */
mysqlnd_error_info error_info;
/*
To prevent queries during unbuffered fetches. Also to
mark the connection as destroyed for garbage collection.
*/
enum mysqlnd_connection_state state;
enum_mysqlnd_query_type last_query_type;
/* Temporary storage between query and (use|store)_result() call */
MYSQLND_RES *current_result;
/*
How many result sets reference this connection.
It won't be freed until this number reaches 0.
The last one, please close the door! :-)
The result set objects can determine by inspecting
'quit_sent' whether the connection is still valid.
*/
unsigned int refcount;
/* Temporal storage for mysql_query */
unsigned int field_count;
/* persistent connection */
zend_bool persistent;
/* options */
MYSQLND_OPTION options;
/* zval cache */
MYSQLND_THD_ZVAL_PCACHE *zval_cache;
/* qcache */
MYSQLND_QCACHE *qcache;
/* stats */
MYSQLND_STATS stats;
struct st_mysqlnd_conn_methods *m;
};
typedef struct st_php_mysql_packet_row php_mysql_packet_row;
struct mysqlnd_field_hash_key
{
zend_bool is_numeric;
unsigned long key;
#if PHP_MAJOR_VERSION >= 6
zstr ustr;
unsigned int ulen;
#endif
};
struct st_mysqlnd_result_metadata
{
MYSQLND_FIELD *fields;
struct mysqlnd_field_hash_key *zend_hash_keys;
unsigned int current_field;
unsigned int field_count;
/* We need this to make fast allocs in rowp_read */
unsigned int bit_fields_count;
size_t bit_fields_total_len; /* trailing \0 not counted */
struct st_mysqlnd_res_meta_methods *m;
};
struct st_mysqlnd_buffered_result
{
zval ***data;
zval ***data_cursor;
zend_uchar **row_buffers;
mynd_ulonglong row_count;
zend_bool persistent;
MYSQLND_QCACHE *qcache;
unsigned int references;
zend_bool async_invalid;
mysqlnd_error_info error_info;
};
struct st_mysqlnd_unbuffered_result
{
/* For unbuffered (both normal and PS) */
zval **last_row_data;
zend_uchar *last_row_buffer;
mynd_ulonglong row_count;
zend_bool eof_reached;
};
struct st_mysqlnd_res
{
struct st_mysqlnd_res_methods m;
MYSQLND *conn;
enum_mysqlnd_res_type type;
unsigned int field_count;
/* For metadata functions */
MYSQLND_RES_METADATA *meta;
/* To be used with store_result() - both normal and PS */
MYSQLND_RES_BUFFERED *data;
MYSQLND_RES_UNBUFFERED *unbuf;
/*
Column lengths of current row - both buffered and unbuffered.
For buffered results it duplicates the data found in **data
*/
unsigned long *lengths;
php_mysql_packet_row *row_packet; /* Unused for PS */
/* zval cache */
MYSQLND_THD_ZVAL_PCACHE *zval_cache;
};
struct st_mysqlnd_param_bind
{
zval *zv;
zend_uchar type;
enum_param_bind_flags flags;
};
struct st_mysqlnd_result_bind
{
zval *zv;
zend_uchar original_type;
zend_bool bound;
};
struct st_mysqlnd_stmt
{
MYSQLND *conn;
unsigned long stmt_id;
unsigned long flags;/* cursor is set here */
enum_mysqlnd_stmt_state state;
unsigned int warning_count;
MYSQLND_RES *result;
unsigned int field_count;
unsigned int param_count;
unsigned char send_types_to_server;
MYSQLND_PARAM_BIND *param_bind;
MYSQLND_RESULT_BIND *result_bind;
zend_bool result_zvals_separated_once;
mysqlnd_upsert_status upsert_status;
mysqlnd_error_info error_info;
zend_bool update_max_length;
unsigned long prefetch_rows;
zend_bool cursor_exists;
mysqlnd_stmt_use_or_store_func default_rset_handler;
MYSQLND_CMD_BUFFER cmd_buffer;
unsigned int execute_count;/* count how many times the stmt was executed */
struct st_mysqlnd_stmt_methods *m;
};
#endif /* MYSQLND_STRUCTS_H */

File diff suppressed because it is too large Load Diff

View File

@ -0,0 +1,335 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| Copyright (c) 2006-2007 The PHP Group |
+----------------------------------------------------------------------+
| This source file is subject to version 3.01 of the PHP license, |
| that is bundled with this package in the file LICENSE, and is |
| available through the world-wide-web at the following url: |
| http://www.php.net/license/3_01.txt |
| If you did not receive a copy of the PHP license and are unable to |
| obtain it through the world-wide-web, please send a note to |
| license@php.net so we can mail you a copy immediately. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@mysql.com> |
| Andrey Hristov <andrey@mysql.com> |
| Ulf Wendel <uwendel@mysql.com> |
+----------------------------------------------------------------------+
*/
/* $Id$ */
#ifndef MYSQLND_WIREPROTOCOL_H
#define MYSQLND_WIREPROTOCOL_H
#define MYSQLND_HEADER_SIZE 4
#define MYSQLND_NULL_LENGTH (unsigned long) ~0
typedef zend_uchar mysqlnd_1b;
typedef zend_ushort mysqlnd_2b;
typedef zend_uint mysqlnd_4b;
/* Used in mysqlnd_debug.c */
extern char * mysqlnd_read_header_name;
extern char * mysqlnd_read_body_name;
/* Packet handling */
#define PACKET_INIT(packet, enum_type, c_type) \
{ \
packet = (c_type) ecalloc(1, packet_methods[enum_type].struct_size); \
((c_type) (packet))->header.m = &packet_methods[enum_type]; \
}
#define PACKET_WRITE(packet, conn) ((packet)->header.m->write_to_net((packet), (conn) TSRMLS_CC))
#define PACKET_READ(packet, conn) ((packet)->header.m->read_from_net((packet), (conn) TSRMLS_CC))
#define PACKET_FREE(packet) \
do { \
((packet)->header.m->free_mem((packet), FALSE TSRMLS_CC)); \
} while (0);
#define PACKET_INIT_ALLOCA(packet, enum_type) \
{ \
memset(&(packet), 0, packet_methods[enum_type].struct_size); \
(packet).header.m = &packet_methods[enum_type]; \
}
#define PACKET_WRITE_ALLOCA(packet, conn) PACKET_WRITE(&(packet), (conn))
#define PACKET_READ_ALLOCA(packet, conn) PACKET_READ(&(packet), (conn))
#define PACKET_FREE_ALLOCA(packet) (packet.header.m->free_mem(&(packet), TRUE TSRMLS_CC))
/* Enums */
enum php_mysql_packet_type
{
PROT_GREET_PACKET= 0,
PROT_AUTH_PACKET,
PROT_OK_PACKET,
PROT_EOF_PACKET,
PROT_CMD_PACKET,
PROT_RSET_HEADER_PACKET,
PROT_RSET_FLD_PACKET,
PROT_ROW_PACKET,
PROT_STATS_PACKET,
PROT_PREPARE_RESP_PACKET,
PROT_CHG_USER_PACKET,
PROT_LAST, /* should always be last */
};
enum php_mysqlnd_server_command
{
COM_SLEEP = 0,
COM_QUIT,
COM_INIT_DB,
COM_QUERY,
COM_FIELD_LIST,
COM_CREATE_DB,
COM_DROP_DB,
COM_REFRESH,
COM_SHUTDOWN,
COM_STATISTICS,
COM_PROCESS_INFO,
COM_CONNECT,
COM_PROCESS_KILL,
COM_DEBUG,
COM_PING,
COM_TIME = 15,
COM_DELAYED_INSERT,
COM_CHANGE_USER,
COM_BINLOG_DUMP,
COM_TABLE_DUMP,
COM_CONNECT_OUT = 20,
COM_REGISTER_SLAVE,
COM_STMT_PREPARE = 22,
COM_STMT_EXECUTE = 23,
COM_STMT_SEND_LONG_DATA = 24,
COM_STMT_CLOSE = 25,
COM_STMT_RESET = 26,
COM_SET_OPTION = 27,
COM_STMT_FETCH = 28,
COM_DAEMON,
COM_END
};
extern const char * const mysqlnd_command_to_text[COM_END];
/* Low-level extraction functionality */
typedef struct st_mysqlnd_packet_methods {
size_t struct_size;
enum_func_status (*read_from_net)(void *packet, MYSQLND *conn TSRMLS_DC);
size_t (*write_to_net)(void *packet, MYSQLND *conn TSRMLS_DC);
void (*free_mem)(void *packet, zend_bool alloca TSRMLS_DC);
} mysqlnd_packet_methods;
extern mysqlnd_packet_methods packet_methods[];
typedef struct st_mysqlnd_packet_header {
size_t size;
zend_uchar packet_no;
mysqlnd_packet_methods *m;
} mysqlnd_packet_header;
/* Server greets the client */
typedef struct st_php_mysql_packet_greet {
mysqlnd_packet_header header;
mysqlnd_1b protocol_version;
char *server_version;
mysqlnd_4b thread_id;
zend_uchar scramble_buf[SCRAMBLE_LENGTH];
/* 1 byte pad */
mysqlnd_2b server_capabilities;
mysqlnd_1b charset_no;
mysqlnd_2b server_status;
/* 13 byte pad*/
zend_bool pre41;
/* If error packet, we use these */
char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no;
} php_mysql_packet_greet;
/* Client authenticates */
typedef struct st_php_mysql_packet_auth {
mysqlnd_packet_header header;
mysqlnd_4b client_flags;
uint32 max_packet_size;
mysqlnd_1b charset_no;
/* 23 byte pad */
char *user;
/* 8 byte scramble */
char *db;
/* 12 byte scramble */
/* Here the packet ends. This is user supplied data */
char *password;
/* +1 for \0 because of scramble() */
unsigned char *server_scramble_buf;
size_t db_len;
} php_mysql_packet_auth;
/* OK packet */
typedef struct st_php_mysql_packet_ok {
mysqlnd_packet_header header;
mysqlnd_1b field_count; /* always 0x0 */
mynd_ulonglong affected_rows;
mynd_ulonglong last_insert_id;
mysqlnd_2b server_status;
mysqlnd_2b warning_count;
char *message;
size_t message_len;
/* If error packet, we use these */
char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no;
} php_mysql_packet_ok;
/* Command packet */
typedef struct st_php_mysql_packet_command {
mysqlnd_packet_header header;
enum php_mysqlnd_server_command command;
const char *argument;
size_t arg_len;
} php_mysql_packet_command;
/* EOF packet */
typedef struct st_php_mysql_packet_eof {
mysqlnd_packet_header header;
mysqlnd_1b field_count; /* 0xFE */
mysqlnd_2b warning_count;
mysqlnd_2b server_status;
/* If error packet, we use these */
char error[MYSQLND_ERRMSG_SIZE+1];
char sqlstate[MYSQLND_SQLSTATE_LENGTH + 1];
unsigned int error_no;
} php_mysql_packet_eof;
/* EOF packet */
/* Result Set header*/
typedef struct st_php_mysql_packet_rset_header {
mysqlnd_packet_header header;
/*
0x00 => ok
~0 => LOAD DATA LOCAL
error_no != 0 => error
others => result set -> Read res_field packets up to field_count
*/
unsigned long field_count;
/*
These are filled if no SELECT query. For SELECT warning_count
and server status are in the last row packet, the EOF packet.
*/
mysqlnd_2b warning_count;
mysqlnd_2b server_status;
mynd_ulonglong affected_rows;
mynd_ulonglong last_insert_id;
/* This is for both LOAD DATA or info, when no result set */
char *info_or_local_file;
size_t info_or_local_file_len;
/* If error packet, we use these */
mysqlnd_error_info error_info;
} php_mysql_packet_rset_header;
/* Result set field packet */
typedef struct st_php_mysql_packet_res_field {
mysqlnd_packet_header header;
MYSQLND_FIELD *metadata;
/* For table definitions, empty for result sets */
zend_bool skip_parsing;
zend_bool stupid_list_fields_eof;
} php_mysql_packet_res_field;
/* Row packet */
struct st_php_mysql_packet_row {
mysqlnd_packet_header header;
zval **fields;
mysqlnd_4b field_count;
zend_bool eof;
/*
These are, of course, only for SELECT in the EOF packet,
which is detected by this packet
*/
mysqlnd_2b warning_count;
mysqlnd_2b server_status;
zend_uchar *row_buffer;
zend_bool skip_extraction;
zend_bool binary_protocol;
zend_bool persistent_alloc;
MYSQLND_FIELD *fields_metadata;
/* We need this to alloc bigger bufs in non-PS mode */
unsigned int bit_fields_count;
size_t bit_fields_total_len; /* trailing \0 not counted */
/* If error packet, we use these */
mysqlnd_error_info error_info;
};
/* Statistics packet */
typedef struct st_php_mysql_packet_stats {
mysqlnd_packet_header header;
char *message;
/* message_len is not part of the packet*/
size_t message_len;
} php_mysql_packet_stats;
/* COM_PREPARE response packet */
typedef struct st_php_mysql_packet_prepare_response {
mysqlnd_packet_header header;
/* also known as field_count 0x00=OK , 0xFF=error */
unsigned char error_code;
unsigned long stmt_id;
unsigned int field_count;
unsigned int param_count;
unsigned int warning_count;
/* present in case of error */
mysqlnd_error_info error_info;
} php_mysql_packet_prepare_response;
/* Statistics packet */
typedef struct st_php_mysql_packet_chg_user_resp {
mysqlnd_packet_header header;
mysqlnd_4b field_count;
/* message_len is not part of the packet*/
mysqlnd_2b server_capabilities;
/* If error packet, we use these */
mysqlnd_error_info error_info;
} php_mysql_packet_chg_user_resp;
size_t mysqlnd_stream_write(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC);
size_t mysqlnd_stream_write_w_header(MYSQLND * const conn, char * const buf, size_t count TSRMLS_DC);
#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
size_t php_mysqlnd_consume_uneaten_data(MYSQLND * const conn, enum php_mysqlnd_server_command cmd TSRMLS_DC);
#endif
void php_mysqlnd_scramble(zend_uchar * const buffer, const zend_uchar * const scramble, const zend_uchar * const pass);
unsigned long php_mysqlnd_net_field_length(zend_uchar **packet);
zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, mynd_ulonglong length);
extern char * const mysqlnd_empty_string;
#endif /* MYSQLND_WIREPROTOCOL_H */
/*
* Local variables:
* tab-width: 4
* c-basic-offset: 4
* End:
* vim600: noet sw=4 ts=4 fdm=marker
* vim<600: noet sw=4 ts=4
*/

29
ext/mysqlnd/php_mysqlnd.h Normal file
View File

@ -0,0 +1,29 @@
/*
+----------------------------------------------------------------------+
| PHP Version 6 |
+----------------------------------------------------------------------+
| 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. |
+----------------------------------------------------------------------+
| Authors: Georg Richter <georg@php.net> |
| Andrey Hristov <andrey@php.net> |
| Ulf Wendel <uw@php.net> |
+----------------------------------------------------------------------+
$Id$
*/
#ifndef PHP_MYSQLND_H
#define PHP_MYSQLND_H
#define phpext_mysqlnd_ptr &mysqlnd_module_entry
extern zend_module_entry mysqlnd_module_entry;
#endif /* PHP_MYSQLND_H */