diff options
Diffstat (limited to 'ext/mysqlnd')
| -rw-r--r-- | ext/mysqlnd/config9.m4 | 9 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd.c | 130 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd.h | 16 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_block_alloc.c | 3 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_charset.c | 425 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_debug.c | 218 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_debug.h | 81 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_enum_n_def.h | 33 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_loaddata.c | 8 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_net.c | 9 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_portability.h | 12 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_priv.h | 25 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_ps.c | 130 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_ps_codec.c | 211 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_result.c | 190 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_result_meta.c | 25 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_statistics.c | 18 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_statistics.h | 4 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_structs.h | 17 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.c | 105 | ||||
| -rw-r--r-- | ext/mysqlnd/mysqlnd_wireprotocol.h | 4 | ||||
| -rw-r--r-- | ext/mysqlnd/php_mysqlnd.c | 8 |
22 files changed, 1020 insertions, 661 deletions
diff --git a/ext/mysqlnd/config9.m4 b/ext/mysqlnd/config9.m4 index 4a23e101a..fad2bce82 100644 --- a/ext/mysqlnd/config9.m4 +++ b/ext/mysqlnd/config9.m4 @@ -1,5 +1,5 @@ dnl -dnl $Id: config9.m4 298023 2010-04-15 11:01:30Z andrey $ +dnl $Id: config9.m4 304973 2010-10-28 13:46:54Z andrey $ dnl config.m4 for mysqlnd driver @@ -27,13 +27,10 @@ if test "$PHP_MYSQLND_ENABLED" = "yes"; then dnl Windows uses config.w32 thus this code is safe for now if test "$PHP_MYSQLND_COMPRESSION_SUPPORT" != "no"; then - AC_DEFINE([MYSQLND_COMPRESSION_ENABLED], 1, [Enable compressed protocol support]) - if test "$PHP_ZLIB_DIR" != "no"; then + if test -z "$PHP_ZLIB_DIR"; then + AC_DEFINE([MYSQLND_COMPRESSION_ENABLED], 1, [Enable compressed protocol support]) PHP_ADD_LIBRARY_WITH_PATH(z, $PHP_ZLIB_DIR, MYSQLND_SHARED_LIBADD) MYSQLND_LIBS="$MYSQLND_LIBS -L$PHP_ZLIB_DIR/$PHP_LIBDIR -lz" - else - PHP_ADD_LIBRARY(z,, MYSQLND_SHARED_LIBADD) - MYSQLND_LIBS="$MYSQLND_LIBS -lz" fi fi AC_DEFINE([MYSQLND_SSL_SUPPORTED], 1, [Enable SSL support]) diff --git a/ext/mysqlnd/mysqlnd.c b/ext/mysqlnd/mysqlnd.c index d0f2c1c20..430db402e 100644 --- a/ext/mysqlnd/mysqlnd.c +++ b/ext/mysqlnd/mysqlnd.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd.c 300635 2010-06-21 15:32:26Z andrey $ */ +/* $Id: mysqlnd.c 306008 2010-12-06 13:50:51Z andrey $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_wireprotocol.h" @@ -282,7 +282,7 @@ MYSQLND_METHOD(mysqlnd_conn, simple_command_handle_response)(MYSQLND * conn, enu MYSQLND_PACKET_EOF * ok_response = conn->protocol->m.get_eof_packet(conn->protocol, FALSE TSRMLS_CC); if (!ok_response) { SET_OOM_ERROR(conn->error_info); - break; + break; } if (FAIL == (ret = PACKET_READ(ok_response, conn))) { SET_CLIENT_ERROR(conn->error_info, CR_MALFORMED_PACKET, UNKNOWN_SQLSTATE, @@ -399,25 +399,6 @@ MYSQLND_METHOD(mysqlnd_conn, set_server_option)(MYSQLND * const conn, enum_mysql /* }}} */ -/* {{{ _mysqlnd_restart_psession */ -PHPAPI void _mysqlnd_restart_psession(MYSQLND * conn TSRMLS_DC) -{ - DBG_ENTER("_mysqlnd_restart_psession"); - conn->m->restart_psession(conn TSRMLS_CC); - DBG_VOID_RETURN; -} -/* }}} */ - - -/* {{{ _mysqlnd_end_psession */ -PHPAPI void _mysqlnd_end_psession(MYSQLND * conn TSRMLS_DC) -{ - DBG_ENTER("_mysqlnd_end_psession"); - conn->m->end_psession(conn TSRMLS_CC); - DBG_VOID_RETURN; -} -/* }}} */ - /* {{{ mysqlnd_conn::restart_psession */ static enum_func_status MYSQLND_METHOD(mysqlnd_conn, restart_psession)(MYSQLND * conn TSRMLS_DC) @@ -481,7 +462,7 @@ mysqlnd_connect_run_authentication( if (options->charset_name && (charset = mysqlnd_find_charset_name(options->charset_name))) { auth_packet->charset_no = charset->nr; } else { -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE auth_packet->charset_no = 200;/* utf8 - swedish collation, check mysqlnd_charset.c */ #else auth_packet->charset_no = greet_packet->charset_no; @@ -498,7 +479,7 @@ mysqlnd_connect_run_authentication( goto err; } memcpy(auth_packet->server_scramble_buf, greet_packet->scramble_buf, SCRAMBLE_LENGTH); - + if (!PACKET_WRITE(auth_packet, conn)) { CONN_SET_STATE(conn, CONN_QUIT_SENT); SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone); @@ -515,7 +496,7 @@ mysqlnd_connect_run_authentication( if (FAIL == conn->net->m.enable_ssl(conn->net TSRMLS_CC)) { goto err; } - + auth_packet->send_half_packet = FALSE; if (!PACKET_WRITE(auth_packet, conn)) { CONN_SET_STATE(conn, CONN_QUIT_SENT); @@ -550,7 +531,7 @@ mysqlnd_connect_run_authentication( err: PACKET_FREE(auth_packet); PACKET_FREE(ok_packet); - DBG_RETURN(ret); + DBG_RETURN(ret); } /* }}} */ @@ -568,7 +549,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, const char *passwd, unsigned int passwd_len, const char *db, unsigned int db_len, unsigned int port, - const char *socket, + const char * socket_or_pipe, unsigned int mysql_flags TSRMLS_DC) { @@ -636,11 +617,11 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, int transport_len; #ifndef PHP_WIN32 if (host_len == sizeof("localhost") - 1 && !strncasecmp(host, "localhost", host_len)) { - DBG_INF_FMT("socket=%s", socket? socket:"n/a"); - if (!socket) { - socket = "/tmp/mysql.sock"; + DBG_INF_FMT("socket=%s", socket_or_pipe? socket_or_pipe:"n/a"); + if (!socket_or_pipe) { + socket_or_pipe = "/tmp/mysql.sock"; } - transport_len = spprintf(&transport, 0, "unix://%s", socket); + transport_len = spprintf(&transport, 0, "unix://%s", socket_or_pipe); unix_socket = TRUE; } else #endif @@ -714,6 +695,10 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, if (mysql_flags & CLIENT_COMPRESS) { mysql_flags &= ~CLIENT_COMPRESS; } +#else + if (conn->net->options.flags & MYSQLND_NET_FLAG_USE_COMPRESSION) { + mysql_flags |= CLIENT_COMPRESS; + } #endif #ifndef MYSQLND_SSL_SUPPORTED if (mysql_flags & CLIENT_SSL) { @@ -769,21 +754,21 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, spprintf(&p, 0, "%s via TCP/IP", conn->host); if (!p) { SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ + goto err; /* OOM */ } conn->host_info = mnd_pestrdup(p, conn->persistent); efree(p); /* allocated by spprintf */ if (!conn->host_info) { SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ + goto err; /* OOM */ } } } else { - conn->unix_socket = mnd_pestrdup(socket, conn->persistent); + conn->unix_socket = mnd_pestrdup(socket_or_pipe, conn->persistent); conn->host_info = mnd_pestrdup("Localhost via UNIX socket", conn->persistent); if (!conn->unix_socket || !conn->host_info) { SET_OOM_ERROR(conn->error_info); - goto err; /* OOM */ + goto err; /* OOM */ } conn->unix_socket_len = strlen(conn->unix_socket); } @@ -799,7 +784,7 @@ MYSQLND_METHOD(mysqlnd_conn, connect)(MYSQLND * conn, mysqlnd_local_infile_default(conn); -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE { unsigned int as_unicode = 1; conn->m->set_client_option(conn, MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE, (char *)&as_unicode TSRMLS_CC); @@ -865,7 +850,7 @@ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn, const char *passwd, unsigned int passwd_len, const char *db, unsigned int db_len, unsigned int port, - const char *socket, + const char *socket_or_pipe, unsigned int mysql_flags TSRMLS_DC) { @@ -883,7 +868,7 @@ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND * conn, } } - ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket, mysql_flags TSRMLS_CC); + ret = conn->m->connect(conn, host, user, passwd, passwd_len, db, db_len, port, socket_or_pipe, mysql_flags TSRMLS_CC); if (ret == FAIL) { if (self_alloced) { @@ -1188,11 +1173,11 @@ MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, con FALSE, TRUE TSRMLS_CC)) { DBG_RETURN(NULL); } - + /* Prepare for the worst case. MyISAM goes to 2500 BIT columns, double it for safety. - */ + */ result = conn->m->result_init(5000, conn->persistent TSRMLS_CC); if (!result) { DBG_RETURN(NULL); @@ -1211,7 +1196,7 @@ MYSQLND_METHOD(mysqlnd_conn, list_fields)(MYSQLND * conn, const char *table, con /* OOM */ SET_OOM_ERROR(conn->error_info); result->m.free_result(result, TRUE TSRMLS_CC); - DBG_RETURN(NULL); + DBG_RETURN(NULL); } result->unbuf->eof_reached = TRUE; @@ -1287,20 +1272,19 @@ MYSQLND_METHOD(mysqlnd_conn, sqlstate)(const MYSQLND * const conn TSRMLS_DC) PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC) { DBG_ENTER("mysqlnd_old_escape_string"); - DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), - newstr, escapestr, escapestr_len TSRMLS_CC)); + DBG_RETURN(mysqlnd_cset_escape_slashes(mysqlnd_find_charset_name("latin1"), newstr, escapestr, escapestr_len TSRMLS_CC)); } /* }}} */ /* {{{ mysqlnd_conn::ssl_set */ -void +static enum_func_status MYSQLND_METHOD(mysqlnd_conn, ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC) { - conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_KEY, key TSRMLS_CC); - conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CERT, cert TSRMLS_CC); - conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CA, ca TSRMLS_CC); - conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CAPATH, capath TSRMLS_CC); - conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CIPHER, cipher TSRMLS_CC); + return (PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_KEY, key TSRMLS_CC) && + PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CERT, cert TSRMLS_CC) && + PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CA, ca TSRMLS_CC) && + PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CAPATH, capath TSRMLS_CC) && + PASS == conn->net->m.set_client_option(conn->net, MYSQLND_OPT_SSL_CIPHER, cipher TSRMLS_CC)) ? PASS : FAIL; } /* }}} */ @@ -1384,14 +1368,14 @@ MYSQLND_METHOD(mysqlnd_conn, ping)(MYSQLND * const conn TSRMLS_DC) /* }}} */ -/* {{{ mysqlnd_conn::stat */ +/* {{{ mysqlnd_conn::statistic */ static enum_func_status -MYSQLND_METHOD(mysqlnd_conn, stat)(MYSQLND * conn, char **message, unsigned int * message_len TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_conn, statistic)(MYSQLND * conn, char **message, unsigned int * message_len TSRMLS_DC) { enum_func_status ret; MYSQLND_PACKET_STATS * stats_header; - DBG_ENTER("mysqlnd_conn::stat"); + DBG_ENTER("mysqlnd_conn::statistic"); DBG_INF_FMT("conn=%llu", conn->thread_id); ret = conn->m->simple_command(conn, COM_STATISTICS, NULL, 0, PROT_LAST, FALSE, TRUE TSRMLS_CC); @@ -1438,8 +1422,7 @@ MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND * conn, unsigned int pid TSRMLS_DC) a protocol of giving back -1. Thus we have to follow it :( */ SET_ERROR_AFF_ROWS(conn); - } else if (PASS == (ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, - 4, PROT_LAST, FALSE, TRUE TSRMLS_CC))) { + } else if (PASS == (ret = conn->m->simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_LAST, FALSE, TRUE TSRMLS_CC))) { CONN_SET_STATE(conn, CONN_QUIT_SENT); } DBG_RETURN(ret); @@ -1577,13 +1560,13 @@ MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn, enum_connection_close_type c STAT_CLOSE_IMPLICIT, STAT_CLOSE_DISCONNECT }; - enum_mysqlnd_collected_stats stat = close_type_to_stat_map[close_type]; + enum_mysqlnd_collected_stats statistic = close_type_to_stat_map[close_type]; DBG_ENTER("mysqlnd_conn::close"); DBG_INF_FMT("conn=%llu", conn->thread_id); if (conn->state >= CONN_READY) { - MYSQLND_INC_CONN_STATISTIC(conn->stats, stat); + MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic); MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_CONNECTIONS); if (conn->persistent) { MYSQLND_DEC_CONN_STATISTIC(conn->stats, STAT_OPENED_PERSISTENT_CONNECTIONS); @@ -1954,7 +1937,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, int2store(p, conn->charset->nr); p+=2; } - + if (PASS != conn->m->simple_command(conn, COM_CHANGE_USER, buffer, p - buffer, PROT_LAST /* we will handle the OK packet*/, silent, TRUE TSRMLS_CC)) { @@ -1983,20 +1966,24 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, PACKET_FREE(redundant_error_packet); DBG_INF_FMT("Server is %u, buggy, sends two ERR messages", mysqlnd_get_server_version(conn)); } else { - SET_OOM_ERROR(conn->error_info); + SET_OOM_ERROR(conn->error_info); } } } if (ret == PASS) { + char * tmp = NULL; + /* if we get conn->user as parameter and then we first free it, then estrndup it, we will crash */ + tmp = mnd_pestrndup(user, user_len, conn->persistent); if (conn->user) { mnd_pefree(conn->user, conn->persistent); } - conn->user = mnd_pestrndup(user, user_len, conn->persistent); + conn->user = tmp; + tmp = mnd_pestrdup(passwd, conn->persistent); if (conn->passwd) { mnd_pefree(conn->passwd, conn->persistent); } - conn->passwd = mnd_pestrdup(passwd, conn->persistent); + conn->passwd = tmp; if (conn->last_message) { mnd_pefree(conn->last_message, conn->persistent); @@ -2010,7 +1997,7 @@ MYSQLND_METHOD(mysqlnd_conn, change_user)(MYSQLND * const conn, } else if (ret == FAIL && chg_user_resp->server_asked_323_auth == TRUE) { /* old authentication with new server !*/ DBG_ERR(mysqlnd_old_passwd); - SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); + SET_CLIENT_ERROR(conn->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, mysqlnd_old_passwd); } end: PACKET_FREE(chg_user_resp); @@ -2036,9 +2023,7 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn, DBG_ENTER("mysqlnd_conn::set_client_option"); DBG_INF_FMT("conn=%llu option=%u", conn->thread_id, option); switch (option) { -#ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_OPT_COMPRESS: -#endif #ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_OPT_READ_TIMEOUT: case MYSQL_OPT_WRITE_TIMEOUT: @@ -2054,7 +2039,7 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn, case MYSQLND_OPT_NET_READ_BUFFER_SIZE: ret = conn->net->m.set_client_option(conn->net, option, value TSRMLS_CC); break; -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE case MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE: conn->options.numeric_and_datetime_as_unicode = *(unsigned int*) value; break; @@ -2116,10 +2101,17 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn, DBG_INF_FMT("charset=%s", conn->options.charset_name); break; } + case MYSQL_OPT_NAMED_PIPE: + conn->options.protocol = MYSQL_PROTOCOL_PIPE; + break; + case MYSQL_OPT_PROTOCOL: + if (*(unsigned int*) value < MYSQL_PROTOCOL_LAST) { + conn->options.protocol = *(unsigned int*) value; + } + break; #ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_SET_CHARSET_DIR: case MYSQL_OPT_RECONNECT: - case MYSQL_OPT_PROTOCOL: /* we don't need external character sets, all character sets are compiled in. For compatibility we just ignore this setting. Same for protocol, we don't support old protocol */ @@ -2131,7 +2123,6 @@ MYSQLND_METHOD(mysqlnd_conn, set_client_option)(MYSQLND * const conn, #endif #ifdef WHEN_SUPPORTED_BY_MYSQLI - case MYSQL_OPT_NAMED_PIPE: case MYSQL_SHARED_MEMORY_BASE_NAME: case MYSQL_OPT_USE_RESULT: case MYSQL_SECURE_AUTH: @@ -2178,7 +2169,7 @@ MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC) conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC); } conn->current_result = NULL; - + DBG_RETURN(result); } /* }}} */ @@ -2209,7 +2200,7 @@ MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC) result = conn->current_result->m.store_result(conn->current_result, conn, FALSE TSRMLS_CC); if (!result) { - conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC); + conn->current_result->m.free_result(conn->current_result, TRUE TSRMLS_CC); } conn->current_result = NULL; DBG_RETURN(result); @@ -2269,7 +2260,7 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn) MYSQLND_METHOD(mysqlnd_conn, get_server_version), MYSQLND_METHOD(mysqlnd_conn, get_server_info), - MYSQLND_METHOD(mysqlnd_conn, stat), + MYSQLND_METHOD(mysqlnd_conn, statistic), MYSQLND_METHOD(mysqlnd_conn, get_host_info), MYSQLND_METHOD(mysqlnd_conn, get_proto_info), MYSQLND_METHOD(mysqlnd_conn, info), @@ -2328,10 +2319,11 @@ MYSQLND_METHOD(mysqlnd_conn, init)(MYSQLND * conn TSRMLS_DC) PHPAPI MYSQLND * _mysqlnd_init(zend_bool persistent TSRMLS_DC) { size_t alloc_size = sizeof(MYSQLND) + mysqlnd_plugin_count() * sizeof(void *); - MYSQLND *ret = mnd_pecalloc(1, alloc_size, persistent); + MYSQLND *ret; DBG_ENTER("mysqlnd_init"); DBG_INF_FMT("persistent=%u", persistent); + ret = mnd_pecalloc(1, alloc_size, persistent); if (!ret) { DBG_RETURN(NULL); } diff --git a/ext/mysqlnd/mysqlnd.h b/ext/mysqlnd/mysqlnd.h index 2db4c6dc4..032057fff 100644 --- a/ext/mysqlnd/mysqlnd.h +++ b/ext/mysqlnd/mysqlnd.h @@ -17,12 +17,12 @@ | Ulf Wendel <uwendel@mysql.com> | +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd.h 300533 2010-06-17 16:56:48Z pajoye $ */ +/* $Id: mysqlnd.h 304625 2010-10-22 14:34:33Z andrey $ */ #ifndef MYSQLND_H #define MYSQLND_H -#define MYSQLND_VERSION "mysqlnd 5.0.7-dev - 091210 - $Revision: 300533 $" +#define MYSQLND_VERSION "mysqlnd 5.0.7-dev - 091210 - $Revision: 304625 $" #define MYSQLND_VERSION_ID 50007 /* This forces inlining of some accessor functions */ @@ -44,7 +44,7 @@ #define MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND 1 #endif -#if PHP_DEBUG && !defined(PHP_WIN32) +#if PHP_DEBUG #define MYSQLND_DBG_ENABLED 1 #else #define MYSQLND_DBG_ENABLED 0 @@ -85,10 +85,8 @@ PHPAPI struct st_mysqlnd_stmt_methods * mysqlnd_stmt_get_methods(); PHPAPI void mysqlnd_stmt_set_methods(struct st_mysqlnd_stmt_methods *methods); -#define mysqlnd_restart_psession(conn) _mysqlnd_restart_psession((conn) TSRMLS_CC) -PHPAPI void _mysqlnd_restart_psession(MYSQLND * conn TSRMLS_DC); -#define mysqlnd_end_psession(conn) _mysqlnd_end_psession((conn) TSRMLS_CC) -PHPAPI void _mysqlnd_end_psession(MYSQLND *conn TSRMLS_DC); +#define mysqlnd_restart_psession(conn) (conn)->m->restart_psession((conn) TSRMLS_CC) +#define mysqlnd_end_psession(conn) (conn)->m->end_psession((conn) TSRMLS_CC) PHPAPI void mysqlnd_minfo_print_hash(zval *values); #define mysqlnd_thread_safe() TRUE @@ -104,7 +102,7 @@ PHPAPI MYSQLND * mysqlnd_connect(MYSQLND *conn, const char *passwd, unsigned int passwd_len, const char *db, unsigned int db_len, unsigned int port, - const char *socket, + const char *socket_or_pipe, unsigned int mysql_flags TSRMLS_DC); @@ -286,7 +284,7 @@ ZEND_BEGIN_MODULE_GLOBALS(mysqlnd) long debug_realloc_fail_threshold; ZEND_END_MODULE_GLOBALS(mysqlnd) -PHPAPI ZEND_DECLARE_MODULE_GLOBALS(mysqlnd); +PHPAPI ZEND_EXTERN_MODULE_GLOBALS(mysqlnd) #ifdef ZTS #define MYSQLND_G(v) TSRMG(mysqlnd_globals_id, zend_mysqlnd_globals *, v) diff --git a/ext/mysqlnd/mysqlnd_block_alloc.c b/ext/mysqlnd/mysqlnd_block_alloc.c index 1288e7690..c89b3770b 100644 --- a/ext/mysqlnd/mysqlnd_block_alloc.c +++ b/ext/mysqlnd/mysqlnd_block_alloc.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_block_alloc.c 298917 2010-05-03 17:07:18Z andrey $ */ +/* $Id: mysqlnd_block_alloc.c 303734 2010-09-23 16:03:22Z andrey $ */ #include "php.h" #include "mysqlnd.h" @@ -104,7 +104,6 @@ mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, unsigned int siz DBG_RETURN(FAIL); } chunk->ptr = new_ptr; - } DBG_RETURN(PASS); } diff --git a/ext/mysqlnd/mysqlnd_charset.c b/ext/mysqlnd/mysqlnd_charset.c index d8a2c5ac0..1e058fa1a 100644 --- a/ext/mysqlnd/mysqlnd_charset.c +++ b/ext/mysqlnd/mysqlnd_charset.c @@ -24,6 +24,44 @@ #include "mysqlnd_debug.h" /* {{{ utf8 functions */ +static unsigned int check_mb_utf8mb3_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 unsigned int check_mb_utf8_sequence(const char *start, const char *end) { @@ -60,16 +98,57 @@ static unsigned int check_mb_utf8_sequence(const char *start, const char *end) } return 3; } + if (c < 0xF5) { + if (start + 4 > end) { /* We need 4 characters */ + return 0; /* too small */ + } + + /* + UTF-8 quick four-byte mask: + 11110xxx 10xxxxxx 10xxxxxx 10xxxxxx + Encoding allows to encode U+00010000..U+001FFFFF + + The maximum character defined in the Unicode standard is U+0010FFFF. + Higher characters U+00110000..U+001FFFFF are not used. + + 11110000.10010000.10xxxxxx.10xxxxxx == F0.90.80.80 == U+00010000 (min) + 11110100.10001111.10111111.10111111 == F4.8F.BF.BF == U+0010FFFF (max) + + Valid codes: + [F0][90..BF][80..BF][80..BF] + [F1][80..BF][80..BF][80..BF] + [F2][80..BF][80..BF][80..BF] + [F3][80..BF][80..BF][80..BF] + [F4][80..8F][80..BF][80..BF] + */ + + if (!((start[1] ^ 0x80) < 0x40 && + (start[2] ^ 0x80) < 0x40 && + (start[3] ^ 0x80) < 0x40 && + (c >= 0xf1 || start[1] >= 0x90) && + (c <= 0xf3 || start[1] <= 0x8F))) + { + return 0; /* invalid utf8 character */ + } + return 4; + } return 0; } +static unsigned int check_mb_utf8mb3_valid(const char *start, const char *end) +{ + unsigned int len = check_mb_utf8mb3_sequence(start, end); + return (len > 1)? len:0; +} + static unsigned int check_mb_utf8_valid(const char *start, const char *end) { unsigned int len = check_mb_utf8_sequence(start, end); return (len > 1)? len:0; } -static unsigned int mysqlnd_mbcharlen_utf8(unsigned int utf8) + +static unsigned int mysqlnd_mbcharlen_utf8mb3(unsigned int utf8) { if (utf8 < 0x80) { return 1; /* single byte character */ @@ -83,8 +162,27 @@ static unsigned int mysqlnd_mbcharlen_utf8(unsigned int utf8) if (utf8 < 0xF0) { return 3; /* triple byte character */ } - /* We still don't support characters out of the BMP */ + return 0; +} + +static unsigned int mysqlnd_mbcharlen_utf8(unsigned int 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 */ + } + if (utf8 < 0xF8) { + return 4; /* four byte character */ + } return 0; } /* }}} */ @@ -292,186 +390,60 @@ static unsigned int mysqlnd_mbcharlen_ujis(unsigned int ujis) -/* {{{ mysqlnd_charsets */ -const MYSQLND_CHARSET mysqlnd_charsets[] = +/* {{{ utf16 functions */ +#define UTF16_HIGH_HEAD(x) ((((zend_uchar) (x)) & 0xFC) == 0xD8) +#define UTF16_LOW_HEAD(x) ((((zend_uchar) (x)) & 0xFC) == 0xDC) + +static unsigned int check_mb_utf16(const char *start, const char *end) { - { 1, "big5","big5_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_big5, check_mb_big5}, - { 3, "dec8", "dec8_swedisch_ci", 1, 1, "", NULL, NULL}, - { 4, "cp850", "cp850_general_ci", 1, 1, "", NULL, NULL}, - { 6, "hp8", "hp8_english_ci", 1, 1, "", NULL, NULL}, - { 7, "koi8r", "koi8r_general_ci", 1, 1, "", NULL, NULL}, - { 8, "latin1", "latin1_swedish_ci", 1, 1, "", NULL, NULL}, - { 9, "latin2", "latin2_general_ci", 1, 1, "", NULL, NULL}, - { 10, "swe7", "swe7_swedish_ci", 1, 1, "", NULL, NULL}, - { 11, "ascii", "ascii_general_ci", 1, 1, "", NULL, NULL}, - { 12, "ujis", "ujis_japanese_ci", 1, 3, "", mysqlnd_mbcharlen_ujis, check_mb_ujis}, - { 13, "sjis", "sjis_japanese_ci", 1, 2, "", mysqlnd_mbcharlen_sjis, check_mb_sjis}, - { 16, "hebrew", "hebrew_general_ci", 1, 1, "", NULL, NULL}, - { 18, "tis620", "tis620_thai_ci", 1, 1, "", NULL, NULL}, - { 19, "euckr", "euckr_korean_ci", 1, 2, "", mysqlnd_mbcharlen_euckr, check_mb_euckr}, - { 22, "koi8u", "koi8u_general_ci", 1, 1, "", NULL, NULL}, - { 24, "gb2312", "gb2312_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gb2312, check_mb_gb2312}, - { 25, "greek", "greek_general_ci", 1, 1, "", NULL, NULL}, - { 26, "cp1250", "cp1250_general_ci", 1, 1, "", NULL, NULL}, - { 28, "gbk", "gbk_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gbk, check_mb_gbk}, - { 30, "latin5", "latin5_turkish_ci", 1, 1, "", NULL, NULL}, - { 32, "armscii8", "armscii8_general_ci", 1, 1, "", NULL, NULL}, - { 33, "utf8", "utf8_general_ci", 1, 3, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 35, "ucs2", "ucs2_general_ci", 2, 2, "UCS-2 Unicode", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 36, "cp866", "cp866_general_ci", 1, 1, "", NULL, NULL}, - { 37, "keybcs2", "keybcs2_general_ci", 1, 1, "", NULL, NULL}, - { 38, "macce", "macce_general_ci", 1, 1, "", NULL, NULL}, - { 39, "macroman", "macroman_general_ci", 1, 1, "", NULL, NULL}, - { 40, "cp852", "cp852_general_ci", 1, 1, "", NULL, NULL}, - { 41, "latin7", "latin7_general_ci", 1, 1, "", NULL, NULL}, - { 51, "cp1251", "cp1251_general_ci", 1, 1, "", NULL, NULL}, - { 57, "cp1256", "cp1256_general_ci", 1, 1, "", NULL, NULL}, - { 59, "cp1257", "cp1257_general_ci", 1, 1, "", NULL, NULL}, - { 63, "binary", "binary", 1, 1, "", NULL, NULL}, - { 92, "geostd8", "geostd8_general_ci", 1, 1, "", NULL, NULL}, - { 95, "cp932", "cp932_japanese_ci", 1, 2, "", mysqlnd_mbcharlen_cp932, check_mb_cp932}, - { 97, "eucjpms", "eucjpms_japanese_ci", 1, 3, "", mysqlnd_mbcharlen_eucjpms, check_mb_eucjpms}, - { 2, "latin2", "latin2_czech_cs", 1, 1, "", NULL, NULL}, - { 5, "latin1", "latin1_german_ci", 1, 1, "", NULL, NULL}, - { 14, "cp1251", "cp1251_bulgarian_ci", 1, 1, "", NULL, NULL}, - { 15, "latin1", "latin1_danish_ci", 1, 1, "", NULL, NULL}, - { 17, "filename", "filename", 1, 5, "", NULL, NULL}, - { 20, "latin7", "latin7_estonian_cs", 1, 1, "", NULL, NULL}, - { 21, "latin2", "latin2_hungarian_ci", 1, 1, "", NULL, NULL}, - { 23, "cp1251", "cp1251_ukrainian_ci", 1, 1, "", NULL, NULL}, - { 27, "latin2", "latin2_croatian_ci", 1, 1, "", NULL, NULL}, - { 29, "cp1257", "cp1257_lithunian_ci", 1, 1, "", NULL, NULL}, - { 31, "latin1", "latin1_german2_ci", 1, 1, "", NULL, NULL}, - { 34, "cp1250", "cp1250_czech_cs", 1, 1, "", NULL, NULL}, - { 42, "latin7", "latin7_general_cs", 1, 1, "", NULL, NULL}, - { 43, "macce", "macce_bin", 1, 1, "", NULL, NULL}, - { 44, "cp1250", "cp1250_croatian_ci", 1, 1, "", NULL, NULL}, - { 47, "latin1", "latin1_bin", 1, 1, "", NULL, NULL}, - { 48, "latin1", "latin1_general_ci", 1, 1, "", NULL, NULL}, - { 49, "latin1", "latin1_general_cs", 1, 1, "", NULL, NULL}, - { 50, "cp1251", "cp1251_bin", 1, 1, "", NULL, NULL}, - { 52, "cp1251", "cp1251_general_cs", 1, 1, "", NULL, NULL}, - { 53, "macroman", "macroman_bin", 1, 1, "", NULL, NULL}, - { 58, "cp1257", "cp1257_bin", 1, 1, "", NULL, NULL}, - { 60, "armascii8", "armascii8_bin", 1, 1, "", NULL, NULL}, - { 65, "ascii", "ascii_bin", 1, 1, "", NULL, NULL}, - { 66, "cp1250", "cp1250_bin", 1, 1, "", NULL, NULL}, - { 67, "cp1256", "cp1256_bin", 1, 1, "", NULL, NULL}, - { 68, "cp866", "cp866_bin", 1, 1, "", NULL, NULL}, - { 69, "dec8", "dec8_bin", 1, 1, "", NULL, NULL}, - { 70, "greek", "greek_bin", 1, 1, "", NULL, NULL}, - { 71, "hebew", "hebrew_bin", 1, 1, "", NULL, NULL}, - { 72, "hp8", "hp8_bin", 1, 1, "", NULL, NULL}, - { 73, "keybcs2", "keybcs2_bin", 1, 1, "", NULL, NULL}, - { 74, "koi8r", "koi8r_bin", 1, 1, "", NULL, NULL}, - { 75, "koi8u", "koi8u_bin", 1, 1, "", NULL, NULL}, - { 77, "latin2", "latin2_bin", 1, 1, "", NULL, NULL}, - { 78, "latin5", "latin5_bin", 1, 1, "", NULL, NULL}, - { 79, "latin7", "latin7_bin", 1, 1, "", NULL, NULL}, - { 80, "cp850", "cp850_bin", 1, 1, "", NULL, NULL}, - { 81, "cp852", "cp852_bin", 1, 1, "", NULL, NULL}, - { 82, "swe7", "swe7_bin", 1, 1, "", NULL, NULL}, - { 93, "geostd8", "geostd8_bin", 1, 1, "", NULL, NULL}, - { 83, "utf8", "utf8_bin", 1, 3, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 84, "big5", "big5_bin", 1, 2, "", mysqlnd_mbcharlen_big5, check_mb_big5}, - { 85, "euckr", "euckr_bin", 1, 2, "", mysqlnd_mbcharlen_euckr, check_mb_euckr}, - { 86, "gb2312", "gb2312_bin", 1, 2, "", mysqlnd_mbcharlen_gb2312, check_mb_gb2312}, - { 87, "gbk", "gbk_bin", 1, 2, "", mysqlnd_mbcharlen_gbk, check_mb_gbk}, - { 88, "sjis", "sjis_bin", 1, 2, "", mysqlnd_mbcharlen_sjis, check_mb_sjis}, - { 89, "tis620", "tis620_bin", 1, 1, "", NULL, NULL}, - { 90, "ucs2", "ucs2_bin", 2, 2, "UCS-2 Unicode", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 91, "ujis", "ujis_bin", 1, 3, "", mysqlnd_mbcharlen_ujis, check_mb_ujis}, - { 94, "latin1", "latin1_spanish_ci", 1, 1, "", NULL, NULL}, - { 96, "cp932", "cp932_bin", 1, 2, "", mysqlnd_mbcharlen_cp932, check_mb_cp932}, - { 99, "cp1250", "cp1250_polish_ci", 1, 1, "", NULL, NULL}, - { 98, "eucjpms", "eucjpms_bin", 1, 3, "", mysqlnd_mbcharlen_eucjpms, check_mb_eucjpms}, - { 128, "ucs2", "ucs2_unicode_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 129, "ucs2", "ucs2_icelandic_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 130, "ucs2", "ucs2_latvian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 131, "ucs2", "ucs2_romanian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 132, "ucs2", "ucs2_slovenian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 133, "ucs2", "ucs2_polish_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 134, "ucs2", "ucs2_estonian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 135, "ucs2", "ucs2_spanish_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 136, "ucs2", "ucs2_swedish_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 137, "ucs2", "ucs2_turkish_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 138, "ucs2", "ucs2_czech_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 139, "ucs2", "ucs2_danish_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 140, "ucs2", "ucs2_lithunian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 141, "ucs2", "ucs2_slovak_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 142, "ucs2", "ucs2_spanish2_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 143, "ucs2", "ucs2_roman_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 144, "ucs2", "ucs2_persian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 145, "ucs2", "ucs2_esperanto_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 146, "ucs2", "ucs2_hungarian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 147, "ucs2", "ucs2_sinhala_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 192, "utf8", "utf8_general_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 193, "utf8", "utf8_icelandic_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 194, "utf8", "utf8_latvian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 195, "utf8", "utf8_romanian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 196, "utf8", "utf8_slovenian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 197, "utf8", "utf8_polish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 198, "utf8", "utf8_estonian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 119, "utf8", "utf8_spanish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 200, "utf8", "utf8_swedish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 201, "utf8", "utf8_turkish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 202, "utf8", "utf8_czech_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 203, "utf8", "utf8_danish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid }, - { 204, "utf8", "utf8_lithunian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid }, - { 205, "utf8", "utf8_slovak_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 206, "utf8", "utf8_spanish2_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 207, "utf8", "utf8_roman_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 208, "utf8", "utf8_persian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 209, "utf8", "utf8_esperanto_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 210, "utf8", "utf8_hungarian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 192, "utf8mb3", "utf8mb3_general_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 193, "utf8mb3", "utf8mb3_icelandic_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 194, "utf8mb3", "utf8mb3_latvian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 195, "utf8mb3", "utf8mb3_romanian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 196, "utf8mb3", "utf8mb3_slovenian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 197, "utf8mb3", "utf8mb3_polish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 198, "utf8mb3", "utf8mb3_estonian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 119, "utf8mb3", "utf8mb3_spanish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 200, "utf8mb3", "utf8mb3_swedish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 201, "utf8mb3", "utf8mb3_turkish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 202, "utf8mb3", "utf8mb3_czech_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 203, "utf8mb3", "utf8mb3_danish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid }, - { 204, "utf8mb3", "utf8mb3_lithunian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid }, - { 205, "utf8mb3", "utf8mb3_slovak_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 206, "utf8mb3", "utf8mb3_spanish2_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 207, "utf8mb3", "utf8mb3_roman_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 208, "utf8mb3", "utf8mb3_persian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 209, "utf8mb3", "utf8mb3_esperanto_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 210, "utf8mb3", "utf8mb3_hungarian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 211, "utf8mb3", "utf8mb3_sinhala_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 224, "utf8", "utf8_unicode_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 225, "utf8", "utf8_icelandic_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 226, "utf8", "utf8_latvian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 227, "utf8", "utf8_romanian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 228, "utf8", "utf8_slovenian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 229, "utf8", "utf8_polish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 230, "utf8", "utf8_estonian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 231, "utf8", "utf8_spanish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 232, "utf8", "utf8_swedish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 233, "utf8", "utf8_turkish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 234, "utf8", "utf8_czech_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 235, "utf8", "utf8_danish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 236, "utf8", "utf8_lithuanian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 237, "utf8", "utf8_slovak_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 238, "utf8", "utf8_spanish2_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 239, "utf8", "utf8_roman_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 240, "utf8", "utf8_persian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 241, "utf8", "utf8_esperanto_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 242, "utf8", "utf8_hungarian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 243, "utf8", "utf8_sinhala_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 254, "utf8mb3", "utf8mb3_general_cs", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 0, NULL, NULL, 0, 0, NULL, NULL, NULL} -}; + if (start + 2 > end) { + return 0; + } + + if (UTF16_HIGH_HEAD(*start)) { + return (start + 4 <= end) && UTF16_LOW_HEAD(start[2]) ? 4 : 0; + } + + if (UTF16_LOW_HEAD(*start)) { + return 0; + } + return 2; +} + + +static uint mysqlnd_mbcharlen_utf16(unsigned int utf16) +{ + return UTF16_HIGH_HEAD(utf16) ? 4 : 2; +} /* }}} */ +/* {{{ utf32 functions */ +static uint +check_mb_utf32(const char *start __attribute((unused)), const char *end __attribute((unused))) +{ + return 4; +} + + +static uint +mysqlnd_mbcharlen_utf32(unsigned int utf32 __attribute((unused))) +{ + return 4; +} +/* }}} */ + +/* + The server compiles sometimes the full utf-8 (the mb4) as utf8m4, and the old as utf8, + for BC reasons. Sometimes, utf8mb4 is just utf8 but the old charsets are utf8mb3. + Change easily now, with a macro, could be made compilastion dependable. +*/ + +#define UTF8_MB4 "utf8mb4" +#define UTF8_MB3 "utf8" + /* {{{ mysqlnd_charsets */ -const MYSQLND_CHARSET mysqlnd_charsets60[] = +const MYSQLND_CHARSET mysqlnd_charsets[] = { { 1, "big5","big5_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_big5, check_mb_big5}, { 3, "dec8", "dec8_swedisch_ci", 1, 1, "", NULL, NULL}, @@ -494,7 +466,7 @@ const MYSQLND_CHARSET mysqlnd_charsets60[] = { 28, "gbk", "gbk_chinese_ci", 1, 2, "", mysqlnd_mbcharlen_gbk, check_mb_gbk}, { 30, "latin5", "latin5_turkish_ci", 1, 1, "", NULL, NULL}, { 32, "armscii8", "armscii8_general_ci", 1, 1, "", NULL, NULL}, - { 33, "utf8", "utf8_general_ci", 1, 2, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 33, UTF8_MB3, UTF8_MB3"_general_ci", 1, 3, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, { 35, "ucs2", "ucs2_general_ci", 2, 2, "UCS-2 Unicode", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, { 36, "cp866", "cp866_general_ci", 1, 1, "", NULL, NULL}, { 37, "keybcs2", "keybcs2_general_ci", 1, 1, "", NULL, NULL}, @@ -524,14 +496,22 @@ const MYSQLND_CHARSET mysqlnd_charsets60[] = { 42, "latin7", "latin7_general_cs", 1, 1, "", NULL, NULL}, { 43, "macce", "macce_bin", 1, 1, "", NULL, NULL}, { 44, "cp1250", "cp1250_croatian_ci", 1, 1, "", NULL, NULL}, + { 45, UTF8_MB4, UTF8_MB4"_general_ci", 1, 3, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 46, UTF8_MB4, UTF8_MB4"_bin", 1, 3, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, { 47, "latin1", "latin1_bin", 1, 1, "", NULL, NULL}, { 48, "latin1", "latin1_general_ci", 1, 1, "", NULL, NULL}, { 49, "latin1", "latin1_general_cs", 1, 1, "", NULL, NULL}, { 50, "cp1251", "cp1251_bin", 1, 1, "", NULL, NULL}, { 52, "cp1251", "cp1251_general_cs", 1, 1, "", NULL, NULL}, { 53, "macroman", "macroman_bin", 1, 1, "", NULL, NULL}, + { 54, "utf16", "utf16_general_ci", 2, 4, "UTF-16 Unicode", mysqlnd_mbcharlen_utf16, check_mb_utf16}, + { 55, "utf16", "utf16_bin", 2, 4, "UTF-16 Unicode", mysqlnd_mbcharlen_utf16, check_mb_utf16}, { 58, "cp1257", "cp1257_bin", 1, 1, "", NULL, NULL}, +#ifdef USED_TO_BE_SO_BEFORE_MYSQL_5_5 { 60, "armascii8", "armascii8_bin", 1, 1, "", NULL, NULL}, +#endif + { 60, "utf32", "utf32_general_ci", 4, 4, "UTF-32 Unicode", mysqlnd_mbcharlen_utf32, check_mb_utf32}, + { 61, "utf32", "utf32_bin", 4, 4, "UTF-32 Unicode", mysqlnd_mbcharlen_utf32, check_mb_utf32}, { 65, "ascii", "ascii_bin", 1, 1, "", NULL, NULL}, { 66, "cp1250", "cp1250_bin", 1, 1, "", NULL, NULL}, { 67, "cp1256", "cp1256_bin", 1, 1, "", NULL, NULL}, @@ -550,7 +530,7 @@ const MYSQLND_CHARSET mysqlnd_charsets60[] = { 81, "cp852", "cp852_bin", 1, 1, "", NULL, NULL}, { 82, "swe7", "swe7_bin", 1, 1, "", NULL, NULL}, { 93, "geostd8", "geostd8_bin", 1, 1, "", NULL, NULL}, - { 83, "utf8", "utf8_bin", 1, 2, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 83, UTF8_MB3, UTF8_MB3"_bin", 1, 3, "UTF-8 Unicode", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, { 84, "big5", "big5_bin", 1, 2, "", mysqlnd_mbcharlen_big5, check_mb_big5}, { 85, "euckr", "euckr_bin", 1, 2, "", mysqlnd_mbcharlen_euckr, check_mb_euckr}, { 86, "gb2312", "gb2312_bin", 1, 2, "", mysqlnd_mbcharlen_gb2312, check_mb_gb2312}, @@ -583,47 +563,52 @@ const MYSQLND_CHARSET mysqlnd_charsets60[] = { 145, "ucs2", "ucs2_esperanto_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, { 146, "ucs2", "ucs2_hungarian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, { 147, "ucs2", "ucs2_sinhala_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, - { 192, "utf8mb3", "utf8mb3_general_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 193, "utf8mb3", "utf8mb3_icelandic_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 194, "utf8mb3", "utf8mb3_latvian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 195, "utf8mb3", "utf8mb3_romanian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 196, "utf8mb3", "utf8mb3_slovenian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 197, "utf8mb3", "utf8mb3_polish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 198, "utf8mb3", "utf8mb3_estonian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 119, "utf8mb3", "utf8mb3_spanish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 200, "utf8mb3", "utf8mb3_swedish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 201, "utf8mb3", "utf8mb3_turkish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 202, "utf8mb3", "utf8mb3_czech_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 203, "utf8mb3", "utf8mb3_danish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid }, - { 204, "utf8mb3", "utf8mb3_lithunian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid }, - { 205, "utf8mb3", "utf8mb3_slovak_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 206, "utf8mb3", "utf8mb3_spanish2_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 207, "utf8mb3", "utf8mb3_roman_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 208, "utf8mb3", "utf8mb3_persian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 209, "utf8mb3", "utf8mb3_esperanto_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 210, "utf8mb3", "utf8mb3_hungarian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 211, "utf8mb3", "utf8mb3_sinhala_ci", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 224, "utf8", "utf8_unicode_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 225, "utf8", "utf8_icelandic_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 226, "utf8", "utf8_latvian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 227, "utf8", "utf8_romanian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 228, "utf8", "utf8_slovenian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 229, "utf8", "utf8_polish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 230, "utf8", "utf8_estonian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 231, "utf8", "utf8_spanish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 232, "utf8", "utf8_swedish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 233, "utf8", "utf8_turkish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 234, "utf8", "utf8_czech_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 235, "utf8", "utf8_danish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 236, "utf8", "utf8_lithuanian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 237, "utf8", "utf8_slovak_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 238, "utf8", "utf8_spanish2_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 239, "utf8", "utf8_roman_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 240, "utf8", "utf8_persian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 241, "utf8", "utf8_esperanto_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 242, "utf8", "utf8_hungarian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 243, "utf8", "utf8_sinhala_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, - { 254, "utf8mb3", "utf8mb3_general_cs", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 149, "ucs2", "ucs2_croatian_ci", 2, 2, "", mysqlnd_mbcharlen_ucs2, check_mb_ucs2}, /* MDB */ + + { 192, UTF8_MB3, UTF8_MB3"_general_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 193, UTF8_MB3, UTF8_MB3"_icelandic_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 194, UTF8_MB3, UTF8_MB3"_latvian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 195, UTF8_MB3, UTF8_MB3"_romanian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 196, UTF8_MB3, UTF8_MB3"_slovenian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 197, UTF8_MB3, UTF8_MB3"_polish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 198, UTF8_MB3, UTF8_MB3"_estonian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 119, UTF8_MB3, UTF8_MB3"_spanish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 200, UTF8_MB3, UTF8_MB3"_swedish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 201, UTF8_MB3, UTF8_MB3"_turkish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 202, UTF8_MB3, UTF8_MB3"_czech_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 203, UTF8_MB3, UTF8_MB3"_danish_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid }, + { 204, UTF8_MB3, UTF8_MB3"_lithunian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid }, + { 205, UTF8_MB3, UTF8_MB3"_slovak_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 206, UTF8_MB3, UTF8_MB3"_spanish2_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 207, UTF8_MB3, UTF8_MB3"_roman_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 208, UTF8_MB3, UTF8_MB3"_persian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 209, UTF8_MB3, UTF8_MB3"_esperanto_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 210, UTF8_MB3, UTF8_MB3"_hungarian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 211, UTF8_MB3, UTF8_MB3"_sinhala_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, + { 213, UTF8_MB3, UTF8_MB3"_croatian_ci", 1, 3, "", mysqlnd_mbcharlen_utf8mb3, check_mb_utf8mb3_valid}, /*MDB*/ + + { 224, UTF8_MB4, UTF8_MB4"_unicode_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 225, UTF8_MB4, UTF8_MB4"_icelandic_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 226, UTF8_MB4, UTF8_MB4"_latvian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 227, UTF8_MB4, UTF8_MB4"_romanian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 228, UTF8_MB4, UTF8_MB4"_slovenian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 229, UTF8_MB4, UTF8_MB4"_polish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 230, UTF8_MB4, UTF8_MB4"_estonian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 231, UTF8_MB4, UTF8_MB4"_spanish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 232, UTF8_MB4, UTF8_MB4"_swedish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 233, UTF8_MB4, UTF8_MB4"_turkish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 234, UTF8_MB4, UTF8_MB4"_czech_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 235, UTF8_MB4, UTF8_MB4"_danish_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 236, UTF8_MB4, UTF8_MB4"_lithuanian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 237, UTF8_MB4, UTF8_MB4"_slovak_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 238, UTF8_MB4, UTF8_MB4"_spanish2_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 239, UTF8_MB4, UTF8_MB4"_roman_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 240, UTF8_MB4, UTF8_MB4"_persian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 241, UTF8_MB4, UTF8_MB4"_esperanto_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 242, UTF8_MB4, UTF8_MB4"_hungarian_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + { 243, UTF8_MB4, UTF8_MB4"_sinhala_ci", 1, 4, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, + + { 254, UTF8_MB3, UTF8_MB3"_general_cs", 1, 3, "", mysqlnd_mbcharlen_utf8, check_mb_utf8_valid}, { 0, NULL, NULL, 0, 0, NULL, NULL, NULL} }; /* }}} */ diff --git a/ext/mysqlnd/mysqlnd_debug.c b/ext/mysqlnd/mysqlnd_debug.c index 575efacac..692c81ee2 100644 --- a/ext/mysqlnd/mysqlnd_debug.c +++ b/ext/mysqlnd/mysqlnd_debug.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_debug.c 300635 2010-06-21 15:32:26Z andrey $ */ +/* $Id: mysqlnd_debug.c 305389 2010-11-15 23:46:21Z pajoye $ */ #include "php.h" #include "mysqlnd.h" @@ -36,16 +36,6 @@ static const char * const mysqlnd_debug_default_trace_file = "/tmp/mysqlnd.trace #define MYSQLND_ZTS(self) #endif -#define MYSQLND_DEBUG_DUMP_TIME 1 -#define MYSQLND_DEBUG_DUMP_TRACE 2 -#define MYSQLND_DEBUG_DUMP_PID 4 -#define MYSQLND_DEBUG_DUMP_LINE 8 -#define MYSQLND_DEBUG_DUMP_FILE 16 -#define MYSQLND_DEBUG_DUMP_LEVEL 32 -#define MYSQLND_DEBUG_APPEND 64 -#define MYSQLND_DEBUG_FLUSH 128 -#define MYSQLND_DEBUG_TRACE_MEMORY_CALLS 256 - static const char mysqlnd_emalloc_name[] = "_mysqlnd_emalloc"; static const char mysqlnd_pemalloc_name[] = "_mysqlnd_pemalloc"; static const char mysqlnd_ecalloc_name[] = "_mysqlnd_ecalloc"; @@ -81,6 +71,7 @@ const char * mysqlnd_debug_std_no_trace_funcs[] = NULL /* must be always last */ }; + /* {{{ mysqlnd_debug::open */ static enum_func_status MYSQLND_METHOD(mysqlnd_debug, open)(MYSQLND_DEBUG * self, zend_bool reopen) @@ -287,7 +278,6 @@ MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self, flags & MYSQLND_DEBUG_DUMP_LEVEL? level_buffer:"", pipe_buffer, type? type:"", buffer); efree(buffer); - ret = php_stream_write(self->stream, message_line, message_line_len)? PASS:FAIL; efree(message_line); /* allocated by spprintf */ @@ -301,7 +291,7 @@ MYSQLND_METHOD(mysqlnd_debug, log_va)(MYSQLND_DEBUG *self, /* FALSE - The DBG_ calls won't be traced, TRUE - will be traced */ -/* {{{ mysqlnd_res_meta::func_enter */ +/* {{{ mysqlnd_debug::func_enter */ static zend_bool MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, @@ -319,6 +309,12 @@ MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self, while (*p) { if (*p == func_name) { zend_stack_push(&self->call_stack, "", sizeof("")); +#ifndef MYSQLND_PROFILING_DISABLED + if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) { + uint64_t some_time = 0; + zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time)); + } +#endif return FALSE; } p++; @@ -326,6 +322,12 @@ MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self, } zend_stack_push(&self->call_stack, func_name, func_name_len + 1); +#ifndef MYSQLND_PROFILING_DISABLED + if (self->flags & MYSQLND_DEBUG_PROFILE_CALLS) { + uint64_t some_time = 0; + zend_stack_push(&self->call_time_stack, &some_time, sizeof(some_time)); + } +#endif if (zend_hash_num_elements(&self->not_filtered_functions) && 0 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1)) @@ -338,12 +340,34 @@ MYSQLND_METHOD(mysqlnd_debug, func_enter)(MYSQLND_DEBUG * self, } /* }}} */ +#ifndef MYSQLND_PROFILING_DISABLED +struct st_mysqlnd_dbg_function_profile { + uint64_t calls; + uint64_t min_own; + uint64_t max_own; + uint64_t avg_own; + uint64_t own_underporm_calls; + uint64_t min_in_calls; + uint64_t max_in_calls; + uint64_t avg_in_calls; + uint64_t in_calls_underporm_calls; + uint64_t min_total; + uint64_t max_total; + uint64_t avg_total; + uint64_t total_underporm_calls; +}; +#define PROFILE_UNDERPERFORM_THRESHOLD 10 +#endif -/* {{{ mysqlnd_res_meta::func_leave */ +/* {{{ mysqlnd_debug::func_leave */ static enum_func_status -MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file) +MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, uint64_t call_time) { char *func_name; + uint64_t * parent_non_own_time_ptr = NULL, * mine_non_own_time_ptr = NULL; + uint64_t mine_non_own_time = 0; + zend_bool profile_calls = self->flags & MYSQLND_DEBUG_PROFILE_CALLS? TRUE:FALSE; + if ((self->flags & MYSQLND_DEBUG_DUMP_TRACE) == 0 || self->file_name == NULL) { return PASS; } @@ -353,12 +377,92 @@ MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int lin zend_stack_top(&self->call_stack, (void **)&func_name); +#ifndef MYSQLND_PROFILING_DISABLED + if (profile_calls) { + zend_stack_top(&self->call_time_stack, (void **)&mine_non_own_time_ptr); + mine_non_own_time = *mine_non_own_time_ptr; + zend_stack_del_top(&self->call_time_stack); /* callee - removing ourselves */ + } +#endif + if (func_name[0] == '\0') { ; /* don't log that function */ } else if (!zend_hash_num_elements(&self->not_filtered_functions) || 1 == zend_hash_exists(&self->not_filtered_functions, func_name, strlen(func_name) + 1)) { - self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", func_name); +#ifndef MYSQLND_PROFILING_DISABLED + if (FALSE == profile_calls) { +#endif + self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s", func_name); + +#ifndef MYSQLND_PROFILING_DISABLED + } else { + struct st_mysqlnd_dbg_function_profile f_profile_stack = {0}; + struct st_mysqlnd_dbg_function_profile * f_profile = NULL; + uint64_t own_time = call_time - mine_non_own_time; + uint func_name_len = strlen(func_name); + + self->m->log_va(self, line, file, zend_stack_count(&self->call_stack) - 1, NULL, "<%s (total=%u own=%u in_calls=%u)", + func_name, (unsigned int) call_time, (unsigned int) own_time, (unsigned int) mine_non_own_time + ); + + if (SUCCESS == zend_hash_find(&self->function_profiles, func_name, func_name_len + 1, (void **) &f_profile)) { + /* found */ + if (f_profile) { + if (mine_non_own_time < f_profile->min_in_calls) { + f_profile->min_in_calls = mine_non_own_time; + } else if (mine_non_own_time > f_profile->max_in_calls) { + f_profile->max_in_calls = mine_non_own_time; + } + f_profile->avg_in_calls = (f_profile->avg_in_calls * f_profile->calls + mine_non_own_time) / (f_profile->calls + 1); + + if (own_time < f_profile->min_own) { + f_profile->min_own = own_time; + } else if (own_time > f_profile->max_own) { + f_profile->max_own = own_time; + } + f_profile->avg_own = (f_profile->avg_own * f_profile->calls + own_time) / (f_profile->calls + 1); + + if (call_time < f_profile->min_total) { + f_profile->min_total = call_time; + } else if (call_time > f_profile->max_total) { + f_profile->max_total = call_time; + } + f_profile->avg_total = (f_profile->avg_total * f_profile->calls + call_time) / (f_profile->calls + 1); + + ++f_profile->calls; + if (f_profile->calls > PROFILE_UNDERPERFORM_THRESHOLD) { + if (f_profile->avg_in_calls < mine_non_own_time) { + f_profile->in_calls_underporm_calls++; + } + if (f_profile->avg_own < own_time) { + f_profile->own_underporm_calls++; + } + if (f_profile->avg_total < call_time) { + f_profile->total_underporm_calls++; + } + } + } + } else { + /* add */ + f_profile = &f_profile_stack; + f_profile->min_in_calls = f_profile->max_in_calls = f_profile->avg_in_calls = mine_non_own_time; + f_profile->min_total = f_profile->max_total = f_profile->avg_total = call_time; + f_profile->min_own = f_profile->max_own = f_profile->avg_own = own_time; + f_profile->calls = 1; + zend_hash_add(&self->function_profiles, func_name, func_name_len+1, f_profile, sizeof(struct st_mysqlnd_dbg_function_profile), NULL); + } + if ((uint) zend_stack_count(&self->call_time_stack)) { + uint64_t parent_non_own_time = 0; + + zend_stack_top(&self->call_time_stack, (void **)&parent_non_own_time_ptr); + parent_non_own_time = *parent_non_own_time_ptr; + parent_non_own_time += call_time; + zend_stack_del_top(&self->call_time_stack); /* the caller */ + zend_stack_push(&self->call_time_stack, &parent_non_own_time, sizeof(parent_non_own_time)); /* add back the caller */ + } + } +#endif } return zend_stack_del_top(&self->call_stack) == SUCCESS? PASS:FAIL; @@ -366,15 +470,57 @@ MYSQLND_METHOD(mysqlnd_debug, func_leave)(MYSQLND_DEBUG * self, unsigned int lin /* }}} */ -/* {{{ mysqlnd_res_meta::close */ +/* {{{ mysqlnd_debug::close */ static enum_func_status MYSQLND_METHOD(mysqlnd_debug, close)(MYSQLND_DEBUG * self) { MYSQLND_ZTS(self); if (self->stream) { +#ifndef MYSQLND_PROFILING_DISABLED + if (!(self->flags & MYSQLND_DEBUG_FLUSH) && (self->flags & MYSQLND_DEBUG_PROFILE_CALLS)) { + struct st_mysqlnd_dbg_function_profile * f_profile; + HashPosition pos_values; + + self->m->log_va(self, __LINE__, __FILE__, 0, "info : ", + "number of functions: %d", zend_hash_num_elements(&self->function_profiles)); + zend_hash_internal_pointer_reset_ex(&self->function_profiles, &pos_values); + while (zend_hash_get_current_data_ex(&self->function_profiles, (void **) &f_profile, &pos_values) == SUCCESS) { + char *string_key = NULL; + uint string_key_len; + ulong num_key; + + zend_hash_get_current_key_ex(&self->function_profiles, &string_key, &string_key_len, &num_key, 0, &pos_values); + + self->m->log_va(self, __LINE__, __FILE__, -1, "info : ", + "%-40s\tcalls=%5llu own_slow=%5llu in_calls_slow=%5llu total_slow=%5llu" + " min_own=%5llu max_own=%7llu avg_own=%7llu " + " min_in_calls=%5llu max_in_calls=%7llu avg_in_calls=%7llu" + " min_total=%5llu max_total=%7llu avg_total=%7llu" + ,string_key + ,(uint64_t) f_profile->calls + ,(uint64_t) f_profile->own_underporm_calls + ,(uint64_t) f_profile->in_calls_underporm_calls + ,(uint64_t) f_profile->total_underporm_calls + + ,(uint64_t) f_profile->min_own + ,(uint64_t) f_profile->max_own + ,(uint64_t) f_profile->avg_own + ,(uint64_t) f_profile->min_in_calls + ,(uint64_t) f_profile->max_in_calls + ,(uint64_t) f_profile->avg_in_calls + ,(uint64_t) f_profile->min_total + ,(uint64_t) f_profile->max_total + ,(uint64_t) f_profile->avg_total + ); + zend_hash_move_forward_ex(&self->function_profiles, &pos_values); + } + } +#endif + php_stream_free(self->stream, PHP_STREAM_FREE_CLOSE); self->stream = NULL; } + /* no DBG_RETURN please */ return PASS; } /* }}} */ @@ -389,7 +535,9 @@ MYSQLND_METHOD(mysqlnd_debug, free)(MYSQLND_DEBUG * self) self->file_name = NULL; } zend_stack_destroy(&self->call_stack); + zend_stack_destroy(&self->call_time_stack); zend_hash_destroy(&self->not_filtered_functions); + zend_hash_destroy(&self->function_profiles); efree(self); return PASS; } @@ -433,6 +581,11 @@ MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const } if (i + 1 < mode_len && mode[i+1] == ',') { unsigned int j = i + 2; +#ifdef PHP_WIN32 + if (i+4 < mode_len && mode[i+3] == ':' && (mode[i+4] == '\\' || mode[i+5] == '/')) { + j = i + 5; + } +#endif while (j < mode_len) { if (mode[j] == ':') { break; @@ -562,6 +715,10 @@ MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const self->flags |= MYSQLND_DEBUG_TRACE_MEMORY_CALLS; state = PARSER_WAIT_COLON; break; + case 'x': /* mysqlnd extension - profile calls */ + self->flags |= MYSQLND_DEBUG_PROFILE_CALLS; + state = PARSER_WAIT_COLON; + break; default: if (state == PARSER_WAIT_MODIFIER) { #if 0 @@ -588,7 +745,6 @@ MYSQLND_METHOD(mysqlnd_debug, set_mode)(MYSQLND_DEBUG * self, const char * const } /* }}} */ - MYSQLND_CLASS_METHODS_START(mysqlnd_debug) MYSQLND_METHOD(mysqlnd_debug, open), MYSQLND_METHOD(mysqlnd_debug, set_mode), @@ -601,7 +757,6 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_debug) MYSQLND_CLASS_METHODS_END; - /* {{{ mysqlnd_debug_init */ PHPAPI MYSQLND_DEBUG * mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC) @@ -613,11 +768,13 @@ mysqlnd_debug_init(const char * skip_functions[] TSRMLS_DC) ret->nest_level_limit = 0; ret->pid = getpid(); zend_stack_init(&ret->call_stack); + zend_stack_init(&ret->call_time_stack); zend_hash_init(&ret->not_filtered_functions, 0, NULL, NULL, 0); + zend_hash_init(&ret->function_profiles, 0, NULL, NULL, 0); ret->m = & mysqlnd_mysqlnd_debug_methods; ret->skip_functions = skip_functions; - + return ret; } /* }}} */ @@ -634,12 +791,15 @@ PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC) return; } } - + dbg->m->close(dbg); dbg->m->set_mode(dbg, mode); while (zend_stack_count(&dbg->call_stack)) { zend_stack_del_top(&dbg->call_stack); } + while (zend_stack_count(&dbg->call_time_stack)) { + zend_stack_del_top(&dbg->call_time_stack); + } #endif } /* }}} */ @@ -650,7 +810,7 @@ PHPAPI void _mysqlnd_debug(const char * mode TSRMLS_DC) #define __zend_filename "/unknown/unknown" #define __zend_lineno 0 #endif - + #define REAL_SIZE(s) (collect_memory_statistics? (s) + sizeof(size_t) : (s)) #define REAL_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) - sizeof(size_t)) : (p)) #define FAKE_PTR(p) (collect_memory_statistics && (p)? (((char *)(p)) + sizeof(size_t)) : (p)) @@ -1092,7 +1252,9 @@ char * _mysqlnd_pestrdup(const char * const ptr, zend_bool persistent MYSQLND_ME } /* }}} */ -#if MYSQLND_DEBUG_MEMORY +#define MYSQLND_DEBUG_MEMORY 1 + +#if MYSQLND_DEBUG_MEMORY == 0 /* {{{ mysqlnd_zend_mm_emalloc */ static void * mysqlnd_zend_mm_emalloc(size_t size MYSQLND_MEM_D) @@ -1208,8 +1370,6 @@ static char * mysqlnd_zend_mm_pestrdup(const char * const ptr, zend_bool persist #endif -#define MYSQLND_DEBUG_MEMORY 1 - PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator = { #if MYSQLND_DEBUG_MEMORY @@ -1249,7 +1409,7 @@ PHPAPI struct st_mysqlnd_allocator_methods mysqlnd_allocator = /* Follows code borrowed from zend_builtin_functions.c because the functions there are static */ -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE /* {{{ gettraceasstring() macros */ #define TRACE_APPEND_CHR(chr) \ *str = (char*)erealloc(*str, *len + 1 + 1); \ @@ -1593,14 +1753,14 @@ static int mysqlnd_build_trace_args(zval **arg TSRMLS_DC, int num_args, va_list case IS_OBJECT: { char *class_name; zend_uint class_name_len; - int dup; + int dupl; TRACE_APPEND_STR("Object("); - dup = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC); + dupl = zend_get_object_classname(*arg, &class_name, &class_name_len TSRMLS_CC); TRACE_APPEND_STRL(class_name, class_name_len); - if(!dup) { + if (!dupl) { efree(class_name); } diff --git a/ext/mysqlnd/mysqlnd_debug.h b/ext/mysqlnd/mysqlnd_debug.h index f79a8969b..4c6197d36 100644 --- a/ext/mysqlnd/mysqlnd_debug.h +++ b/ext/mysqlnd/mysqlnd_debug.h @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_debug.h 299755 2010-05-25 21:54:21Z andrey $ */ +/* $Id: mysqlnd_debug.h 305878 2010-12-01 10:16:51Z andrey $ */ #ifndef MYSQLND_DEBUG_H #define MYSQLND_DEBUG_H @@ -27,17 +27,17 @@ 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, + 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, + 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, + zend_bool (*func_enter)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, const char * const func_name, unsigned int 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_handle)(MYSQLND_DEBUG *self); + enum_func_status (*func_leave)(MYSQLND_DEBUG * self, unsigned int line, const char * const file, uint64_t call_time); + enum_func_status (*close)(MYSQLND_DEBUG * self); + enum_func_status (*free_handle)(MYSQLND_DEBUG * self); }; @@ -52,7 +52,9 @@ struct st_mysqlnd_debug int pid; char * file_name; zend_stack call_stack; + zend_stack call_time_stack; HashTable not_filtered_functions; + HashTable function_profiles; struct st_mysqlnd_debug_methods *m; const char ** skip_functions; }; @@ -63,15 +65,66 @@ PHPAPI MYSQLND_DEBUG * mysqlnd_debug_init(const char * skip_functions[] TSRMLS_D PHPAPI char * mysqlnd_get_backtrace(uint max_levels, size_t * length TSRMLS_DC); -#if defined(__GNUC__) +#if defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 1400)) +#ifdef PHP_WIN32 +#include "win32/time.h" +#elif defined(NETWARE) +#include <sys/timeval.h> +#include <sys/time.h> +#else +#include <sys/time.h> +#endif + +#ifndef MYSQLND_PROFILING_DISABLED +#define DBG_PROFILE_TIMEVAL_TO_DOUBLE(tp) ((tp.tv_sec * 1000000LL)+ tp.tv_usec) +#define DBG_PROFILE_START_TIME() gettimeofday(&__dbg_prof_tp, NULL); __dbg_prof_start = DBG_PROFILE_TIMEVAL_TO_DOUBLE(__dbg_prof_tp); +#define DBG_PROFILE_END_TIME(duration) gettimeofday(&__dbg_prof_tp, NULL); (duration) = (DBG_PROFILE_TIMEVAL_TO_DOUBLE(__dbg_prof_tp) - __dbg_prof_start); +#else +#define DBG_PROFILE_TIMEVAL_TO_DOUBLE(tp) +#define DBG_PROFILE_START_TIME() +#define DBG_PROFILE_END_TIME(duration) +#endif + #define DBG_INF_EX(dbg_obj, msg) do { if (dbg_skip_trace == FALSE) (dbg_obj)->m->log((dbg_obj), __LINE__, __FILE__, -1, "info : ", (msg)); } while (0) #define DBG_ERR_EX(dbg_obj, msg) do { if (dbg_skip_trace == FALSE) (dbg_obj)->m->log((dbg_obj), __LINE__, __FILE__, -1, "error: ", (msg)); } while (0) #define DBG_INF_FMT_EX(dbg_obj, ...) do { if (dbg_skip_trace == FALSE) (dbg_obj)->m->log_va((dbg_obj), __LINE__, __FILE__, -1, "info : ", __VA_ARGS__); } while (0) #define DBG_ERR_FMT_EX(dbg_obj, ...) do { if (dbg_skip_trace == FALSE) (dbg_obj)->m->log_va((dbg_obj), __LINE__, __FILE__, -1, "error: ", __VA_ARGS__); } while (0) -#define DBG_ENTER_EX(dbg_obj, func_name) zend_bool dbg_skip_trace = TRUE; if ((dbg_obj)) dbg_skip_trace = !(dbg_obj)->m->func_enter((dbg_obj), __LINE__, __FILE__, func_name, strlen(func_name)); -#define DBG_RETURN_EX(dbg_obj, value) do { if ((dbg_obj)) (dbg_obj)->m->func_leave((dbg_obj), __LINE__, __FILE__); return (value); } while (0) -#define DBG_VOID_RETURN_EX(dbg_obj) do { if ((dbg_obj)) (dbg_obj)->m->func_leave((dbg_obj), __LINE__, __FILE__); return; } while (0) +#define DBG_ENTER_EX(dbg_obj, func_name) \ + struct timeval __dbg_prof_tp = {0}; \ + uint64_t __dbg_prof_start = 0; /* initialization is needed */ \ + zend_bool dbg_skip_trace = TRUE; \ + if ((dbg_obj)) { \ + dbg_skip_trace = !(dbg_obj)->m->func_enter((dbg_obj), __LINE__, __FILE__, func_name, strlen(func_name)); \ + } \ + do { \ + if ((dbg_obj) && (dbg_obj)->flags & MYSQLND_DEBUG_PROFILE_CALLS) { \ + DBG_PROFILE_START_TIME(); \ + } \ + } while (0); + +#define DBG_RETURN_EX(dbg_obj, value) \ + do {\ + if ((dbg_obj)) { \ + uint64_t this_call_duration = 0; \ + if ((dbg_obj)->flags & MYSQLND_DEBUG_PROFILE_CALLS) { \ + DBG_PROFILE_END_TIME(this_call_duration); \ + } \ + (dbg_obj)->m->func_leave((dbg_obj), __LINE__, __FILE__, this_call_duration); \ + } \ + return (value);\ + } while (0) +#define DBG_VOID_RETURN_EX(dbg_obj) \ + do {\ + if ((dbg_obj)) { \ + uint64_t this_call_duration = 0; \ + if ((dbg_obj)->flags & MYSQLND_DEBUG_PROFILE_CALLS) { \ + DBG_PROFILE_END_TIME(this_call_duration); \ + } \ + (dbg_obj)->m->func_leave((dbg_obj), __LINE__, __FILE__, this_call_duration); \ + } \ + return;\ + } while (0) #else static inline void DBG_INF_EX(MYSQLND_DEBUG * dbg_obj, const char * const msg) {} @@ -82,7 +135,7 @@ static inline void DBG_ENTER_EX(MYSQLND_DEBUG * dbg_obj, const char * const func #define DBG_RETURN_EX(dbg_obj, value) return (value) #define DBG_VOID_RETURN_EX(dbg_obj) return -#endif +#endif /* defined(__GNUC__) || (defined(_MSC_VER) && (_MSC_VER >= 1400)) */ #if MYSQLND_DBG_ENABLED == 1 diff --git a/ext/mysqlnd/mysqlnd_enum_n_def.h b/ext/mysqlnd/mysqlnd_enum_n_def.h index dbc938b12..209caf245 100644 --- a/ext/mysqlnd/mysqlnd_enum_n_def.h +++ b/ext/mysqlnd/mysqlnd_enum_n_def.h @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_enum_n_def.h 298650 2010-04-27 11:02:51Z andrey $ */ +/* $Id: mysqlnd_enum_n_def.h 305904 2010-12-02 13:59:56Z andrey $ */ #ifndef MYSQLND_ENUM_N_DEF_H #define MYSQLND_ENUM_N_DEF_H @@ -63,7 +63,8 @@ #define SERVER_STATUS_LAST_ROW_SENT 128 #define SERVER_STATUS_DB_DROPPED 256 /* A database was dropped */ #define SERVER_STATUS_NO_BACKSLASH_ESCAPES 512 -#define SERVER_QUERY_WAS_SLOW 1024 +#define SERVER_QUERY_WAS_SLOW 2048 +#define SERVER_PS_OUT_PARAMS 4096 #define MYSQLND_NO_DATA 100 #define MYSQLND_DATA_TRUNCATED 101 @@ -94,24 +95,27 @@ #define CLIENT_SSL_VERIFY_SERVER_CERT (1UL << 30) + +#define MYSQLND_NET_FLAG_USE_COMPRESSION 1 + typedef enum mysqlnd_extension { MYSQLND_MYSQL = 0, - MYSQLND_MYSQLI, + MYSQLND_MYSQLI } enum_mysqlnd_extension; enum { MYSQLND_FETCH_ASSOC = 1, MYSQLND_FETCH_NUM = 2, - MYSQLND_FETCH_BOTH = 1|2, + MYSQLND_FETCH_BOTH = 1|2 }; /* Follow libmysql convention */ typedef enum func_status { PASS = 0, - FAIL = 1, + FAIL = 1 } enum_func_status; typedef enum mysqlnd_query_type @@ -152,7 +156,7 @@ typedef enum mysqlnd_option MYSQL_REPORT_DATA_TRUNCATION, MYSQL_OPT_RECONNECT, MYSQL_OPT_SSL_VERIFY_SERVER_CERT, -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE MYSQLND_OPT_NUMERIC_AND_DATETIME_AS_UNICODE = 200, #endif #ifdef MYSQLND_STRING_TO_INT_CONVERSION @@ -168,6 +172,15 @@ typedef enum mysqlnd_option MYSQLND_OPT_SSL_PASSPHRASE = 209 } enum_mysqlnd_option; +typedef enum mysqlnd_protocol_type +{ + MYSQL_PROTOCOL_DEFAULT = 0, + MYSQL_PROTOCOL_TCP, /* all, supported */ + MYSQL_PROTOCOL_SOCKET, /* unix, supported */ + MYSQL_PROTOCOL_PIPE, /* win32, not-supported */ + MYSQL_PROTOCOL_MEMORY, /* win32, not-supported */ + MYSQL_PROTOCOL_LAST +} enum_mysqlnd_protocol_type; typedef enum mysqlnd_field_types { @@ -284,7 +297,7 @@ typedef enum mysqlnd_connection_state CONN_SENDING_LOAD_DATA, CONN_FETCHING_DATA, CONN_NEXT_RESULT_PENDING, - CONN_QUIT_SENT, /* object is "destroyed" at this stage */ + CONN_QUIT_SENT /* object is "destroyed" at this stage */ } enum_mysqlnd_connection_state; @@ -295,7 +308,7 @@ typedef enum mysqlnd_stmt_state 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 */ + MYSQLND_STMT_USER_FETCHING /* fetch_row_buff or fetch_row_unbuf */ } enum_mysqlnd_stmt_state; @@ -490,6 +503,8 @@ typedef enum mysqlnd_collected_stats STAT_COM_SET_OPTION, STAT_COM_STMT_FETCH, STAT_COM_DAEMON, + STAT_BYTES_RECEIVED_PURE_DATA_TEXT, + STAT_BYTES_RECEIVED_PURE_DATA_PS, STAT_LAST /* Should be always the last */ } enum_mysqlnd_collected_stats; @@ -508,7 +523,7 @@ enum mysqlnd_packet_type PROT_STATS_PACKET, PROT_PREPARE_RESP_PACKET, PROT_CHG_USER_RESP_PACKET, - PROT_LAST, /* should always be last */ + PROT_LAST /* should always be last */ }; diff --git a/ext/mysqlnd/mysqlnd_loaddata.c b/ext/mysqlnd/mysqlnd_loaddata.c index 1885cbc6d..462389824 100644 --- a/ext/mysqlnd/mysqlnd_loaddata.c +++ b/ext/mysqlnd/mysqlnd_loaddata.c @@ -57,7 +57,7 @@ int mysqlnd_local_infile_init(void **ptr, char *filename, void **userdata TSRMLS if (!info) { DBG_RETURN(1); } - + *ptr = info; /* check open_basedir */ @@ -173,7 +173,7 @@ static const char *lost_conn = "Lost connection to MySQL server during LOAD DATA enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC) { - char *buf; + char *buf = NULL; char empty_packet[MYSQLND_HEADER_SIZE]; enum_func_status result = FAIL; unsigned int buflen = 4096; @@ -244,7 +244,9 @@ infile_error: } (*conn->infile.local_infile_end)(info TSRMLS_CC); - mnd_efree(buf); + if (buf) { + mnd_efree(buf); + } DBG_INF_FMT("%s", result == PASS? "PASS":"FAIL"); DBG_RETURN(result); } diff --git a/ext/mysqlnd/mysqlnd_net.c b/ext/mysqlnd/mysqlnd_net.c index 207fa53f0..b6ee73dbb 100644 --- a/ext/mysqlnd/mysqlnd_net.c +++ b/ext/mysqlnd/mysqlnd_net.c @@ -41,14 +41,13 @@ /* {{{ mysqlnd_set_sock_no_delay */ static int -mysqlnd_set_sock_no_delay(php_stream * stream) +mysqlnd_set_sock_no_delay(php_stream * stream TSRMLS_DC) { int socketd = ((php_netstream_data_t*)stream->abstract)->socket; int ret = SUCCESS; int flag = 1; int result = setsockopt(socketd, IPPROTO_TCP, TCP_NODELAY, (char *) &flag, sizeof(int)); - TSRMLS_FETCH(); DBG_ENTER("mysqlnd_set_sock_no_delay"); @@ -184,7 +183,7 @@ MYSQLND_METHOD(mysqlnd_net, connect)(MYSQLND_NET * net, const char * const schem if (!memcmp(scheme, "tcp://", sizeof("tcp://") - 1)) { /* TCP -> Set TCP_NODELAY */ - mysqlnd_set_sock_no_delay(net->stream); + mysqlnd_set_sock_no_delay(net->stream TSRMLS_CC); } { @@ -665,10 +664,8 @@ MYSQLND_METHOD(mysqlnd_net, set_client_option)(MYSQLND_NET * const net, enum mys net->options.timeout_write = *(unsigned int*) value; break; #endif -#ifdef WHEN_SUPPORTED_BY_MYSQLI case MYSQL_OPT_COMPRESS: -#endif - /* currently not supported. Todo!! */ + net->options.flags |= MYSQLND_NET_FLAG_USE_COMPRESSION; break; default: DBG_RETURN(FAIL); diff --git a/ext/mysqlnd/mysqlnd_portability.h b/ext/mysqlnd/mysqlnd_portability.h index 532c71959..b9479150a 100644 --- a/ext/mysqlnd/mysqlnd_portability.h +++ b/ext/mysqlnd/mysqlnd_portability.h @@ -12,6 +12,8 @@ This file is public domain and comes with NO WARRANTY of any kind */ #ifndef MYSQLND_PORTABILITY_H #define MYSQLND_PORTABILITY_H + + /* Comes from global.h as OFFSET, renamed to STRUCT_OFFSET */ #define STRUCT_OFFSET(t, f) ((size_t)(char *)&((t *)0)->f) @@ -479,20 +481,18 @@ typedef union { short/long to/from some place in memory V should be a (not register) variable, M is a pointer to byte */ -#ifdef WORDS_BIGENDIAN +#ifndef float8get +#ifdef WORDS_BIGENDIAN #define float8get(V,M) memcpy((char*) &(V),(char*) (M), sizeof(double)) #define float8store(T,V) memcpy((char*) (T),(char*) &(V), sizeof(double)) - #else - -#ifndef float8get #define float8get(V,M) memcpy((char*) &(V),(char*) (M),sizeof(double)) #define float8store(T,V) memcpy((char*) (T),(char*) &(V),sizeof(double)) -#endif /* float8get */ - #endif /* WORDS_BIGENDIAN */ +#endif /* float8get */ + #endif /* MYSQLND_PORTABILITY_H */ diff --git a/ext/mysqlnd/mysqlnd_priv.h b/ext/mysqlnd/mysqlnd_priv.h index e55522208..eab65b7fc 100644 --- a/ext/mysqlnd/mysqlnd_priv.h +++ b/ext/mysqlnd/mysqlnd_priv.h @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_priv.h 298781 2010-04-29 15:49:51Z andrey $ */ +/* $Id: mysqlnd_priv.h 304984 2010-10-29 15:02:39Z andrey $ */ #ifndef MYSQLND_PRIV_H #define MYSQLND_PRIV_H @@ -33,6 +33,12 @@ #define Z_DELREF_PP(ppz) Z_DELREF_P(*(ppz)) #endif +#if PHP_MAJOR_VERSION >= 6 +#define MYSQLND_UNICODE 1 +#else +#define MYSQLND_UNICODE 0 +#endif + #ifdef ZTS #include "TSRM.h" #endif @@ -45,24 +51,33 @@ #define MYSQLND_CLASS_METHODS_START(class) struct st_##class##_methods MYSQLND_CLASS_METHOD_TABLE_NAME(class) = { #define MYSQLND_CLASS_METHODS_END } -#if PHP_MAJOR_VERSION < 6 +#if MYSQLND_UNICODE #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); \ + zend_u_hash_init(Z_ARRVAL_P(arg), (field_count), NULL, ZVAL_PTR_DTOR, 0, 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);\ + zend_hash_init(Z_ARRVAL_P(arg), (field_count), NULL, ZVAL_PTR_DTOR, 0); \ Z_TYPE_P(arg) = IS_ARRAY;\ } #endif - +#define MYSQLND_DEBUG_DUMP_TIME 1 +#define MYSQLND_DEBUG_DUMP_TRACE 2 +#define MYSQLND_DEBUG_DUMP_PID 4 +#define MYSQLND_DEBUG_DUMP_LINE 8 +#define MYSQLND_DEBUG_DUMP_FILE 16 +#define MYSQLND_DEBUG_DUMP_LEVEL 32 +#define MYSQLND_DEBUG_APPEND 64 +#define MYSQLND_DEBUG_FLUSH 128 +#define MYSQLND_DEBUG_TRACE_MEMORY_CALLS 256 +#define MYSQLND_DEBUG_PROFILE_CALLS 512 /* Client Error codes */ diff --git a/ext/mysqlnd/mysqlnd_ps.c b/ext/mysqlnd/mysqlnd_ps.c index fa8be3ec2..b332d3de7 100644 --- a/ext/mysqlnd/mysqlnd_ps.c +++ b/ext/mysqlnd/mysqlnd_ps.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_ps.c 300735 2010-06-24 19:52:13Z andrey $ */ +/* $Id: mysqlnd_ps.c 306051 2010-12-07 11:13:55Z andrey $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_wireprotocol.h" @@ -52,8 +52,6 @@ enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC); static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC); -static void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC); - /* {{{ mysqlnd_stmt::store_result */ static MYSQLND_RES * MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC) @@ -175,7 +173,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC) } if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) { - stmt->upsert_status.affected_rows = result->stored_data->row_count; + stmt->upsert_status.affected_rows = result->stored_data->row_count; stmt->state = MYSQLND_STMT_PREPARED; result->type = MYSQLND_RES_PS_BUF; } else { @@ -227,10 +225,15 @@ MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC) DBG_RETURN(FAIL); } - /* Free space for next result */ - mysqlnd_internal_free_stmt_content(s TSRMLS_CC); + DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); + DBG_INF_FMT("server_status=%u cursor=%u", conn->upsert_status.server_status, conn->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); - DBG_RETURN(s->m->parse_execute_response(s TSRMLS_CC)); + /* Free space for next result */ + s->m->free_stmt_content(s TSRMLS_CC); + { + enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC); + DBG_RETURN(ret); + } } /* }}} */ @@ -290,7 +293,7 @@ mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC) if (!prepare_resp) { SET_OOM_ERROR(stmt->error_info); SET_OOM_ERROR(stmt->conn->error_info); - goto done; + goto done; } if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) { @@ -435,13 +438,19 @@ MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const } if (stmt_to_prepare != stmt) { - /* Free old buffers, binding and resources on server */ - s->m->net_close(s, TRUE TSRMLS_CC); - - memcpy(stmt, stmt_to_prepare, sizeof(MYSQLND_STMT_DATA)); - - /* Now we will have a clean new statement object */ - mnd_pefree(stmt_to_prepare, stmt_to_prepare->persistent); + /* swap */ + size_t real_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *); + char * tmp_swap = mnd_malloc(real_size); + memcpy(tmp_swap, s, real_size); + memcpy(s, s_to_prepare, real_size); + memcpy(s_to_prepare, tmp_swap, real_size); + mnd_free(tmp_swap); + { + MYSQLND_STMT_DATA * tmp_swap_data = stmt_to_prepare; + stmt_to_prepare = stmt; + stmt = tmp_swap_data; + } + s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC); } stmt->state = MYSQLND_STMT_PREPARED; DBG_INF("PASS"); @@ -482,10 +491,17 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC) /* close the statement here, the connection has been closed */ } stmt->state = MYSQLND_STMT_PREPARED; + stmt->send_types_to_server = 1; } else { + /* + stmt->send_types_to_server has already been set to 0 in + mysqlnd_stmt_execute_generate_request / mysqlnd_stmt_execute_store_params + In case there is a situation in which binding was done for integer and the + value is > LONG_MAX or < LONG_MIN, there is string conversion and we have + to resend the types. Next execution will also need to resend the type. + */ SET_EMPTY_ERROR(stmt->error_info); SET_EMPTY_ERROR(stmt->conn->error_info); - stmt->send_types_to_server = 0; stmt->upsert_status = conn->upsert_status; stmt->state = MYSQLND_STMT_EXECUTED; if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type == QUERY_LOAD_LOCAL) { @@ -545,6 +561,15 @@ mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC) } } } +/* #ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET */ +#if A0 + if (stmt->upsert_status.server_status & SERVER_PS_OUT_PARAMS) { + s->m->free_stmt_content(s TSRMLS_CC); + DBG_INF("PS OUT Variable RSet, skipping"); + /* OUT params result set. Skip for now to retain compatibility */ + ret = mysqlnd_stmt_execute_parse_response(s TSRMLS_CC); + } +#endif DBG_INF(ret == PASS? "PASS":"FAIL"); DBG_RETURN(ret); @@ -572,7 +597,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC) SET_ERROR_AFF_ROWS(stmt); SET_ERROR_AFF_ROWS(stmt->conn); - + if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) { /* We don need to copy the data from the buffers which we will clean. @@ -690,6 +715,8 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC) ret = s->m->parse_execute_response(s TSRMLS_CC); + DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status.server_status, stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS); + if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status.affected_rows) { MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status.affected_rows); } @@ -869,7 +896,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) { if ( (Z_TYPE_P(data) == IS_STRING -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE || Z_TYPE_P(data) == IS_UNICODE #endif ) @@ -904,7 +931,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int stmt->error_info = row_packet->error_info; } CONN_SET_STATE(result->conn, CONN_READY); - result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ + result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */ } else if (row_packet->eof) { DBG_INF("EOF"); /* Mark the connection as usable again */ @@ -1059,7 +1086,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla Z_TYPE_P(data), Z_REFCOUNT_P(stmt->result_bind[i].zv)); if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data))) { if ((Z_TYPE_P(data) == IS_STRING -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE || Z_TYPE_P(data) == IS_UNICODE #endif ) @@ -1258,7 +1285,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned in MYSQLND * conn; zend_uchar *cmd_buf; enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA; - + DBG_ENTER("mysqlnd_stmt::send_long_data"); if (!stmt || !stmt->conn) { DBG_RETURN(FAIL); @@ -1313,16 +1340,15 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned in memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length); /* COM_STMT_SEND_LONG_DATA doesn't send an OK packet*/ - ret = conn->m->simple_command(conn, cmd, (char *)cmd_buf, packet_len, - PROT_LAST , FALSE, TRUE TSRMLS_CC); + ret = conn->m->simple_command(conn, cmd, (char *)cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC); mnd_efree(cmd_buf); if (FAIL == ret) { stmt->error_info = conn->error_info; } } else { ret = FAIL; - SET_OOM_ERROR(stmt->error_info); - SET_OOM_ERROR(conn->error_info); + SET_OOM_ERROR(stmt->error_info); + SET_OOM_ERROR(conn->error_info); } /* Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not @@ -1467,7 +1493,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigne DBG_RETURN(FAIL); } } - + /* Prevent from freeing */ /* Don't update is_ref, or we will leak during conversion */ Z_ADDREF_P(zv); @@ -1482,7 +1508,7 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigne } stmt->param_bind[param_no].zv = zv; stmt->param_bind[param_no].type = type; - + stmt->send_types_to_server = 1; } DBG_INF("PASS"); @@ -1805,7 +1831,7 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC) if (result) { result->m.free_result(result, TRUE TSRMLS_CC); } - DBG_RETURN(NULL); + DBG_RETURN(NULL); } /* }}} */ @@ -1817,39 +1843,42 @@ MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s, const void * const value TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - unsigned long val = *(unsigned long *) value; DBG_ENTER("mysqlnd_stmt::attr_set"); if (!stmt) { DBG_RETURN(FAIL); } - DBG_INF_FMT("stmt=%lu attr_type=%u value=%lu", stmt->stmt_id, attr_type, val); + DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type); switch (attr_type) { - case STMT_ATTR_UPDATE_MAX_LENGTH: + case STMT_ATTR_UPDATE_MAX_LENGTH:{ + zend_uchar bval = *(zend_uchar *) value; /* XXX : libmysql uses my_bool, but mysqli uses ulong as storage on the stack and mysqlnd won't be used out of the scope of PHP -> use ulong. */ - stmt->update_max_length = val? TRUE:FALSE; + stmt->update_max_length = bval? TRUE:FALSE; break; + } case STMT_ATTR_CURSOR_TYPE: { - if (val > (unsigned long) CURSOR_TYPE_READ_ONLY) { + unsigned int ival = *(unsigned int *) value; + if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) { SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented"); DBG_INF("FAIL"); DBG_RETURN(FAIL); } - stmt->flags = val; + stmt->flags = ival; break; } case STMT_ATTR_PREFETCH_ROWS: { - if (val == 0) { - val = MYSQLND_DEFAULT_PREFETCH_ROWS; - } else if (val > 1) { + unsigned int ival = *(unsigned int *) value; + if (ival == 0) { + ival = MYSQLND_DEFAULT_PREFETCH_ROWS; + } else if (ival > 1) { SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented"); DBG_INF("FAIL"); DBG_RETURN(FAIL); } - stmt->prefetch_rows = val; + stmt->prefetch_rows = ival; break; } default: @@ -2056,12 +2085,12 @@ mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param /* }}} */ -/* {{{ mysqlnd_internal_free_stmt_content */ +/* {{{ mysqlnd_stmt::free_stmt_content */ static void -mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const s TSRMLS_DC) +MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - DBG_ENTER("mysqlnd_internal_free_stmt_content"); + DBG_ENTER("mysqlnd_stmt::free_stmt_content"); if (!stmt) { DBG_VOID_RETURN; } @@ -2112,7 +2141,7 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_boo MYSQLND_STMT_DATA * stmt = s? s->data:NULL; MYSQLND * conn; zend_uchar cmd_buf[STMT_ID_LENGTH /* statement id */]; - enum_mysqlnd_collected_stats stat = STAT_LAST; + enum_mysqlnd_collected_stats statistic = STAT_LAST; DBG_ENTER("mysqlnd_stmt::net_close"); if (!stmt || !stmt->conn) { @@ -2163,16 +2192,16 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_boo } switch (stmt->execute_count) { case 0: - stat = STAT_PS_PREPARED_NEVER_EXECUTED; + statistic = STAT_PS_PREPARED_NEVER_EXECUTED; break; case 1: - stat = STAT_PS_PREPARED_ONCE_USED; + statistic = STAT_PS_PREPARED_ONCE_USED; break; default: break; } - if (stat != STAT_LAST) { - MYSQLND_INC_CONN_STATISTIC(conn->stats, stat); + if (statistic != STAT_LAST) { + MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic); } if (stmt->execute_cmd_buffer.buffer) { @@ -2180,7 +2209,7 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_boo stmt->execute_cmd_buffer.buffer = NULL; } - mysqlnd_internal_free_stmt_content(s TSRMLS_CC); + s->m->free_stmt_content(s TSRMLS_CC); if (stmt->conn) { stmt->conn->m->free_reference(stmt->conn TSRMLS_CC); @@ -2196,7 +2225,7 @@ static enum_func_status MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC) { MYSQLND_STMT_DATA * stmt = s? s->data:NULL; - enum_func_status ret; + enum_func_status ret = FAIL; zend_bool persistent = s->persistent; DBG_ENTER("mysqlnd_stmt::dtor"); @@ -2318,7 +2347,8 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_stmt) MYSQLND_METHOD(mysqlnd_stmt, free_result_bind), MYSQLND_METHOD(mysqlnd_stmt, server_status), mysqlnd_stmt_execute_generate_request, - mysqlnd_stmt_execute_parse_response + mysqlnd_stmt_execute_parse_response, + MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content) MYSQLND_CLASS_METHODS_END; @@ -2360,7 +2390,7 @@ MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn TSRMLS_DC) DBG_RETURN(ret); } while (0); - + SET_OOM_ERROR(conn->error_info); if (ret) { ret->m->dtor(ret, TRUE TSRMLS_CC); diff --git a/ext/mysqlnd/mysqlnd_ps_codec.c b/ext/mysqlnd/mysqlnd_ps_codec.c index 9256763a9..7e15f2e90 100644 --- a/ext/mysqlnd/mysqlnd_ps_codec.c +++ b/ext/mysqlnd/mysqlnd_ps_codec.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_ps_codec.c 300735 2010-06-24 19:52:13Z andrey $ */ +/* $Id: mysqlnd_ps_codec.c 304131 2010-10-06 06:08:55Z andrey $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_wireprotocol.h" @@ -84,7 +84,7 @@ void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field, #endif /* #if SIZEOF_LONG==4 */ { if (byte_count < 8 || uval <= L64(9223372036854775807)) { - ZVAL_LONG(zv, uval); + ZVAL_LONG(zv, (long) uval); /* the cast is safe, we are in the range */ } else { DBG_INF("stringify"); tmp_len = sprintf((char *)&tmp, MYSQLND_LLU_SPEC, uval); @@ -112,12 +112,12 @@ void ps_fetch_from_1_to_8_bytes(zval *zv, const MYSQLND_FIELD * const field, } else #endif /* SIZEOF */ { - ZVAL_LONG(zv, lval); + ZVAL_LONG(zv, (long) lval); /* the cast is safe, we are in the range */ } } if (tmp_len) { -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE if (as_unicode) { DBG_INF("stringify"); ZVAL_UTF8_STRINGL(zv, tmp, tmp_len, ZSTR_DUPLICATE); @@ -231,7 +231,7 @@ void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field, { struct st_mysqlnd_time t; unsigned int length; /* First byte encodes the length*/ - char *to; + char * value; DBG_ENTER("ps_fetch_time"); if ((length = php_mysqlnd_net_field_length(row))) { @@ -262,17 +262,17 @@ void ps_fetch_time(zval *zv, const MYSQLND_FIELD * const field, 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); + length = spprintf(&value, 0, "%s%02u:%02u:%02u", (t.neg ? "-" : ""), t.hour, t.minute, t.second); - DBG_INF_FMT("%s", to); -#if PHP_MAJOR_VERSION >= 6 + DBG_INF_FMT("%s", value); +#if MYSQLND_UNICODE if (!as_unicode) { #endif - ZVAL_STRINGL(zv, to, length, 1); - efree(to); /* allocated by spprintf */ -#if PHP_MAJOR_VERSION >= 6 + ZVAL_STRINGL(zv, value, length, 1); + efree(value); /* allocated by spprintf */ +#if MYSQLND_UNICODE } else { - ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE); + ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE); } #endif DBG_VOID_RETURN; @@ -288,7 +288,7 @@ void ps_fetch_date(zval *zv, const MYSQLND_FIELD * const field, { struct st_mysqlnd_time t = {0}; unsigned int length; /* First byte encodes the length*/ - char *to; + char * value; DBG_ENTER("ps_fetch_date"); if ((length = php_mysqlnd_net_field_length(row))) { @@ -313,17 +313,17 @@ void ps_fetch_date(zval *zv, const MYSQLND_FIELD * const field, 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); + length = spprintf(&value, 0, "%04u-%02u-%02u", t.year, t.month, t.day); - DBG_INF_FMT("%s", to); -#if PHP_MAJOR_VERSION >= 6 + DBG_INF_FMT("%s", value); +#if MYSQLND_UNICODE if (!as_unicode) { #endif - ZVAL_STRINGL(zv, to, length, 1); - efree(to); /* allocated by spprintf */ -#if PHP_MAJOR_VERSION >= 6 + ZVAL_STRINGL(zv, value, length, 1); + efree(value); /* allocated by spprintf */ +#if MYSQLND_UNICODE } else { - ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE); + ZVAL_UTF8_STRINGL(zv, value, length, ZSTR_AUTOFREE); } #endif DBG_VOID_RETURN; @@ -339,7 +339,7 @@ void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field, { struct st_mysqlnd_time t; unsigned int length; /* First byte encodes the length*/ - char *to; + char * value; DBG_ENTER("ps_fetch_datetime"); if ((length = php_mysqlnd_net_field_length(row))) { @@ -371,16 +371,16 @@ void ps_fetch_datetime(zval *zv, const MYSQLND_FIELD * const field, 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", + length = spprintf(&value, 0, "%04u-%02u-%02u %02u:%02u:%02u", t.year, t.month, t.day, t.hour, t.minute, t.second); - DBG_INF_FMT("%s", to); -#if PHP_MAJOR_VERSION >= 6 + DBG_INF_FMT("%s", value); +#if MYSQLND_UNICODE if (!as_unicode) { #endif - ZVAL_STRINGL(zv, to, length, 1); - efree(to); /* allocated by spprintf */ -#if PHP_MAJOR_VERSION >= 6 + ZVAL_STRINGL(zv, value, length, 1); + efree(value); /* allocated by spprintf */ +#if MYSQLND_UNICODE } else { ZVAL_UTF8_STRINGL(zv, to, length, ZSTR_AUTOFREE); } @@ -403,10 +403,7 @@ void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field, unsigned long length = php_mysqlnd_net_field_length(row); DBG_ENTER("ps_fetch_string"); DBG_INF_FMT("len = %lu", length); -#if PHP_MAJOR_VERSION < 6 - DBG_INF("copying from the row buffer"); - ZVAL_STRINGL(zv, (char *)*row, length, 1); -#else +#if MYSQLND_UNICODE if (field->charsetnr == MYSQLND_BINARY_CHARSET_NR) { DBG_INF("Binary charset"); ZVAL_STRINGL(zv, (char *)*row, length, 1); @@ -414,6 +411,9 @@ void ps_fetch_string(zval *zv, const MYSQLND_FIELD * const field, DBG_INF_FMT("copying from the row buffer"); ZVAL_UTF8_STRINGL(zv, (char*)*row, length, ZSTR_DUPLICATE); } +#else + DBG_INF("copying from the row buffer"); + ZVAL_STRINGL(zv, (char *)*row, length, 1); #endif (*row) += length; @@ -482,7 +482,7 @@ void _mysqlnd_init_ps_fetch_subsystem() 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; @@ -493,11 +493,11 @@ void _mysqlnd_init_ps_fetch_subsystem() 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].func = ps_fetch_string; 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; @@ -507,7 +507,7 @@ void _mysqlnd_init_ps_fetch_subsystem() 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; @@ -519,7 +519,7 @@ void _mysqlnd_init_ps_fetch_subsystem() 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; @@ -608,12 +608,47 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar size_t data_size = 0; zval **copies = NULL;/* if there are different types */ enum_func_status ret = FAIL; + int resend_types_next_time = 0; DBG_ENTER("mysqlnd_stmt_execute_store_params"); /* 1. Store type information */ - if (stmt->send_types_to_server) { + /* + check if need to send the types even if stmt->send_types_to_server is 0. This is because + if we send "i" (42) then the type will be int and the server will expect int. However, if next + time we try to send > LONG_MAX, the conversion to string will send a string and the server + won't expect it and interpret the value as 0. Thus we need to resend the types, if any such values + occur, and force resend for the next execution. + */ + for (i = 0; i < stmt->param_count; i++) { + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && + (stmt->param_bind[i].type == MYSQL_TYPE_LONG || stmt->param_bind[i].type == MYSQL_TYPE_LONGLONG)) + { + /* always copy the var, because we do many conversions */ + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG && + PASS != mysqlnd_stmt_copy_it(&copies, stmt->param_bind[i].zv, stmt->param_count, i TSRMLS_CC)) + { + SET_OOM_ERROR(stmt->error_info); + goto end; + } + /* + if it doesn't fit in a long send it as a string. + Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX + */ + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { + zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + convert_to_double_ex(&tmp_data); + if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) { + stmt->send_types_to_server = resend_types_next_time = 1; + } + } + } + } + int1store(*p, stmt->send_types_to_server); + (*p)++; + + 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; @@ -626,21 +661,46 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } memcpy(tmp_buf, *buf, offset); *buf = tmp_buf; - + /* Update our pos pointer */ *p = *buf + offset; } for (i = 0; i < stmt->param_count; i++) { + short current_type = stmt->param_bind[i].type; /* 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; + if (current_type == MYSQL_TYPE_LONG) { + current_type = MYSQL_TYPE_LONGLONG; } #endif - int2store(*p, stmt->param_bind[i].type); + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_NULL && (current_type == MYSQL_TYPE_LONG || current_type == MYSQL_TYPE_LONGLONG)) { + /* + if it doesn't fit in a long send it as a string. + Check bug #52891 : Wrong data inserted with mysqli/mysqlnd when using bind_param, value > LONG_MAX + */ + if (Z_TYPE_P(stmt->param_bind[i].zv) != IS_LONG) { + zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + + convert_to_double_ex(&tmp_data); + if (Z_DVAL_P(tmp_data) > LONG_MAX || Z_DVAL_P(tmp_data) < LONG_MIN) { + convert_to_string_ex(&tmp_data); + current_type = MYSQL_TYPE_VAR_STRING; + /* + don't change stmt->param_bind[i].type to MYSQL_TYPE_VAR_STRING + we force convert_to_long_ex in all cases, thus the type will be right in the next switch. + if the type is however not long, then we will do a goto in the next switch. + We want to preserve the original bind type given by the user. Thus, we do these hacks. + */ + } else { + convert_to_long_ex(&tmp_data); + } + } + } + int2store(*p, current_type); *p+= 2; } } + stmt->send_types_to_server = resend_types_next_time; /* 2. Store data */ /* 2.1 Calculate how much space we need */ @@ -654,9 +714,11 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar for (j = i + 1; j < stmt->param_count; j++) { if (stmt->param_bind[j].zv == the_var) { /* Double binding of the same zval, make a copy */ - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { - SET_OOM_ERROR(stmt->error_info); - goto end; + if (!copies || !copies[i]) { + if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { + SET_OOM_ERROR(stmt->error_info); + goto end; + } } break; } @@ -674,23 +736,25 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } } break; -#if SIZEOF_LONG==8 case MYSQL_TYPE_LONGLONG: + { + zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + if (Z_TYPE_P(tmp_data) == IS_STRING) { + goto use_string; + } + convert_to_long_ex(&tmp_data); + } data_size += 8; -#elif SIZEOF_LONG==4 + break; case MYSQL_TYPE_LONG: - data_size += 4; -#else -#error "Should not happen" -#endif - if (Z_TYPE_P(the_var) != IS_LONG) { - if (!copies || !copies[i]) { - if (PASS != mysqlnd_stmt_copy_it(&copies, the_var, stmt->param_count, i TSRMLS_CC)) { - SET_OOM_ERROR(stmt->error_info); - goto end; - } + { + zval *tmp_data = (copies && copies[i])? copies[i]: stmt->param_bind[i].zv; + if (Z_TYPE_P(tmp_data) == IS_STRING) { + goto use_string; } + convert_to_long_ex(&tmp_data); } + data_size += 4; break; case MYSQL_TYPE_LONG_BLOB: if (!(stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED)) { @@ -703,11 +767,12 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } break; case MYSQL_TYPE_VAR_STRING: +use_string: data_size += 8; /* max 8 bytes for size */ -#if PHP_MAJOR_VERSION < 6 - if (Z_TYPE_P(the_var) != IS_STRING) -#elif PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE if (Z_TYPE_P(the_var) != IS_STRING || Z_TYPE_P(the_var) == IS_UNICODE) +#else + if (Z_TYPE_P(the_var) != IS_STRING) #endif { if (!copies || !copies[i]) { @@ -717,7 +782,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar } } the_var = copies[i]; -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE if (Z_TYPE_P(the_var) == IS_UNICODE) { zval_unicode_to_string_ex(the_var, UG(utf8_conv) TSRMLS_CC); } @@ -727,7 +792,6 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar data_size += Z_STRLEN_P(the_var); break; } - } /* 2.2 Enlarge the buffer, if needed */ @@ -757,7 +821,7 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar /* 2.3 Store the actual data */ for (i = 0; i < stmt->param_count; i++) { - zval *data = copies && copies[i]? copies[i]: stmt->param_bind[i].zv; + zval *data = (copies && copies[i])? copies[i]: 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)); @@ -768,21 +832,22 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar float8store(*p, Z_DVAL_P(data)); (*p) += 8; break; -#if SIZEOF_LONG==8 case MYSQL_TYPE_LONGLONG: - convert_to_long_ex(&data); + if (Z_TYPE_P(data) == IS_STRING) { + goto send_string; + } + /* data has alreade been converted to long */ int8store(*p, Z_LVAL_P(data)); (*p) += 8; break; -#elif SIZEOF_LONG==4 case MYSQL_TYPE_LONG: - convert_to_long_ex(&data); + if (Z_TYPE_P(data) == IS_STRING) { + goto send_string; + } + /* data has alreade been converted to long */ 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; @@ -791,7 +856,9 @@ mysqlnd_stmt_execute_store_params(MYSQLND_STMT * s, zend_uchar **buf, zend_uchar *p = php_mysqlnd_net_store_length(*p, 0); } break; - case MYSQL_TYPE_VAR_STRING:{ + case MYSQL_TYPE_VAR_STRING: +send_string: + { 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); @@ -855,10 +922,6 @@ mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** requ memset(p, 0, null_count); p += null_count; - - int1store(p, stmt->send_types_to_server); - p++; - ret = mysqlnd_stmt_execute_store_params(s, &cmd_buffer, &p, &cmd_buffer_length, null_byte_offset TSRMLS_CC); *free_buffer = (cmd_buffer != stmt->execute_cmd_buffer.buffer); diff --git a/ext/mysqlnd/mysqlnd_result.c b/ext/mysqlnd/mysqlnd_result.c index 645c81905..1d0106e0a 100644 --- a/ext/mysqlnd/mysqlnd_result.c +++ b/ext/mysqlnd/mysqlnd_result.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_result.c 301234 2010-07-13 13:02:00Z andrey $ */ +/* $Id: mysqlnd_result.c 304183 2010-10-07 13:49:00Z andrey $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_wireprotocol.h" @@ -42,14 +42,14 @@ MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const resu zval **data_cursor = result->stored_data? result->stored_data->data:NULL; zval **data_begin = result->stored_data? result->stored_data->data:NULL; unsigned int field_count = result->meta? result->meta->field_count : 0; - unsigned int row_count = result->stored_data? result->stored_data->row_count:0; + uint64_t row_count = result->stored_data? result->stored_data->row_count:0; enum_func_status ret = PASS; DBG_ENTER("mysqlnd_res::initialize_result_set_rest"); if (!data_cursor || row_count == result->stored_data->initialized_rows) { DBG_RETURN(ret); } - while ((data_cursor - data_begin) < (row_count * field_count)) { + while ((data_cursor - data_begin) < (int)(row_count * field_count)) { if (NULL == data_cursor[0]) { enum_func_status rc = result->m.row_decoder( result->stored_data->row_buffers[(data_cursor - data_begin) / field_count], @@ -86,19 +86,23 @@ MYSQLND_METHOD(mysqlnd_res, initialize_result_set_rest)(MYSQLND_RES * const resu /* }}} */ - /* {{{ mysqlnd_palloc_zval_ptr_dtor */ +static void mysqlnd_palloc_zval_ptr_dtor(zval **zv, enum_mysqlnd_res_type type, zend_bool * copy_ctor_called TSRMLS_DC) { DBG_ENTER("mysqlnd_palloc_zval_ptr_dtor"); - *copy_ctor_called = FALSE; - + if (!zv || !*zv) { + *copy_ctor_called = FALSE; + DBG_ERR_FMT("zv was NULL"); + DBG_VOID_RETURN; + } /* 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) { + *copy_ctor_called = FALSE; ; /* do nothing, zval_ptr_dtor will do the job*/ } else if (Z_REFCOUNT_PP(zv) > 1) { /* @@ -120,6 +124,12 @@ void mysqlnd_palloc_zval_ptr_dtor(zval **zv, enum_mysqlnd_res_type type, zend_bo } *copy_ctor_called = TRUE; } else { + /* + noone but us point to this, so we can safely ZVAL_NULL the zval, + so Zend does not try to free what the zval points to - which is + in result set buffers + */ + *copy_ctor_called = FALSE; if (Z_TYPE_PP(zv) == IS_STRING) { ZVAL_NULL(*zv); } @@ -152,18 +162,16 @@ MYSQLND_METHOD(mysqlnd_res, unbuffered_free_last_data)(MYSQLND_RES * result TSRM for (i = 0; i < result->field_count; i++) { mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]), result->type, ©_ctor_called TSRMLS_CC); if (copy_ctor_called) { - ctor_called_count++; + ++ctor_called_count; } } DBG_INF_FMT("copy_ctor_called_count=%u", ctor_called_count); /* By using value3 macros we hold a mutex only once, there is no value2 */ - MYSQLND_INC_CONN_STATISTIC_W_VALUE3(global_stats, + MYSQLND_INC_CONN_STATISTIC_W_VALUE2(global_stats, STAT_COPY_ON_WRITE_PERFORMED, ctor_called_count, STAT_COPY_ON_WRITE_SAVED, - result->field_count - ctor_called_count, - STAT_COPY_ON_WRITE_PERFORMED, 0); - + result->field_count - ctor_called_count); /* Free last row's zvals */ mnd_efree(unbuf->last_row_data); unbuf->last_row_data = NULL; @@ -186,31 +194,37 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC) { MYSQLND_RES_BUFFERED *set = result->stored_data; unsigned int field_count = result->field_count; - int row; + int64_t row; DBG_ENTER("mysqlnd_res::free_buffered_data"); DBG_INF_FMT("Freeing "MYSQLND_LLU_SPEC" row(s)", set->row_count); DBG_INF("Freeing data & row_buffer"); if (set->data) { + unsigned int copy_on_write_performed = 0; + unsigned int copy_on_write_saved = 0; DBG_INF_FMT("before: real_usage=%lu usage=%lu", zend_memory_usage(TRUE TSRMLS_CC), zend_memory_usage(FALSE TSRMLS_CC)); for (row = set->row_count - 1; row >= 0; row--) { zval **current_row = set->data + row * field_count; MYSQLND_MEMORY_POOL_CHUNK *current_buffer = set->row_buffers[row]; - int col; + int64_t col; - for (col = field_count - 1; col >= 0; --col) { - zend_bool copy_ctor_called; - if (current_row == NULL || current_row[0] == NULL) { - break;/* row that was never initialized */ - } - mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), result->type, ©_ctor_called TSRMLS_CC); + if (current_row != NULL) { + for (col = field_count - 1; col >= 0; --col) { + if (current_row[col]) { + zend_bool copy_ctor_called; + mysqlnd_palloc_zval_ptr_dtor(&(current_row[col]), result->type, ©_ctor_called TSRMLS_CC); #if MYSQLND_DEBUG_MEMORY - DBG_INF_FMT("Copy_ctor_called=%u", copy_ctor_called); + DBG_INF_FMT("Copy_ctor_called=%u", copy_ctor_called); #endif - MYSQLND_INC_GLOBAL_STATISTIC(copy_ctor_called? STAT_COPY_ON_WRITE_PERFORMED: - STAT_COPY_ON_WRITE_SAVED); + if (copy_ctor_called) { + ++copy_on_write_performed; + } else { + ++copy_on_write_saved; + } + } + } } #if MYSQLND_DEBUG_MEMORY DBG_INF("Freeing current_row & current_buffer"); @@ -218,6 +232,8 @@ MYSQLND_METHOD(mysqlnd_res, free_buffered_data)(MYSQLND_RES * result TSRMLS_DC) current_buffer->free_chunk(current_buffer TSRMLS_CC); } + MYSQLND_INC_GLOBAL_STATISTIC_W_VALUE2(STAT_COPY_ON_WRITE_PERFORMED, copy_on_write_performed, + STAT_COPY_ON_WRITE_SAVED, copy_on_write_saved); mnd_pefree(set->data, set->persistent); set->data = NULL; } @@ -376,7 +392,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) if (!rset_header) { SET_OOM_ERROR(conn->error_info); ret = FAIL; - break; + break; } SET_ERROR_AFF_ROWS(conn); @@ -443,7 +459,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) break; default: do { /* Result set */ MYSQLND_RES * result; - enum_mysqlnd_collected_stats stat = STAT_LAST; + enum_mysqlnd_collected_stats statistic = STAT_LAST; DBG_INF("Result set pending"); SET_EMPTY_MESSAGE(conn->last_message, conn->last_message_len, conn->persistent); @@ -489,7 +505,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) ret = FAIL; break; } - + if (FAIL == (ret = result->m.read_result_metadata(result, conn TSRMLS_CC))) { /* For PS, we leave them in Prepared state */ if (!stmt && conn->current_result) { @@ -505,7 +521,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) if (!fields_eof) { SET_OOM_ERROR(conn->error_info); ret = FAIL; - break; + break; } if (FAIL == (ret = PACKET_READ(fields_eof, conn))) { DBG_ERR("Error ocurred while reading the EOF packet"); @@ -532,11 +548,11 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) */ conn->upsert_status.server_status = fields_eof->server_status; if (fields_eof->server_status & SERVER_QUERY_NO_GOOD_INDEX_USED) { - stat = STAT_BAD_INDEX_USED; + statistic = STAT_BAD_INDEX_USED; } else if (fields_eof->server_status & SERVER_QUERY_NO_INDEX_USED) { - stat = STAT_NO_INDEX_USED; + statistic = STAT_NO_INDEX_USED; } else if (fields_eof->server_status & SERVER_QUERY_WAS_SLOW) { - stat = STAT_QUERY_WAS_SLOW; + statistic = STAT_QUERY_WAS_SLOW; } if (to_log) { #if A0 @@ -545,7 +561,7 @@ mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT * s TSRMLS_DC) efree(backtrace); #endif } - MYSQLND_INC_CONN_STATISTIC(conn->stats, stat); + MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic); } } while (0); PACKET_FREE(fields_eof); @@ -663,7 +679,7 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC) if (!row_packet->skip_extraction) { MYSQLND_FIELD *field = result->meta->fields; - struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys; + struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys; enum_func_status rc = result->m.row_decoder(result->unbuf->last_row_buffer, result->unbuf->last_row_data, @@ -679,7 +695,7 @@ mysqlnd_fetch_row_unbuffered_c(MYSQLND_RES * result TSRMLS_DC) retrow = mnd_malloc(result->field_count * sizeof(char *)); if (retrow) { - for (i = 0; i < field_count; i++, field++, zend_hash_key++) { + for (i = 0; i < field_count; i++, field++, hash_key++) { zval *data = result->unbuf->last_row_data[i]; unsigned int len; @@ -778,7 +794,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla if (!row_packet->skip_extraction) { HashTable *row_ht = Z_ARRVAL_P(row); MYSQLND_FIELD *field = result->meta->fields; - struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys; + struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys; unsigned int i, field_count = result->field_count; unsigned long *lengths = result->lengths; @@ -793,7 +809,7 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla if (PASS != rc) { DBG_RETURN(FAIL); } - for (i = 0; i < field_count; i++, field++, zend_hash_key++) { + for (i = 0; i < field_count; i++, field++, hash_key++) { zval *data = result->unbuf->last_row_data[i]; unsigned int len = (Z_TYPE_P(data) == IS_NULL)? 0:Z_STRLEN_P(data); @@ -814,23 +830,23 @@ mysqlnd_fetch_row_unbuffered(MYSQLND_RES * result, void *param, unsigned int fla hashing of the column name, which is not needed as it can be precomputed. */ Z_ADDREF_P(data); - if (zend_hash_key->is_numeric == FALSE) { -#if PHP_MAJOR_VERSION >= 6 + if (hash_key->is_numeric == FALSE) { +#if MYSQLND_UNICODE zend_u_hash_quick_update(Z_ARRVAL_P(row), IS_UNICODE, - zend_hash_key->ustr, - zend_hash_key->ulen + 1, - zend_hash_key->key, + hash_key->ustr, + hash_key->ulen + 1, + hash_key->key, (void *) &data, sizeof(zval *), NULL); #else zend_hash_quick_update(Z_ARRVAL_P(row), field->name, field->name_length + 1, - zend_hash_key->key, + hash_key->key, (void *) &data, sizeof(zval *), NULL); #endif } else { zend_hash_index_update(Z_ARRVAL_P(row), - zend_hash_key->key, + hash_key->key, (void *) &data, sizeof(zval *), NULL); } } @@ -946,7 +962,7 @@ mysqlnd_fetch_row_buffered_c(MYSQLND_RES * result TSRMLS_DC) { zval **current_row = set->data_cursor; MYSQLND_FIELD *field = result->meta->fields; - struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys; + struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys; unsigned int i; if (NULL == current_row[0]) { @@ -983,7 +999,7 @@ mysqlnd_fetch_row_buffered_c(MYSQLND_RES * result TSRMLS_DC) ret = mnd_malloc(result->field_count * sizeof(char *)); if (ret) { - for (i = 0; i < result->field_count; i++, field++, zend_hash_key++) { + for (i = 0; i < result->field_count; i++, field++, hash_key++) { zval *data = current_row[i]; if (Z_TYPE_P(data) != IS_NULL) { @@ -1022,7 +1038,7 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags { zval **current_row = set->data_cursor; MYSQLND_FIELD *field = result->meta->fields; - struct mysqlnd_field_hash_key *zend_hash_key = result->meta->zend_hash_keys; + struct mysqlnd_field_hash_key * hash_key = result->meta->zend_hash_keys; if (NULL == current_row[0]) { uint64_t row_num = (set->data_cursor - set->data) / result->meta->field_count; @@ -1053,7 +1069,7 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags } } - for (i = 0; i < result->field_count; i++, field++, zend_hash_key++) { + for (i = 0; i < result->field_count; i++, field++, hash_key++) { zval *data = current_row[i]; if (flags & MYSQLND_FETCH_NUM) { @@ -1069,23 +1085,23 @@ mysqlnd_fetch_row_buffered(MYSQLND_RES * result, void *param, unsigned int flags hashing of the column name, which is not needed as it can be precomputed. */ Z_ADDREF_P(data); - if (zend_hash_key->is_numeric == FALSE) { -#if PHP_MAJOR_VERSION >= 6 + if (hash_key->is_numeric == FALSE) { +#if MYSQLND_UNICODE zend_u_hash_quick_update(Z_ARRVAL_P(row), IS_UNICODE, - zend_hash_key->ustr, - zend_hash_key->ulen + 1, - zend_hash_key->key, + hash_key->ustr, + hash_key->ulen + 1, + hash_key->key, (void *) &data, sizeof(zval *), NULL); #else zend_hash_quick_update(Z_ARRVAL_P(row), field->name, field->name_length + 1, - zend_hash_key->key, + hash_key->key, (void *) &data, sizeof(zval *), NULL); #endif } else { zend_hash_index_update(Z_ARRVAL_P(row), - zend_hash_key->key, + hash_key->key, (void *) &data, sizeof(zval *), NULL); } } @@ -1128,14 +1144,14 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL if (!set) { SET_OOM_ERROR(conn->error_info); ret = FAIL; - goto end; + goto end; } if (free_rows) { - set->row_buffers = mnd_pemalloc(free_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *), to_cache); + set->row_buffers = mnd_pemalloc((size_t)(free_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)), to_cache); if (!set->row_buffers) { SET_OOM_ERROR(conn->error_info); ret = FAIL; - goto end; + goto end; } } set->persistent = to_cache; @@ -1149,7 +1165,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL if (!row_packet) { SET_OOM_ERROR(conn->error_info); ret = FAIL; - goto end; + goto end; } row_packet->result_set_memory_pool = result->result_set_memory_pool; row_packet->field_count = meta->field_count; @@ -1165,8 +1181,15 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL uint64_t total_allocated_rows = free_rows = next_extend = next_extend * 11 / 10; /* extend with 10% */ MYSQLND_MEMORY_POOL_CHUNK ** new_row_buffers; total_allocated_rows += set->row_count; + + /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ + if (total_allocated_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *) > SIZE_MAX) { + SET_OOM_ERROR(conn->error_info); + ret = FAIL; + goto end; + } new_row_buffers = mnd_perealloc(set->row_buffers, - total_allocated_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *), + (size_t)(total_allocated_rows * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)), set->persistent); if (!new_row_buffers) { SET_OOM_ERROR(conn->error_info); @@ -1193,14 +1216,20 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL } /* Overflow ? */ if (set->row_count) { + /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ + if (set->row_count * meta->field_count * sizeof(zval *) > SIZE_MAX) { + SET_OOM_ERROR(conn->error_info); + ret = FAIL; + goto end; + } /* if pecalloc is used valgrind barks gcc version 4.3.1 20080507 (prerelease) [gcc-4_3-branch revision 135036] (SUSE Linux) */ - set->data = mnd_pemalloc(set->row_count * meta->field_count * sizeof(zval *), to_cache); + set->data = mnd_pemalloc((size_t)(set->row_count * meta->field_count * sizeof(zval *)), to_cache); if (!set->data) { SET_OOM_ERROR(conn->error_info); ret = FAIL; goto end; } - memset(set->data, 0, set->row_count * meta->field_count * sizeof(zval *)); + memset(set->data, 0, (size_t)(set->row_count * meta->field_count * sizeof(zval *))); } MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, @@ -1215,8 +1244,14 @@ MYSQLND_METHOD(mysqlnd_res, store_result_fetch_data)(MYSQLND * const conn, MYSQL } /* save some memory */ if (free_rows) { + /* don't try to allocate more than possible - mnd_XXalloc expects size_t, and it can have narrower range than uint64_t */ + if (set->row_count * sizeof(MYSQLND_MEMORY_POOL_CHUNK *) > SIZE_MAX) { + SET_OOM_ERROR(conn->error_info); + ret = FAIL; + goto end; + } set->row_buffers = mnd_perealloc(set->row_buffers, - set->row_count * sizeof(MYSQLND_MEMORY_POOL_CHUNK *), + (size_t) (set->row_count * sizeof(MYSQLND_MEMORY_POOL_CHUNK *)), set->persistent); } @@ -1277,7 +1312,7 @@ MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result, if (result->stored_data) { conn->error_info = result->stored_data->error_info; } else { - SET_OOM_ERROR(conn->error_info); + SET_OOM_ERROR(conn->error_info); } DBG_RETURN(NULL); } @@ -1310,9 +1345,7 @@ MYSQLND_METHOD(mysqlnd_res, skip_result)(MYSQLND_RES * const result TSRMLS_DC) result->type == MYSQLND_RES_NORMAL? STAT_FLUSHED_NORMAL_SETS: STAT_FLUSHED_PS_SETS); - while ((PASS == result->m.fetch_row(result, NULL, 0, &fetched_anything TSRMLS_CC)) && - fetched_anything == TRUE) - { + while ((PASS == result->m.fetch_row(result, NULL, 0, &fetched_anything TSRMLS_CC)) && fetched_anything == TRUE) { /* do nothing */; } } @@ -1491,6 +1524,9 @@ MYSQLND_METHOD(mysqlnd_res, field_tell)(const MYSQLND_RES * const result TSRMLS_ /* }}} */ +/* for php_addslashes */ +#include "ext/standard/php_string.h" + /* {{{ mysqlnd_res::fetch_into */ static void MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, unsigned int flags, @@ -1525,7 +1561,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_into)(MYSQLND_RES * result, unsigned int flags break; default:exit(0); } - } + } /* return_value is IS_NULL for no more data and an array for data. Thus it's ok to return here. @@ -1567,8 +1603,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_all)(MYSQLND_RES * result, unsigned int flags, DBG_ENTER("mysqlnd_res::fetch_all"); DBG_INF_FMT("flags=%u", flags); - /* mysqlnd_res::fetch_all works with buffered resultsets only */ - if (result->unbuf || (!result->unbuf && !set)) { + if ((!result->unbuf && !set)) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "fetch_all can be used only with buffered sets"); if (result->conn) { SET_CLIENT_ERROR(result->conn->error_info, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "fetch_all can be used only with buffered sets"); @@ -1577,19 +1612,18 @@ MYSQLND_METHOD(mysqlnd_res, fetch_all)(MYSQLND_RES * result, unsigned int flags, DBG_VOID_RETURN; } - mysqlnd_array_init(return_value, (unsigned int) set->row_count); + /* 4 is a magic value. The cast is safe, if larger then the array will be later extended - no big deal :) */ + mysqlnd_array_init(return_value, set? (unsigned int) set->row_count : 4); - if (!set->row_count || !set->data_cursor || set->data_cursor >= set->data + set->row_count) { - DBG_VOID_RETURN; - } - - while (set->data_cursor && - (set->data_cursor - set->data) < (set->row_count * result->meta->field_count)) - { + do { MAKE_STD_ZVAL(row); mysqlnd_fetch_into(result, flags, row, MYSQLND_MYSQLI); + if (Z_TYPE_P(row) != IS_ARRAY) { + zval_ptr_dtor(&row); + break; + } add_index_zval(return_value, i++, row); - } + } while (1); DBG_VOID_RETURN; } @@ -1627,7 +1661,7 @@ MYSQLND_METHOD(mysqlnd_res, fetch_field_data)(MYSQLND_RES * result, unsigned int zend_hash_move_forward(Z_ARRVAL(row)); zend_hash_get_current_data(Z_ARRVAL(row), (void **)&entry); } - + zend_hash_get_current_data(Z_ARRVAL(row), (void **)&entry); *return_value = **entry; @@ -1686,7 +1720,7 @@ mysqlnd_result_init(unsigned int field_count, zend_bool persistent TSRMLS_DC) DBG_ENTER("mysqlnd_result_init"); DBG_INF_FMT("field_count=%u", field_count); - + if (!ret) { DBG_RETURN(NULL); } diff --git a/ext/mysqlnd/mysqlnd_result_meta.c b/ext/mysqlnd/mysqlnd_result_meta.c index a3897bcbb..b15fb10fd 100644 --- a/ext/mysqlnd/mysqlnd_result_meta.c +++ b/ext/mysqlnd/mysqlnd_result_meta.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_result_meta.c 300635 2010-06-21 15:32:26Z andrey $ */ +/* $Id: mysqlnd_result_meta.c 304066 2010-10-05 08:29:54Z uw $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_priv.h" @@ -52,16 +52,16 @@ php_mysqlnd_free_field_metadata(MYSQLND_FIELD *meta, zend_bool persistent TSRMLS and modified for the needs of mysqlnd. */ static zend_bool -mysqlnd_is_key_numeric(char *key, size_t length, long *idx) +mysqlnd_is_key_numeric(const char * key, size_t length, long *idx) { - register char * tmp = key; + register const char * tmp = key; if (*tmp=='-') { tmp++; } if ((*tmp>='0' && *tmp<='9')) { do { /* possibly a numeric index */ - char *end=key+length-1; + const char *end=key+length-1; if (*tmp++=='0' && length>2) { /* don't accept numbers with leading zeros */ break; @@ -92,7 +92,7 @@ mysqlnd_is_key_numeric(char *key, size_t length, long *idx) /* }}} */ -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE /* {{{ mysqlnd_unicode_is_key_numeric */ static zend_bool mysqlnd_unicode_is_key_numeric(UChar *key, size_t length, long *idx) @@ -142,7 +142,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met { unsigned int i = 0; MYSQLND_PACKET_RES_FIELD * field_packet; -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE UChar *ustr; int ulen; #endif @@ -175,7 +175,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met PACKET_FREE(field_packet); DBG_RETURN(FAIL); } - + if (field_packet->stupid_list_fields_eof == TRUE) { meta->field_count = i; break; @@ -224,10 +224,9 @@ MYSQLND_METHOD(mysqlnd_res_meta, read_metadata)(MYSQLND_RES_METADATA * const met meta->bit_fields_total_len += 3;/* 120 */ break; } - } -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, meta->fields[i].name, meta->fields[i].name_length TSRMLS_CC); @@ -284,7 +283,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, free)(MYSQLND_RES_METADATA * meta TSRMLS_DC) if (meta->zend_hash_keys) { DBG_INF("Freeing zend_hash_keys"); -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE if (UG(unicode)) { for (i = 0; i < meta->field_count; i++) { if (meta->zend_hash_keys[i].ustr.v) { @@ -380,7 +379,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, clone_metadata)(const MYSQLND_RES_METADATA * co /* 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 MYSQLND_UNICODE 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); @@ -455,7 +454,7 @@ MYSQLND_METHOD(mysqlnd_res_meta, field_tell)(const MYSQLND_RES_METADATA * const /* }}} */ -static +static MYSQLND_CLASS_METHODS_START(mysqlnd_res_meta) MYSQLND_METHOD(mysqlnd_res_meta, fetch_field), MYSQLND_METHOD(mysqlnd_res_meta, fetch_field_direct), @@ -475,7 +474,7 @@ mysqlnd_result_meta_init(unsigned int field_count, zend_bool persistent TSRMLS_D MYSQLND_RES_METADATA *ret = mnd_pecalloc(1, alloc_size, persistent); DBG_ENTER("mysqlnd_result_meta_init"); DBG_INF_FMT("persistent=%u", persistent); - + do { if (!ret) { break; diff --git a/ext/mysqlnd/mysqlnd_statistics.c b/ext/mysqlnd/mysqlnd_statistics.c index 6557e234c..d918132b0 100644 --- a/ext/mysqlnd/mysqlnd_statistics.c +++ b/ext/mysqlnd/mysqlnd_statistics.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_statistics.c 298217 2010-04-20 13:50:34Z felipe $ */ +/* $Id: mysqlnd_statistics.c 305109 2010-11-05 20:07:34Z andrey $ */ #include "php.h" #include "mysqlnd.h" #include "mysqlnd_priv.h" @@ -190,7 +190,9 @@ const MYSQLND_STRING mysqlnd_stats_values_names[STAT_LAST] = { STR_W_LEN("com_stmt_reset") }, { STR_W_LEN("com_stmt_set_option") }, { STR_W_LEN("com_stmt_fetch") }, - { STR_W_LEN("com_deamon") } + { STR_W_LEN("com_deamon") }, + { STR_W_LEN("bytes_received_real_data_normal") }, + { STR_W_LEN("bytes_received_real_data_ps") } }; /* }}} */ @@ -203,14 +205,14 @@ mysqlnd_fill_stats_hash(const MYSQLND_STATS * const stats, const MYSQLND_STRING mysqlnd_array_init(return_value, stats->count); for (i = 0; i < stats->count; i++) { -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE UChar *ustr, *tstr; int ulen, tlen; #endif char tmp[25]; - + sprintf((char *)&tmp, MYSQLND_LLU_SPEC, stats->values[i]); -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE zend_string_to_unicode(UG(utf8_conv), &ustr, &ulen, names[i].s, 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); @@ -274,14 +276,14 @@ mysqlnd_stats_end(MYSQLND_STATS * stats) /* {{{ mysqlnd_stats_set_trigger */ PHPAPI mysqlnd_stat_trigger -mysqlnd_stats_set_trigger(MYSQLND_STATS * const stats, enum_mysqlnd_collected_stats stat, mysqlnd_stat_trigger trigger TSRMLS_DC) +mysqlnd_stats_set_trigger(MYSQLND_STATS * const stats, enum_mysqlnd_collected_stats statistic, mysqlnd_stat_trigger trigger TSRMLS_DC) { mysqlnd_stat_trigger ret = NULL; DBG_ENTER("mysqlnd_stats_set_trigger"); if (stats) { MYSQLND_STATS_LOCK(stats); - ret = stats->triggers[stat]; - stats->triggers[stat] = trigger; + ret = stats->triggers[statistic]; + stats->triggers[statistic] = trigger; MYSQLND_STATS_UNLOCK(stats); } DBG_RETURN(ret); diff --git a/ext/mysqlnd/mysqlnd_statistics.h b/ext/mysqlnd/mysqlnd_statistics.h index 3fffe5fb1..b54db3584 100644 --- a/ext/mysqlnd/mysqlnd_statistics.h +++ b/ext/mysqlnd/mysqlnd_statistics.h @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_statistics.h 298318 2010-04-22 13:03:44Z andrey $ */ +/* $Id: mysqlnd_statistics.h 303734 2010-09-23 16:03:22Z andrey $ */ #ifndef MYSQLND_STATISTICS_H #define MYSQLND_STATISTICS_H @@ -64,7 +64,7 @@ extern const MYSQLND_STRING mysqlnd_stats_values_names[]; MYSQLND_STAT_CALL_TRIGGER((stats), (statistic), (value)); \ MYSQLND_STATS_UNLOCK(_p_s); \ } - + #define MYSQLND_DEC_STATISTIC(enabler, stats, statistic) \ { \ enum_mysqlnd_collected_stats _s = (statistic);\ diff --git a/ext/mysqlnd/mysqlnd_structs.h b/ext/mysqlnd/mysqlnd_structs.h index f229d9509..5aa486fbd 100644 --- a/ext/mysqlnd/mysqlnd_structs.h +++ b/ext/mysqlnd/mysqlnd_structs.h @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_structs.h 300735 2010-06-24 19:52:13Z andrey $ */ +/* $Id: mysqlnd_structs.h 304112 2010-10-05 16:27:49Z andrey $ */ #ifndef MYSQLND_STRUCTS_H #define MYSQLND_STRUCTS_H @@ -44,7 +44,7 @@ struct st_mysqlnd_memory_pool struct st_mysqlnd_memory_pool_chunk { - uint64_t app; + size_t app; MYSQLND_MEMORY_POOL *pool; zend_uchar *ptr; unsigned int size; @@ -161,7 +161,8 @@ typedef struct st_mysqlnd_options char * unused3; char * unused4; char * unused5; - zend_bool unused6; + + enum_mysqlnd_protocol_type protocol; char *charset_name; /* maximum allowed packet size for communication */ @@ -190,6 +191,7 @@ typedef struct st_mysqlnd_net_options char *ssl_cipher; char *ssl_passphrase; zend_bool ssl_verify_peer; + uint64_t flags; } MYSQLND_NET_OPTIONS; @@ -335,7 +337,7 @@ struct st_mysqlnd_protocol_methods typedef enum_func_status (*func_mysqlnd_conn__init)(MYSQLND * conn TSRMLS_DC); -typedef enum_func_status (*func_mysqlnd_conn__connect)(MYSQLND *conn, const char *host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket, unsigned int mysql_flags TSRMLS_DC); +typedef enum_func_status (*func_mysqlnd_conn__connect)(MYSQLND *conn, const char *host, const char * user, const char * passwd, unsigned int passwd_len, const char * db, unsigned int db_len, unsigned int port, const char * socket_or_pipe, unsigned int mysql_flags TSRMLS_DC); typedef ulong (*func_mysqlnd_conn__escape_string)(const MYSQLND * const conn, char *newstr, const char *escapestr, size_t escapestr_len TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn__set_charset)(MYSQLND * const conn, const char * const charset TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn__query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC); @@ -400,7 +402,7 @@ typedef enum_func_status (*func_mysqlnd_conn__restart_psession)(MYSQLND *conn TS typedef enum_func_status (*func_mysqlnd_conn__end_psession)(MYSQLND *conn TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_conn__send_close)(MYSQLND * conn TSRMLS_DC); -typedef void (*func_mysqlnd_conn__ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC); +typedef enum_func_status (*func_mysqlnd_conn__ssl_set)(MYSQLND * const conn, const char * key, const char * const cert, const char * const ca, const char * const capath, const char * const cipher TSRMLS_DC); typedef MYSQLND_RES * (*func_mysqlnd_conn__result_init)(unsigned int field_count, zend_bool persistent TSRMLS_DC); @@ -625,6 +627,7 @@ typedef void (*func_mysqlnd_stmt__free_result_bind)(MYSQLND_STMT * const stm typedef unsigned int (*func_mysqlnd_stmt__server_status)(const MYSQLND_STMT * const stmt TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_stmt__generate_execute_request)(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC); typedef enum_func_status (*func_mysqlnd_stmt__parse_execute_response)(MYSQLND_STMT * const s TSRMLS_DC); +typedef void (*func_mysqlnd_stmt__free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC); struct st_mysqlnd_stmt_methods { @@ -676,6 +679,8 @@ struct st_mysqlnd_stmt_methods func_mysqlnd_stmt__generate_execute_request generate_execute_request; func_mysqlnd_stmt__parse_execute_response parse_execute_response; + + func_mysqlnd_stmt__free_stmt_content free_stmt_content; }; @@ -788,7 +793,7 @@ struct mysqlnd_field_hash_key { zend_bool is_numeric; unsigned long key; -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE zstr ustr; unsigned int ulen; #endif diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.c b/ext/mysqlnd/mysqlnd_wireprotocol.c index ba31984d8..810a79399 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.c +++ b/ext/mysqlnd/mysqlnd_wireprotocol.c @@ -243,7 +243,7 @@ php_mysqlnd_read_error_from_line(zend_uchar *buf, size_t buf_len, } } if ((buf_len - (p - buf)) > 0) { - error_msg_len = MIN((buf_len - (p - buf)), error_buf_len - 1); + error_msg_len = MIN((int)((buf_len - (p - buf))), (int) (error_buf_len - 1)); memcpy(error, p, error_msg_len); } } @@ -391,14 +391,14 @@ premature_end: /* {{{ php_mysqlnd_greet_free_mem */ static -void php_mysqlnd_greet_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_greet_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_GREET *p= (MYSQLND_PACKET_GREET *) _packet; if (p->server_version) { efree(p->server_version); p->server_version = NULL; } - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } } @@ -508,9 +508,9 @@ size_t php_mysqlnd_auth_write(void *_packet, MYSQLND * conn TSRMLS_DC) /* {{{ php_mysqlnd_auth_free_mem */ static -void php_mysqlnd_auth_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_auth_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { - if (!alloca) { + if (!stack_allocation) { MYSQLND_PACKET_AUTH * p = (MYSQLND_PACKET_AUTH *) _packet; mnd_pefree(p, p->header.persistent); } @@ -591,14 +591,14 @@ premature_end: /* {{{ php_mysqlnd_ok_free_mem */ static void -php_mysqlnd_ok_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +php_mysqlnd_ok_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_OK *p= (MYSQLND_PACKET_OK *) _packet; if (p->message) { mnd_efree(p->message); p->message = NULL; } - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } } @@ -674,9 +674,9 @@ premature_end: /* {{{ php_mysqlnd_eof_free_mem */ static -void php_mysqlnd_eof_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_eof_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { - if (!alloca) { + if (!stack_allocation) { mnd_pefree(_packet, ((MYSQLND_PACKET_EOF *)_packet)->header.persistent); } } @@ -748,9 +748,9 @@ end: /* {{{ php_mysqlnd_cmd_free_mem */ static -void php_mysqlnd_cmd_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_cmd_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { - if (!alloca) { + if (!stack_allocation) { MYSQLND_PACKET_COMMAND * p = (MYSQLND_PACKET_COMMAND *) _packet; mnd_pefree(p, p->header.persistent); } @@ -864,7 +864,7 @@ premature_end: /* {{{ php_mysqlnd_rset_header_free_mem */ static -void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_RSET_HEADER *p= (MYSQLND_PACKET_RSET_HEADER *) _packet; DBG_ENTER("php_mysqlnd_rset_header_free_mem"); @@ -872,7 +872,7 @@ void php_mysqlnd_rset_header_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) mnd_efree(p->info_or_local_file); p->info_or_local_file = NULL; } - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } DBG_VOID_RETURN; @@ -1091,11 +1091,11 @@ premature_end: /* {{{ php_mysqlnd_rset_field_free_mem */ static -void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_RES_FIELD *p= (MYSQLND_PACKET_RES_FIELD *) _packet; /* p->metadata was passed to us as temporal buffer */ - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } } @@ -1106,7 +1106,7 @@ void php_mysqlnd_rset_field_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) static enum_func_status php_mysqlnd_read_row_ex(MYSQLND * conn, MYSQLND_MEMORY_POOL * result_set_memory_pool, MYSQLND_MEMORY_POOL_CHUNK **buffer, - uint64_t *data_size, zend_bool persistent_alloc, + size_t *data_size, zend_bool persistent_alloc, unsigned int prealloc_more_bytes TSRMLS_DC) { enum_func_status ret = PASS; @@ -1201,23 +1201,29 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol"); - end_field = (current_field = start_field = fields) + field_count; - if (!current_field) { + if (!fields) { DBG_RETURN(FAIL); } + end_field = (start_field = fields) + field_count; + /* skip the first byte, not EODATA_MARKER -> 0x0, status */ p++; null_ptr= p; p += (field_count + 9)/8; /* skip null bits */ bit = 4; /* first 2 bits are reserved */ - for (i = 0; current_field < end_field; current_field++, i++) { + for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) { DBG_INF("Directly creating zval"); MAKE_STD_ZVAL(*current_field); if (!*current_field) { DBG_RETURN(FAIL); } + } + + for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) { + enum_mysqlnd_collected_stats statistic; + zend_uchar * orig_p = p; DBG_INF_FMT("Into zval=%p decoding column %u [%s.%s.%s] type=%u field->flags&unsigned=%u flags=%u is_bit=%u as_unicode=%u", *current_field, i, @@ -1226,13 +1232,12 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv if (*null_ptr & bit) { DBG_INF("It's null"); ZVAL_NULL(*current_field); - MYSQLND_INC_CONN_STATISTIC(stats, STAT_BINARY_TYPE_FETCHED_NULL); + statistic = STAT_BINARY_TYPE_FETCHED_NULL; } else { enum_mysqlnd_field_types type = fields_metadata[i].type; mysqlnd_ps_fetch_functions[type].func(*current_field, &fields_metadata[i], 0, &p, as_unicode TSRMLS_CC); if (MYSQLND_G(collect_statistics)) { - enum_mysqlnd_collected_stats statistic; switch (fields_metadata[i].type) { case MYSQL_TYPE_DECIMAL: statistic = STAT_BINARY_TYPE_FETCHED_DECIMAL; break; case MYSQL_TYPE_TINY: statistic = STAT_BINARY_TYPE_FETCHED_INT8; break; @@ -1263,9 +1268,13 @@ php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zv case MYSQL_TYPE_GEOMETRY: statistic = STAT_BINARY_TYPE_FETCHED_GEOMETRY; break; default: statistic = STAT_BINARY_TYPE_FETCHED_OTHER; break; } - MYSQLND_INC_CONN_STATISTIC(stats, statistic); } } + MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, + STAT_BYTES_RECEIVED_PURE_DATA_PS, + (Z_TYPE_PP(current_field) == IS_STRING)? + Z_STRLEN_PP(current_field) : (p - orig_p)); + if (!((bit<<=1) & 255)) { bit = 1; /* to the following byte */ null_ptr++; @@ -1294,22 +1303,25 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval DBG_ENTER("php_mysqlnd_rowp_read_text_protocol"); - end_field = (current_field = start_field = fields) + field_count; - if (!current_field) { + if (!fields) { DBG_RETURN(FAIL); } - for (i = 0; current_field < end_field; current_field++, i++) { - /* Don't reverse the order. It is significant!*/ - zend_uchar *this_field_len_pos = p; - /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */ - unsigned long len = php_mysqlnd_net_field_length(&p); + end_field = (start_field = fields) + field_count; + for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) { DBG_INF("Directly creating zval"); MAKE_STD_ZVAL(*current_field); if (!*current_field) { DBG_RETURN(FAIL); } + } + + for (i = 0, current_field = start_field; current_field < end_field; current_field++, i++) { + /* Don't reverse the order. It is significant!*/ + zend_uchar *this_field_len_pos = p; + /* php_mysqlnd_net_field_length() call should be after *this_field_len_pos = p; */ + unsigned long len = php_mysqlnd_net_field_length(&p); if (current_field > start_field && last_field_was_string) { /* @@ -1332,7 +1344,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ZVAL_NULL(*current_field); last_field_was_string = FALSE; } else { -#if PHP_MAJOR_VERSION >= 6 || defined(MYSQLND_STRING_TO_INT_CONVERSION) +#if MYSQLND_UNICODE || defined(MYSQLND_STRING_TO_INT_CONVERSION) struct st_mysqlnd_perm_bind perm_bind = mysqlnd_ps_fetch_functions[fields_metadata[i].type]; #endif @@ -1368,9 +1380,8 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval case MYSQL_TYPE_GEOMETRY: statistic = STAT_TEXT_TYPE_FETCHED_GEOMETRY; break; default: statistic = STAT_TEXT_TYPE_FETCHED_OTHER; break; } - MYSQLND_INC_CONN_STATISTIC(stats, statistic); + MYSQLND_INC_CONN_STATISTIC_W_VALUE2(stats, statistic, 1, STAT_BYTES_RECEIVED_PURE_DATA_TEXT, len); } - #ifdef MYSQLND_STRING_TO_INT_CONVERSION if (as_int_or_float && perm_bind.php_type == IS_LONG) { zend_uchar save = *(p + len); @@ -1384,7 +1395,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval #else _atoi64((char *) p); #endif - ZVAL_LONG(*current_field, v); + ZVAL_LONG(*current_field, (long) v); /* the cast is safe */ } else { uint64_t v = #ifndef PHP_WIN32 @@ -1406,7 +1417,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval { ZVAL_STRINGL(*current_field, (char *)p, len, 0); } else { - ZVAL_LONG(*current_field, (int64_t)v); + ZVAL_LONG(*current_field, (long) v); /* the cast is safe */ } } *(p + len) = save; @@ -1437,7 +1448,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval p -= len; if (Z_TYPE_PP(current_field) == IS_LONG) { bit_area += 1 + sprintf((char *)start, "%ld", Z_LVAL_PP(current_field)); -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE if (as_unicode) { ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0); } else @@ -1450,7 +1461,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval bit_area += Z_STRLEN_PP(current_field); *bit_area++ = '\0'; zval_dtor(*current_field); -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE if (as_unicode) { ZVAL_UTF8_STRINGL(*current_field, start, bit_area - start - 1, 0); } else @@ -1464,7 +1475,7 @@ php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval the buffers are not referenced - everything is copied. */ } else -#if PHP_MAJOR_VERSION < 6 +#if MYSQLND_UNICODE == 0 { ZVAL_STRINGL(*current_field, (char *)p, len, 0); } @@ -1519,7 +1530,7 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC) size_t old_chunk_size = net->stream->chunk_size; MYSQLND_PACKET_ROW *packet= (MYSQLND_PACKET_ROW *) _packet; size_t post_alloc_for_bit_fields = 0; - uint64_t data_size = 0; + size_t data_size = 0; DBG_ENTER("php_mysqlnd_rowp_read"); @@ -1606,7 +1617,7 @@ end: /* {{{ php_mysqlnd_rowp_free_mem */ static void -php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +php_mysqlnd_rowp_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_ROW *p; @@ -1616,7 +1627,7 @@ php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) p->row_buffer->free_chunk(p->row_buffer TSRMLS_CC); p->row_buffer = NULL; } - DBG_INF_FMT("alloca=%u persistent=%u", (int)alloca, (int)p->header.persistent); + DBG_INF_FMT("stack_allocation=%u persistent=%u", (int)stack_allocation, (int)p->header.persistent); /* Don't free packet->fields : - normal queries -> store_result() | fetch_row_unbuffered() will transfer @@ -1624,7 +1635,7 @@ php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) - PS will pass in it the bound variables, we have to use them! and of course not free the array. As it is passed to us, we should not clean it ourselves. */ - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } DBG_VOID_RETURN; @@ -1656,14 +1667,14 @@ php_mysqlnd_stats_read(void *_packet, MYSQLND *conn TSRMLS_DC) /* {{{ php_mysqlnd_stats_free_mem */ static -void php_mysqlnd_stats_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +void php_mysqlnd_stats_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_STATS *p= (MYSQLND_PACKET_STATS *) _packet; if (p->message) { mnd_efree(p->message); p->message = NULL; } - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } } @@ -1752,10 +1763,10 @@ premature_end: /* {{{ php_mysqlnd_prepare_free_mem */ static void -php_mysqlnd_prepare_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +php_mysqlnd_prepare_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { MYSQLND_PACKET_PREPARE_RESPONSE *p= (MYSQLND_PACKET_PREPARE_RESPONSE *) _packet; - if (!alloca) { + if (!stack_allocation) { mnd_pefree(p, p->header.persistent); } } @@ -1815,9 +1826,9 @@ premature_end: /* {{{ php_mysqlnd_chg_user_free_mem */ static void -php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool alloca TSRMLS_DC) +php_mysqlnd_chg_user_free_mem(void *_packet, zend_bool stack_allocation TSRMLS_DC) { - if (!alloca) { + if (!stack_allocation) { mnd_pefree(_packet, ((MYSQLND_PACKET_CHG_USER_RESPONSE *)_packet)->header.persistent); } } diff --git a/ext/mysqlnd/mysqlnd_wireprotocol.h b/ext/mysqlnd/mysqlnd_wireprotocol.h index 8d862fc8e..7fee8502e 100644 --- a/ext/mysqlnd/mysqlnd_wireprotocol.h +++ b/ext/mysqlnd/mysqlnd_wireprotocol.h @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: mysqlnd_wireprotocol.h 299998 2010-05-31 17:57:03Z andrey $ */ +/* $Id: mysqlnd_wireprotocol.h 304116 2010-10-05 17:20:00Z andrey $ */ #ifndef MYSQLND_WIREPROTOCOL_H #define MYSQLND_WIREPROTOCOL_H @@ -53,7 +53,7 @@ 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); + void (*free_mem)(void *packet, zend_bool stack_allocation TSRMLS_DC); } mysqlnd_packet_methods; diff --git a/ext/mysqlnd/php_mysqlnd.c b/ext/mysqlnd/php_mysqlnd.c index 6bfbe2e4f..e1ddcba70 100644 --- a/ext/mysqlnd/php_mysqlnd.c +++ b/ext/mysqlnd/php_mysqlnd.c @@ -18,7 +18,7 @@ +----------------------------------------------------------------------+ */ -/* $Id: php_mysqlnd.c 300352 2010-06-10 12:24:03Z andrey $ */ +/* $Id: php_mysqlnd.c 304974 2010-10-28 14:07:36Z andrey $ */ #include "php.h" #include "php_ini.h" #include "mysqlnd.h" @@ -37,7 +37,7 @@ static zend_function_entry mysqlnd_functions[] = { /* {{{ mysqlnd_minfo_print_hash */ -#if PHP_MAJOR_VERSION >= 6 +#if MYSQLND_UNICODE PHPAPI void mysqlnd_minfo_print_hash(zval *values) { zval **values_entry; @@ -122,6 +122,8 @@ PHP_MINFO_FUNCTION(mysqlnd) php_info_print_table_row(2, "Read timeout", buf); php_info_print_table_row(2, "Collecting statistics", MYSQLND_G(collect_statistics)? "Yes":"No"); php_info_print_table_row(2, "Collecting memory statistics", MYSQLND_G(collect_memory_statistics)? "Yes":"No"); + + php_info_print_table_row(2, "Tracing", MYSQLND_G(debug)? MYSQLND_G(debug):"n/a"); php_info_print_table_end(); /* Print client stats */ @@ -136,7 +138,7 @@ PHP_MINFO_FUNCTION(mysqlnd) /* }}} */ -PHPAPI ZEND_DECLARE_MODULE_GLOBALS(mysqlnd); +PHPAPI ZEND_DECLARE_MODULE_GLOBALS(mysqlnd) /* {{{ PHP_GINIT_FUNCTION |
