mirror of
https://github.com/php/php-src.git
synced 2024-09-21 18:07:23 +00:00
MFB: More optimizations - less MM calls
Clearly separated fetching (physical reading) from decoding phases (data interpretation). Threaded fetching added but disabled as needs more work for Windows. For Linux needs some touches to add pthreads if this is enabled, probably with a compile-time switch. The code reorganisation makes it easy to add also async API, similar to cURL's one.
This commit is contained in:
parent
618a29411d
commit
18c8e6501b
@ -33,9 +33,6 @@
|
||||
#include "php_mysqli_structs.h"
|
||||
#include "zend_exceptions.h"
|
||||
|
||||
#define MYSQLI_STORE_RESULT 0
|
||||
#define MYSQLI_USE_RESULT 1
|
||||
|
||||
ZEND_DECLARE_MODULE_GLOBALS(mysqli)
|
||||
static PHP_GINIT_FUNCTION(mysqli);
|
||||
|
||||
@ -685,8 +682,11 @@ PHP_MINIT_FUNCTION(mysqli)
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_CLIENT_FOUND_ROWS", CLIENT_FOUND_ROWS, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
/* for mysqli_query */
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_STORE_RESULT", 0, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_USE_RESULT", 1, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_STORE_RESULT", MYSQLI_STORE_RESULT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_USE_RESULT", MYSQLI_USE_RESULT, CONST_CS | CONST_PERSISTENT);
|
||||
#if defined(HAVE_MYSQLND) && defined(MYSQLND_THREADING)
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_BG_STORE_RESULT", MYSQLI_BG_STORE_RESULT, CONST_CS | CONST_PERSISTENT);
|
||||
#endif
|
||||
|
||||
/* for mysqli_fetch_assoc */
|
||||
REGISTER_LONG_CONSTANT("MYSQLI_ASSOC", MYSQLI_ASSOC, CONST_CS | CONST_PERSISTENT);
|
||||
@ -952,7 +952,7 @@ Parameters:
|
||||
ZEND_FUNCTION(mysqli_result_construct)
|
||||
{
|
||||
MY_MYSQL *mysql;
|
||||
MYSQL_RES *result;
|
||||
MYSQL_RES *result = NULL;
|
||||
zval *mysql_link;
|
||||
MYSQLI_RESOURCE *mysqli_resource;
|
||||
long resmode = MYSQLI_STORE_RESULT;
|
||||
@ -967,10 +967,6 @@ ZEND_FUNCTION(mysqli_result_construct)
|
||||
if (zend_parse_parameters(2 TSRMLS_CC, "Ol", &mysql_link, mysqli_link_class_entry, &resmode)==FAILURE) {
|
||||
return;
|
||||
}
|
||||
if (resmode != MYSQLI_USE_RESULT && resmode != MYSQLI_STORE_RESULT) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for resultmode");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
break;
|
||||
default:
|
||||
WRONG_PARAM_COUNT;
|
||||
@ -978,8 +974,21 @@ ZEND_FUNCTION(mysqli_result_construct)
|
||||
|
||||
MYSQLI_FETCH_RESOURCE(mysql, MY_MYSQL *, &mysql_link, "mysqli_link", MYSQLI_STATUS_VALID);
|
||||
|
||||
result = (resmode == MYSQLI_STORE_RESULT) ? mysql_store_result(mysql->mysql) :
|
||||
mysql_use_result(mysql->mysql);
|
||||
switch (resmode) {
|
||||
case MYSQLI_STORE_RESULT:
|
||||
result = mysql_store_result(mysql->mysql);
|
||||
break;
|
||||
case MYSQLI_USE_RESULT:
|
||||
result = mysql_use_result(mysql->mysql);
|
||||
break;
|
||||
#if defined(HAVE_MYSQLND) && defined(MYSQLND_THREADING)
|
||||
case MYSQLI_BG_STORE_RESULT:
|
||||
result = mysqli_bg_store_result(mysql->mysql);
|
||||
break;
|
||||
#endif
|
||||
default:
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for resultmode");
|
||||
}
|
||||
|
||||
if (!result) {
|
||||
RETURN_FALSE;
|
||||
|
@ -37,5 +37,6 @@
|
||||
#define mysqli_close(c, how) mysqlnd_close((c), (how))
|
||||
#define mysqli_stmt_close(c, implicit) mysqlnd_stmt_close((c), (implicit))
|
||||
#define mysqli_free_result(r, implicit) mysqlnd_free_result((r), (implicit))
|
||||
#define mysqli_bg_store_result(r) mysqlnd_bg_store_result((r))
|
||||
|
||||
#endif
|
||||
|
@ -473,7 +473,11 @@ PHP_FUNCTION(mysqli_query)
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Empty query");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
if (resultmode != MYSQLI_USE_RESULT && resultmode != MYSQLI_STORE_RESULT) {
|
||||
if (resultmode != MYSQLI_USE_RESULT && resultmode != MYSQLI_STORE_RESULT
|
||||
#if defined(HAVE_MYSQLND) && defined(MYSQLND_THREADING)
|
||||
&& resultmode != MYSQLI_BG_STORE_RESULT
|
||||
#endif
|
||||
) {
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid value for resultmode");
|
||||
RETURN_FALSE;
|
||||
}
|
||||
@ -495,8 +499,19 @@ PHP_FUNCTION(mysqli_query)
|
||||
RETURN_TRUE;
|
||||
}
|
||||
|
||||
result = (resultmode == MYSQLI_USE_RESULT) ? mysql_use_result(mysql->mysql) : mysql_store_result(mysql->mysql);
|
||||
|
||||
switch (resultmode) {
|
||||
case MYSQLI_STORE_RESULT:
|
||||
result = mysql_store_result(mysql->mysql);
|
||||
break;
|
||||
case MYSQLI_USE_RESULT:
|
||||
result = mysql_use_result(mysql->mysql);
|
||||
break;
|
||||
#if defined(HAVE_MYSQLND) && defined(MYSQLND_THREADING)
|
||||
case MYSQLI_BG_STORE_RESULT:
|
||||
result = mysqli_bg_store_result(mysql->mysql);
|
||||
break;
|
||||
#endif
|
||||
}
|
||||
if (!result) {
|
||||
php_mysqli_throw_sql_exception((char *)mysql_sqlstate(mysql->mysql), mysql_errno(mysql->mysql) TSRMLS_CC,
|
||||
"%s", mysql_error(mysql->mysql));
|
||||
|
@ -213,7 +213,7 @@ static int result_type_read(mysqli_object *obj, zval **retval TSRMLS_DC)
|
||||
if (!p) {
|
||||
ZVAL_NULL(*retval);
|
||||
} else {
|
||||
ZVAL_LONG(*retval, (p->data) ? MYSQLI_STORE_RESULT : MYSQLI_USE_RESULT);
|
||||
ZVAL_LONG(*retval, mysqli_result_is_unbuffered(p) ? MYSQLI_USE_RESULT:MYSQLI_STORE_RESULT);
|
||||
}
|
||||
return SUCCESS;
|
||||
}
|
||||
|
@ -311,6 +311,9 @@ PHP_MYSQLI_EXPORT(zend_object_value) mysqli_objects_new(zend_class_entry * TSRML
|
||||
|
||||
#define MYSQLI_STORE_RESULT 0
|
||||
#define MYSQLI_USE_RESULT 1
|
||||
#ifdef HAVE_MYSQLND
|
||||
#define MYSQLI_BG_STORE_RESULT 101
|
||||
#endif
|
||||
|
||||
/* for mysqli_fetch_assoc */
|
||||
#define MYSQLI_ASSOC 1
|
||||
|
@ -969,9 +969,9 @@ array(61) {
|
||||
["mem_efree_count"]=>
|
||||
string(1) "0"
|
||||
["mem_malloc_count"]=>
|
||||
string(1) "0"
|
||||
string(1) "1"
|
||||
["mem_malloc_ammount"]=>
|
||||
string(1) "0"
|
||||
string(%d) "%d"
|
||||
["mem_calloc_count"]=>
|
||||
string(1) "0"
|
||||
["mem_calloc_ammount"]=>
|
||||
@ -1106,9 +1106,9 @@ array(61) {
|
||||
[u"mem_efree_count"]=>
|
||||
unicode(1) "0"
|
||||
[u"mem_malloc_count"]=>
|
||||
unicode(1) "0"
|
||||
unicode(1) "1"
|
||||
[u"mem_malloc_ammount"]=>
|
||||
unicode(1) "0"
|
||||
unicode(%d) "%d"
|
||||
[u"mem_calloc_count"]=>
|
||||
unicode(1) "0"
|
||||
[u"mem_calloc_ammount"]=>
|
||||
|
@ -66,12 +66,205 @@ const char * mysqlnd_out_of_sync = "Commands out of sync; you can't run this com
|
||||
MYSQLND_STATS *mysqlnd_global_stats = NULL;
|
||||
static zend_bool mysqlnd_library_initted = FALSE;
|
||||
|
||||
MYSQLND_MEMORY_POOL mysqlnd_memory_pool;
|
||||
|
||||
static enum_func_status mysqlnd_send_close(MYSQLND * conn TSRMLS_DC);
|
||||
|
||||
#define MYSQLND_SILENT 1
|
||||
|
||||
#ifdef MYSQLND_THREADED
|
||||
/* {{{ _mysqlnd_fetch_thread */
|
||||
void * _mysqlnd_fetch_thread(void *arg)
|
||||
{
|
||||
MYSQLND *conn = (MYSQLND *) arg;
|
||||
MYSQLND_RES * result = NULL;
|
||||
void ***tsrm_ls = conn->tsrm_ls;
|
||||
#ifndef MYSQLND_SILENT
|
||||
printf("conn=%p tsrm_ls=%p\n", conn, conn->tsrm_ls);
|
||||
#endif
|
||||
do {
|
||||
pthread_mutex_lock(&conn->LOCK_work);
|
||||
while (conn->thread_killed == FALSE /* && there is work */) {
|
||||
#ifndef MYSQLND_SILENT
|
||||
printf("Waiting for work in %s\n", __FUNCTION__);
|
||||
#endif
|
||||
pthread_cond_wait(&conn->COND_work, &conn->LOCK_work);
|
||||
}
|
||||
if (conn->thread_killed == TRUE) {
|
||||
#ifndef MYSQLND_SILENT
|
||||
printf("Thread killed in %s\n", __FUNCTION__);
|
||||
#endif
|
||||
pthread_cond_signal(&conn->COND_thread_ended);
|
||||
pthread_mutex_unlock(&conn->LOCK_work);
|
||||
break;
|
||||
}
|
||||
#ifndef MYSQLND_SILENT
|
||||
printf("Got work in %s\n", __FUNCTION__);
|
||||
#endif
|
||||
CONN_SET_STATE(conn, CONN_FETCHING_DATA);
|
||||
result = conn->current_result;
|
||||
conn->current_result = NULL;
|
||||
pthread_mutex_unlock(&conn->LOCK_work);
|
||||
|
||||
mysqlnd_background_store_result_fetch_data(result TSRMLS_CC);
|
||||
|
||||
/* do fetch the data from the wire */
|
||||
|
||||
pthread_mutex_lock(&conn->LOCK_work);
|
||||
CONN_SET_STATE(conn, CONN_READY);
|
||||
pthread_cond_signal(&conn->COND_work_done);
|
||||
#ifndef MYSQLND_SILENT
|
||||
printf("Signaling work done in %s\n", __FUNCTION__);
|
||||
#endif
|
||||
pthread_mutex_unlock(&conn->LOCK_work);
|
||||
} while (1);
|
||||
|
||||
#ifndef MYSQLND_SILENT
|
||||
printf("Exiting worker thread in %s\n", __FUNCTION__);
|
||||
#endif
|
||||
return NULL;
|
||||
}
|
||||
/* }}} */
|
||||
#endif /* MYSQLND_THREADED */
|
||||
|
||||
/************************************************************************************************/
|
||||
/* Let's don't use pool allocation for now */
|
||||
/* {{{ mysqlnd_mempool_free_chunk */
|
||||
static
|
||||
void mysqlnd_mempool_free_contents(MYSQLND_MEMORY_POOL * pool TSRMLS_DC)
|
||||
{
|
||||
DBG_ENTER("mysqlnd_mempool_dtor");
|
||||
uint i;
|
||||
for (i = 0; i < pool->free_chunk_list_elements; i++) {
|
||||
MYSQLND_MEMORY_POOL_CHUNK * chunk = pool->free_chunk_list[i];
|
||||
chunk->free_chunk(chunk, FALSE TSRMLS_CC);
|
||||
}
|
||||
|
||||
DBG_VOID_RETURN;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* Let's don't use pool allocation for now */
|
||||
/* {{{ mysqlnd_mempool_free_chunk */
|
||||
static
|
||||
void mysqlnd_mempool_free_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, zend_bool cache_it TSRMLS_DC)
|
||||
{
|
||||
DBG_ENTER("mysqlnd_mempool_free_chunk");
|
||||
MYSQLND_MEMORY_POOL * pool = chunk->pool;
|
||||
if (chunk->from_pool) {
|
||||
/* Try to back-off and guess if this is the last block allocated */
|
||||
if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) {
|
||||
/*
|
||||
This was the last allocation. Lucky us, we can free
|
||||
a bit of memory from the pool. Next time we will return from the same ptr.
|
||||
*/
|
||||
pool->free_size += chunk->size;
|
||||
}
|
||||
pool->refcount--;
|
||||
} else {
|
||||
mnd_free(chunk->ptr);
|
||||
}
|
||||
if (cache_it && pool->free_chunk_list_elements < MYSQLND_MEMORY_POOL_CHUNK_LIST_SIZE) {
|
||||
chunk->ptr = NULL;
|
||||
pool->free_chunk_list[pool->free_chunk_list_elements++] = chunk;
|
||||
} else {
|
||||
/* We did not cache it -> free it */
|
||||
mnd_free(chunk);
|
||||
}
|
||||
DBG_VOID_RETURN;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_mempool_resize_chunk */
|
||||
static void
|
||||
mysqlnd_mempool_resize_chunk(MYSQLND_MEMORY_POOL_CHUNK * chunk, uint size TSRMLS_DC)
|
||||
{
|
||||
DBG_ENTER("mysqlnd_mempool_resize_chunk");
|
||||
if (chunk->from_pool) {
|
||||
MYSQLND_MEMORY_POOL * pool = chunk->pool;
|
||||
/* Try to back-off and guess if this is the last block allocated */
|
||||
if (chunk->ptr == (pool->arena + (pool->arena_size - pool->free_size - chunk->size))) {
|
||||
/*
|
||||
This was the last allocation. Lucky us, we can free
|
||||
a bit of memory from the pool. Next time we will return from the same ptr.
|
||||
*/
|
||||
if ((chunk->size + pool->free_size) < size) {
|
||||
zend_uchar *new_ptr;
|
||||
new_ptr = mnd_malloc(size);
|
||||
memcpy(new_ptr, chunk->ptr, chunk->size);
|
||||
chunk->ptr = new_ptr;
|
||||
pool->free_size += chunk->size;
|
||||
chunk->size = size;
|
||||
chunk->pool = NULL; /* now we have no pool memory */
|
||||
pool->refcount--;
|
||||
} else {
|
||||
/* If the chunk is > than asked size then free_memory increases, otherwise decreases*/
|
||||
pool->free_size += (chunk->size - size);
|
||||
}
|
||||
} else {
|
||||
/* Not last chunk, if the user asks for less, give it to him */
|
||||
if (chunk->size >= size) {
|
||||
; /* nop */
|
||||
} else {
|
||||
zend_uchar *new_ptr;
|
||||
new_ptr = mnd_malloc(size);
|
||||
memcpy(new_ptr, chunk->ptr, chunk->size);
|
||||
chunk->ptr = new_ptr;
|
||||
chunk->size = size;
|
||||
chunk->pool = NULL; /* now we have no pool memory */
|
||||
pool->refcount--;
|
||||
}
|
||||
}
|
||||
} else {
|
||||
chunk->ptr = mnd_realloc(chunk->ptr, size);
|
||||
}
|
||||
DBG_VOID_RETURN;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_mempool_get_chunk */
|
||||
static
|
||||
MYSQLND_MEMORY_POOL_CHUNK * mysqlnd_mempool_get_chunk(MYSQLND_MEMORY_POOL * pool, uint size TSRMLS_DC)
|
||||
{
|
||||
MYSQLND_MEMORY_POOL_CHUNK *chunk = NULL;
|
||||
DBG_ENTER("mysqlnd_mempool_get_chunk");
|
||||
|
||||
if (pool->free_chunk_list_elements) {
|
||||
chunk = pool->free_chunk_list[--pool->free_chunk_list_elements];
|
||||
} else {
|
||||
chunk = mnd_malloc(sizeof(MYSQLND_MEMORY_POOL_CHUNK));
|
||||
}
|
||||
|
||||
chunk->free_chunk = mysqlnd_mempool_free_chunk;
|
||||
chunk->resize_chunk = mysqlnd_mempool_resize_chunk;
|
||||
chunk->size = size;
|
||||
/*
|
||||
Should not go over MYSQLND_MAX_PACKET_SIZE, since we
|
||||
expect non-arena memory in mysqlnd_wireprotocol.c . We
|
||||
realloc the non-arena memory.
|
||||
*/
|
||||
chunk->pool = pool;
|
||||
if (size > pool->free_size) {
|
||||
chunk->ptr = mnd_malloc(size);
|
||||
chunk->from_pool = FALSE;
|
||||
} else {
|
||||
chunk->from_pool = TRUE;
|
||||
++pool->refcount;
|
||||
chunk->ptr = pool->arena + (pool->arena_size - pool->free_size);
|
||||
/* Last step, update free_size */
|
||||
pool->free_size -= size;
|
||||
}
|
||||
DBG_RETURN(chunk);
|
||||
}
|
||||
/* }}} */
|
||||
/************************************************************************************************/
|
||||
|
||||
|
||||
/* {{{ mysqlnd_library_init */
|
||||
static
|
||||
void mysqlnd_library_init()
|
||||
void mysqlnd_library_init(TSRMLS_D)
|
||||
{
|
||||
if (mysqlnd_library_initted == FALSE) {
|
||||
mysqlnd_library_initted = TRUE;
|
||||
@ -81,6 +274,13 @@ void mysqlnd_library_init()
|
||||
#ifdef ZTS
|
||||
mysqlnd_global_stats->LOCK_access = tsrm_mutex_alloc();
|
||||
#endif
|
||||
mysqlnd_memory_pool.arena_size = 16000;
|
||||
mysqlnd_memory_pool.free_size = mysqlnd_memory_pool.arena_size;
|
||||
mysqlnd_memory_pool.refcount = 0;
|
||||
/* OOM ? */
|
||||
mysqlnd_memory_pool.arena = mnd_malloc(mysqlnd_memory_pool.arena_size);
|
||||
mysqlnd_memory_pool.get_chunk = mysqlnd_mempool_get_chunk;
|
||||
mysqlnd_memory_pool.free_contents = mysqlnd_mempool_free_contents;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
@ -88,9 +288,12 @@ void mysqlnd_library_init()
|
||||
|
||||
/* {{{ mysqlnd_library_end */
|
||||
static
|
||||
void mysqlnd_library_end()
|
||||
void mysqlnd_library_end(TSRMLS_D)
|
||||
{
|
||||
if (mysqlnd_library_initted == TRUE) {
|
||||
/* mnd_free will reference LOCK_access and won't crash...*/
|
||||
mysqlnd_memory_pool.free_contents(&mysqlnd_memory_pool TSRMLS_CC);
|
||||
free(mysqlnd_memory_pool.arena);
|
||||
#ifdef ZTS
|
||||
tsrm_mutex_free(mysqlnd_global_stats->LOCK_access);
|
||||
#endif
|
||||
@ -229,6 +432,7 @@ MYSQLND_METHOD(mysqlnd_conn, free_contents)(MYSQLND *conn TSRMLS_DC)
|
||||
mnd_pefree(conn->net.cmd_buffer.buffer, pers);
|
||||
conn->net.cmd_buffer.buffer = NULL;
|
||||
}
|
||||
|
||||
conn->charset = NULL;
|
||||
conn->greet_charset = NULL;
|
||||
|
||||
@ -246,6 +450,22 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn, dtor)(MYSQLND *conn TSRMLS_DC)
|
||||
|
||||
conn->m->free_contents(conn TSRMLS_CC);
|
||||
|
||||
#ifdef MYSQLND_THREADED
|
||||
if (conn->thread_is_running) {
|
||||
pthread_mutex_lock(&conn->LOCK_work);
|
||||
conn->thread_killed = TRUE;
|
||||
pthread_cond_signal(&conn->COND_work);
|
||||
pthread_cond_wait(&conn->COND_thread_ended, &conn->LOCK_work);
|
||||
pthread_mutex_unlock(&conn->LOCK_work);
|
||||
}
|
||||
|
||||
tsrm_mutex_free(conn->LOCK_state);
|
||||
|
||||
pthread_cond_destroy(&conn->COND_work);
|
||||
pthread_cond_destroy(&conn->COND_work_done);
|
||||
pthread_mutex_destroy(&conn->LOCK_work);
|
||||
#endif
|
||||
|
||||
mnd_pefree(conn, conn->persistent);
|
||||
|
||||
DBG_VOID_RETURN;
|
||||
@ -363,7 +583,7 @@ mysqlnd_simple_command(MYSQLND *conn, enum php_mysqlnd_server_command command,
|
||||
DBG_ENTER("mysqlnd_simple_command");
|
||||
DBG_INF_FMT("command=%s ok_packet=%d silent=%d", mysqlnd_command_to_text[command], ok_packet, silent);
|
||||
|
||||
switch (conn->state) {
|
||||
switch (CONN_GET_STATE(conn)) {
|
||||
case CONN_READY:
|
||||
break;
|
||||
case CONN_QUIT_SENT:
|
||||
@ -481,13 +701,13 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
|
||||
DBG_ENTER("mysqlnd_connect");
|
||||
DBG_INF_FMT("host=%s user=%s db=%s port=%d flags=%d persistent=%d state=%d",
|
||||
host?host:"", user?user:"", db?db:"", port, mysql_flags,
|
||||
conn? conn->persistent:0, conn? conn->state:-1);
|
||||
conn? conn->persistent:0, conn? CONN_GET_STATE(conn):-1);
|
||||
|
||||
DBG_INF_FMT("state=%d", conn->state);
|
||||
if (conn && conn->state > CONN_ALLOCED && conn->state ) {
|
||||
DBG_INF_FMT("state=%d", CONN_GET_STATE(conn));
|
||||
if (conn && CONN_GET_STATE(conn) > CONN_ALLOCED && CONN_GET_STATE(conn) ) {
|
||||
DBG_INF("Connecting on a connected handle.");
|
||||
|
||||
if (conn->state < CONN_QUIT_SENT) {
|
||||
if (CONN_GET_STATE(conn) < CONN_QUIT_SENT) {
|
||||
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_CLOSE_IMPLICIT);
|
||||
reconnect = TRUE;
|
||||
mysqlnd_send_close(conn TSRMLS_CC);
|
||||
@ -551,7 +771,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
|
||||
self_alloced = TRUE;
|
||||
}
|
||||
|
||||
conn->state = CONN_ALLOCED;
|
||||
CONN_SET_STATE(conn, CONN_ALLOCED);
|
||||
conn->net.packet_no = 0;
|
||||
|
||||
if (conn->options.timeout_connect) {
|
||||
@ -663,7 +883,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
|
||||
conn->scramble = auth_packet->server_scramble_buf = mnd_pemalloc(SCRAMBLE_LENGTH, conn->persistent);
|
||||
memcpy(auth_packet->server_scramble_buf, greet_packet.scramble_buf, SCRAMBLE_LENGTH);
|
||||
if (!PACKET_WRITE(auth_packet, conn)) {
|
||||
conn->state = CONN_QUIT_SENT;
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT);
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);
|
||||
goto err;
|
||||
}
|
||||
@ -687,7 +907,7 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
|
||||
}
|
||||
}
|
||||
} else {
|
||||
conn->state = CONN_READY;
|
||||
CONN_SET_STATE(conn, CONN_READY);
|
||||
|
||||
conn->user = pestrdup(user, conn->persistent);
|
||||
conn->passwd = pestrndup(passwd, passwd_len, conn->persistent);
|
||||
@ -759,6 +979,23 @@ PHPAPI MYSQLND *mysqlnd_connect(MYSQLND *conn,
|
||||
DBG_INF("unicode set");
|
||||
}
|
||||
#endif
|
||||
#ifdef MYSQLND_THREADED
|
||||
{
|
||||
pthread_t th;
|
||||
pthread_attr_t connection_attrib;
|
||||
conn->tsrm_ls = tsrm_ls;
|
||||
|
||||
pthread_attr_init(&connection_attrib);
|
||||
pthread_attr_setdetachstate(&connection_attrib, PTHREAD_CREATE_DETACHED);
|
||||
|
||||
conn->thread_is_running = TRUE;
|
||||
if (pthread_create(&th, &connection_attrib, _mysqlnd_fetch_thread, (void*)conn)) {
|
||||
conn->thread_is_running = FALSE;
|
||||
}
|
||||
}
|
||||
#endif
|
||||
|
||||
|
||||
DBG_RETURN(conn);
|
||||
}
|
||||
err:
|
||||
@ -1081,7 +1318,7 @@ MYSQLND_METHOD(mysqlnd_conn, kill)(MYSQLND *conn, unsigned int pid TSRMLS_DC)
|
||||
SET_ERROR_AFF_ROWS(conn);
|
||||
} else if (PASS == (ret = mysqlnd_simple_command(conn, COM_PROCESS_KILL, buff,
|
||||
4, PROT_LAST, FALSE TSRMLS_CC))) {
|
||||
conn->state = CONN_QUIT_SENT;
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT);
|
||||
}
|
||||
DBG_RETURN(ret);
|
||||
}
|
||||
@ -1154,7 +1391,7 @@ MYSQLND_METHOD(mysqlnd_conn, shutdown)(MYSQLND * const conn, unsigned long level
|
||||
|
||||
|
||||
/* {{{ mysqlnd_send_close */
|
||||
enum_func_status
|
||||
static enum_func_status
|
||||
mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
|
||||
{
|
||||
enum_func_status ret = PASS;
|
||||
@ -1163,7 +1400,7 @@ mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
|
||||
DBG_INF_FMT("conn=%llu conn->net.stream->abstract=%p",
|
||||
conn->thread_id, conn->net.stream? conn->net.stream->abstract:NULL);
|
||||
|
||||
switch (conn->state) {
|
||||
switch (CONN_GET_STATE(conn)) {
|
||||
case CONN_READY:
|
||||
DBG_INF("Connection clean, sending COM_QUIT");
|
||||
ret = mysqlnd_simple_command(conn, COM_QUIT, NULL, 0, PROT_LAST,
|
||||
@ -1199,7 +1436,7 @@ mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
|
||||
We hold one reference, and every other object which needs the
|
||||
connection does increase it by 1.
|
||||
*/
|
||||
conn->state = CONN_QUIT_SENT;
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT);
|
||||
|
||||
DBG_RETURN(ret);
|
||||
}
|
||||
@ -1236,7 +1473,6 @@ MYSQLND_METHOD(mysqlnd_conn, close)(MYSQLND * conn, enum_connection_close_type c
|
||||
|
||||
ret = conn->m->free_reference(conn TSRMLS_CC);
|
||||
|
||||
|
||||
DBG_RETURN(ret);
|
||||
}
|
||||
/* }}} */
|
||||
@ -1273,6 +1509,46 @@ MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference)(MYSQLND * const conn TSRMLS
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_conn::get_state */
|
||||
#ifdef MYSQLND_THREADED
|
||||
static enum mysqlnd_connection_state
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state)(MYSQLND * const conn TSRMLS_DC)
|
||||
{
|
||||
enum mysqlnd_connection_state state;
|
||||
DBG_ENTER("mysqlnd_conn::get_state");
|
||||
tsrm_mutex_lock(conn->LOCK_state);
|
||||
state = conn->state;
|
||||
tsrm_mutex_unlock(conn->LOCK_state);
|
||||
DBG_RETURN(state);
|
||||
}
|
||||
#else
|
||||
static enum mysqlnd_connection_state
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state)(MYSQLND * const conn TSRMLS_DC)
|
||||
{
|
||||
DBG_ENTER("mysqlnd_conn::get_state");
|
||||
DBG_RETURN(conn->state);
|
||||
}
|
||||
#endif
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_conn::set_state */
|
||||
static void
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC)
|
||||
{
|
||||
DBG_ENTER("mysqlnd_conn::set_state");
|
||||
#ifdef MYSQLND_THREADED
|
||||
tsrm_mutex_lock(conn->LOCK_state);
|
||||
#endif
|
||||
conn->state = new_state;
|
||||
#ifdef MYSQLND_THREADED
|
||||
tsrm_mutex_unlock(conn->LOCK_state);
|
||||
#endif
|
||||
DBG_VOID_RETURN;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_conn::field_count */
|
||||
static unsigned int
|
||||
MYSQLND_METHOD(mysqlnd_conn, field_count)(const MYSQLND * const conn)
|
||||
@ -1420,7 +1696,7 @@ MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC)
|
||||
DBG_ENTER("mysqlnd_conn::next_result");
|
||||
DBG_INF_FMT("conn=%llu", conn->thread_id);
|
||||
|
||||
if (conn->state != CONN_NEXT_RESULT_PENDING) {
|
||||
if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING) {
|
||||
DBG_RETURN(FAIL);
|
||||
}
|
||||
|
||||
@ -1433,7 +1709,7 @@ MYSQLND_METHOD(mysqlnd_conn, next_result)(MYSQLND * const conn TSRMLS_DC)
|
||||
if (FAIL == (ret = mysqlnd_query_read_result_set_header(conn, NULL TSRMLS_CC))) {
|
||||
DBG_ERR_FMT("Serious error. %s::%d", __FILE__, __LINE__);
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "Serious error. PID=%d", getpid());
|
||||
conn->state = CONN_QUIT_SENT;
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT);
|
||||
}
|
||||
|
||||
DBG_RETURN(ret);
|
||||
@ -1710,7 +1986,7 @@ MYSQLND_METHOD(mysqlnd_conn, use_result)(MYSQLND * const conn TSRMLS_DC)
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA */
|
||||
if (conn->last_query_type != QUERY_SELECT || conn->state != CONN_FETCHING_DATA) {
|
||||
if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
|
||||
mysqlnd_out_of_sync);
|
||||
DBG_ERR("Command out of sync");
|
||||
@ -1743,7 +2019,7 @@ MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC)
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (conn->last_query_type != QUERY_SELECT || conn->state != CONN_FETCHING_DATA) {
|
||||
if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
|
||||
mysqlnd_out_of_sync);
|
||||
DBG_ERR("Command out of sync");
|
||||
@ -1761,6 +2037,44 @@ MYSQLND_METHOD(mysqlnd_conn, store_result)(MYSQLND * const conn TSRMLS_DC)
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_conn::background_store_result */
|
||||
MYSQLND_RES *
|
||||
MYSQLND_METHOD(mysqlnd_conn, background_store_result)(MYSQLND * const conn TSRMLS_DC)
|
||||
{
|
||||
MYSQLND_RES *result;
|
||||
|
||||
DBG_ENTER("mysqlnd_conn::store_result");
|
||||
DBG_INF_FMT("conn=%llu", conn->thread_id);
|
||||
|
||||
if (!conn->current_result) {
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (conn->last_query_type != QUERY_SELECT || CONN_GET_STATE(conn) != CONN_FETCHING_DATA) {
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
|
||||
mysqlnd_out_of_sync);
|
||||
DBG_ERR("Command out of sync");
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BUFFERED_SETS);
|
||||
|
||||
result = conn->current_result;
|
||||
|
||||
result = result->m.background_store_result(result, conn, FALSE TSRMLS_CC);
|
||||
|
||||
/*
|
||||
Should be here, because current_result is used by the fetching thread to get data info
|
||||
The thread is contacted in mysqlnd_res::background_store_result().
|
||||
*/
|
||||
conn->current_result = NULL;
|
||||
|
||||
DBG_RETURN(result);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_conn::get_connection_stats */
|
||||
static void
|
||||
MYSQLND_METHOD(mysqlnd_conn, get_connection_stats)(const MYSQLND * const conn,
|
||||
@ -1784,6 +2098,7 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
|
||||
MYSQLND_METHOD(mysqlnd_conn, query),
|
||||
MYSQLND_METHOD(mysqlnd_conn, use_result),
|
||||
MYSQLND_METHOD(mysqlnd_conn, store_result),
|
||||
MYSQLND_METHOD(mysqlnd_conn, background_store_result),
|
||||
MYSQLND_METHOD(mysqlnd_conn, next_result),
|
||||
MYSQLND_METHOD(mysqlnd_conn, more_results),
|
||||
|
||||
@ -1829,6 +2144,8 @@ MYSQLND_CLASS_METHODS_START(mysqlnd_conn)
|
||||
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_reference),
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, free_reference),
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, get_state),
|
||||
MYSQLND_METHOD_PRIVATE(mysqlnd_conn, set_state),
|
||||
MYSQLND_CLASS_METHODS_END;
|
||||
|
||||
|
||||
@ -1846,6 +2163,15 @@ PHPAPI MYSQLND *_mysqlnd_init(zend_bool persistent TSRMLS_DC)
|
||||
ret->m = & mysqlnd_mysqlnd_conn_methods;
|
||||
ret->m->get_reference(ret);
|
||||
|
||||
#ifdef MYSQLND_THREADED
|
||||
ret->LOCK_state = tsrm_mutex_alloc();
|
||||
|
||||
pthread_mutex_init(&ret->LOCK_work, NULL);
|
||||
pthread_cond_init(&ret->COND_work, NULL);
|
||||
pthread_cond_init(&ret->COND_work_done, NULL);
|
||||
pthread_cond_init(&ret->COND_thread_ended, NULL);
|
||||
#endif
|
||||
|
||||
DBG_RETURN(ret);
|
||||
}
|
||||
/* }}} */
|
||||
@ -1985,7 +2311,7 @@ static PHP_MINIT_FUNCTION(mysqlnd)
|
||||
{
|
||||
REGISTER_INI_ENTRIES();
|
||||
|
||||
mysqlnd_library_init();
|
||||
mysqlnd_library_init(TSRMLS_C);
|
||||
return SUCCESS;
|
||||
}
|
||||
/* }}} */
|
||||
@ -1995,7 +2321,7 @@ static PHP_MINIT_FUNCTION(mysqlnd)
|
||||
*/
|
||||
static PHP_MSHUTDOWN_FUNCTION(mysqlnd)
|
||||
{
|
||||
mysqlnd_library_end();
|
||||
mysqlnd_library_end(TSRMLS_C);
|
||||
|
||||
UNREGISTER_INI_ENTRIES();
|
||||
return SUCCESS;
|
||||
|
@ -29,6 +29,9 @@
|
||||
/* This forces inlining of some accessor functions */
|
||||
#define MYSQLND_USE_OPTIMISATIONS 0
|
||||
|
||||
|
||||
//#define MYSQLND_THREADING
|
||||
|
||||
/* #define MYSQLND_STRING_TO_INT_CONVERSION */
|
||||
/*
|
||||
This force mysqlnd to do a single (or more depending on ammount of data)
|
||||
@ -98,6 +101,7 @@ void _mysqlnd_debug(const char *mode TSRMLS_DC);
|
||||
|
||||
#define mysqlnd_use_result(conn) (conn)->m->use_result((conn) TSRMLS_CC)
|
||||
#define mysqlnd_store_result(conn) (conn)->m->store_result((conn) TSRMLS_CC)
|
||||
#define mysqlnd_bg_store_result(conn) (conn)->m->background_store_result((conn) TSRMLS_CC)
|
||||
#define mysqlnd_next_result(conn) (conn)->m->next_result((conn) TSRMLS_CC)
|
||||
#define mysqlnd_more_results(conn) (conn)->m->more_results((conn))
|
||||
#define mysqlnd_free_result(r,e_or_i) ((MYSQLND_RES*)r)->m.free_result(((MYSQLND_RES*)(r)), (e_or_i) TSRMLS_CC)
|
||||
@ -242,6 +246,7 @@ PHPAPI ulong mysqlnd_old_escape_string(char *newstr, const char *escapestr, size
|
||||
/* PS */
|
||||
#define mysqlnd_stmt_init(conn) (conn)->m->stmt_init((conn) TSRMLS_CC)
|
||||
#define mysqlnd_stmt_store_result(stmt) (!mysqlnd_stmt_field_count((stmt)) ? PASS:((stmt)->m->store_result((stmt) TSRMLS_CC)? PASS:FAIL))
|
||||
#define mysqlnd_stmt_bg_store_result(stmt) (!mysqlnd_stmt_field_count((stmt)) ? PASS:((stmt)->m->background_store_result((stmt) TSRMLS_CC)? PASS:FAIL))
|
||||
#define mysqlnd_stmt_get_result(stmt) (stmt)->m->get_result((stmt) TSRMLS_CC)
|
||||
#define mysqlnd_stmt_data_seek(stmt, row) (stmt)->m->seek_data((stmt), (row) TSRMLS_CC)
|
||||
#define mysqlnd_stmt_prepare(stmt, q, qlen) (stmt)->m->prepare((stmt), (q), (qlen) TSRMLS_CC)
|
||||
|
@ -22,6 +22,7 @@
|
||||
#ifndef MYSQLND_ENUM_N_DEF_H
|
||||
#define MYSQLND_ENUM_N_DEF_H
|
||||
|
||||
#define MYSQLND_MAX_PACKET_SIZE (256L*256L*256L-1)
|
||||
|
||||
#define MYSQLND_ERRMSG_SIZE 512
|
||||
#define MYSQLND_SQLSTATE_LENGTH 5
|
||||
|
@ -108,6 +108,7 @@
|
||||
#define mysql_free_result(r) mysqlnd_free_result((r), FALSE)
|
||||
#define mysql_store_result(r) mysqlnd_store_result((r))
|
||||
#define mysql_use_result(r) mysqlnd_use_result((r))
|
||||
#define mysql_async_store_result(r) mysqlnd_async_store_result((r))
|
||||
#define mysql_thread_id(r) mysqlnd_thread_id((r))
|
||||
#define mysql_get_client_info() mysqlnd_get_client_info()
|
||||
#define mysql_get_client_version() mysqlnd_get_client_version()
|
||||
@ -116,6 +117,6 @@
|
||||
#define mysql_get_server_info(r) mysqlnd_get_server_info((r))
|
||||
#define mysql_get_server_version(r) mysqlnd_get_server_version((r))
|
||||
#define mysql_warning_count(r) mysqlnd_warning_count((r))
|
||||
#define mysql_eof(r) (((r)->unbuf && (r)->unbuf->eof_reached) || (r)->data)
|
||||
#define mysql_eof(r) (((r)->unbuf && (r)->unbuf->eof_reached) || (r)->stored_data)
|
||||
|
||||
#endif /* MYSQLND_LIBMYSQL_COMPAT_H */
|
||||
|
@ -156,6 +156,14 @@
|
||||
#define SET_STMT_ERROR(stmt, a, b, c) SET_CLIENT_ERROR(stmt->error_info, a, b, c)
|
||||
|
||||
|
||||
#ifdef ZTS
|
||||
#define CONN_GET_STATE(c) (c)->m->get_state((c) TSRMLS_CC)
|
||||
#define CONN_SET_STATE(c, s) (c)->m->set_state((c), (s) TSRMLS_CC)
|
||||
#else
|
||||
#define CONN_GET_STATE(c) (c)->state
|
||||
#define CONN_SET_STATE(c, s) (c)->state = s
|
||||
#endif
|
||||
|
||||
|
||||
/* PS stuff */
|
||||
typedef void (*ps_field_fetch_func)(zval *zv, const MYSQLND_FIELD * const field,
|
||||
@ -175,6 +183,8 @@ extern struct st_mysqlnd_perm_bind mysqlnd_ps_fetch_functions[MYSQL_TYPE_LAST +
|
||||
extern const char * mysqlnd_out_of_sync;
|
||||
extern const char * mysqlnd_server_gone;
|
||||
|
||||
extern MYSQLND_MEMORY_POOL mysqlnd_memory_pool;
|
||||
|
||||
|
||||
enum_func_status mysqlnd_handle_local_infile(MYSQLND *conn, const char *filename, zend_bool *is_warning TSRMLS_DC);
|
||||
|
||||
|
@ -83,7 +83,74 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (conn->state != CONN_FETCHING_DATA ||
|
||||
if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA ||
|
||||
stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
|
||||
{
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
|
||||
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
stmt->default_rset_handler = stmt->m->store_result;
|
||||
|
||||
SET_EMPTY_ERROR(stmt->error_info);
|
||||
SET_EMPTY_ERROR(stmt->conn->error_info);
|
||||
MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_PS_BUFFERED_SETS);
|
||||
|
||||
result = stmt->result;
|
||||
result->type = MYSQLND_RES_PS_BUF;
|
||||
result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
|
||||
result->m.fetch_lengths = NULL;/* makes no sense */
|
||||
result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
|
||||
|
||||
/* Create room for 'next_extend' rows */
|
||||
|
||||
ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
|
||||
TRUE, to_cache TSRMLS_CC);
|
||||
|
||||
if (PASS == ret) {
|
||||
/* libmysql API docs say it should be so for SELECT statements */
|
||||
stmt->upsert_status.affected_rows = stmt->result->stored_data->row_count;
|
||||
|
||||
stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
|
||||
} else {
|
||||
conn->error_info = result->stored_data->error_info;
|
||||
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
|
||||
mnd_efree(stmt->result);
|
||||
stmt->result = NULL;
|
||||
stmt->state = MYSQLND_STMT_PREPARED;
|
||||
}
|
||||
|
||||
DBG_RETURN(result);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_stmt::background_store_result */
|
||||
static MYSQLND_RES *
|
||||
MYSQLND_METHOD(mysqlnd_stmt, background_store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
{
|
||||
enum_func_status ret;
|
||||
MYSQLND *conn = stmt->conn;
|
||||
MYSQLND_RES *result;
|
||||
zend_bool to_cache = FALSE;
|
||||
|
||||
DBG_ENTER("mysqlnd_stmt::store_result");
|
||||
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
|
||||
|
||||
/* be compliant with libmysql - NULL will turn */
|
||||
if (!stmt->field_count) {
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
if (stmt->cursor_exists) {
|
||||
/* Silently convert buffered to unbuffered, for now */
|
||||
MYSQLND_RES * res = stmt->m->use_result(stmt TSRMLS_CC);
|
||||
DBG_RETURN(res);
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA ||
|
||||
stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
|
||||
{
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
|
||||
@ -112,16 +179,15 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
}
|
||||
|
||||
ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
|
||||
TRUE, stmt->update_max_length,
|
||||
to_cache TSRMLS_CC);
|
||||
TRUE, to_cache TSRMLS_CC);
|
||||
|
||||
if (PASS == ret) {
|
||||
/* libmysql API docs say it should be so for SELECT statements */
|
||||
stmt->upsert_status.affected_rows = stmt->result->data->row_count;
|
||||
stmt->upsert_status.affected_rows = stmt->result->stored_data->row_count;
|
||||
|
||||
stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
|
||||
} else {
|
||||
conn->error_info = result->data->error_info;
|
||||
conn->error_info = result->stored_data->error_info;
|
||||
stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
|
||||
mnd_efree(stmt->result);
|
||||
stmt->result = NULL;
|
||||
@ -132,7 +198,6 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
|
||||
/* {{{ mysqlnd_stmt::get_result */
|
||||
static MYSQLND_RES *
|
||||
MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
@ -155,7 +220,7 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
}
|
||||
|
||||
/* Nothing to store for UPSERT/LOAD DATA*/
|
||||
if (conn->state != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
|
||||
if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
|
||||
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
|
||||
DBG_RETURN(NULL);
|
||||
@ -170,14 +235,8 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
|
||||
result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
|
||||
|
||||
/* Not set for SHOW statements at PREPARE stage */
|
||||
if (stmt->result->conn) {
|
||||
stmt->result->conn->m->free_reference(stmt->result->conn TSRMLS_CC);
|
||||
stmt->result->conn = NULL; /* store result does not reference the connection */
|
||||
}
|
||||
|
||||
if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) {
|
||||
stmt->upsert_status.affected_rows = result->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 {
|
||||
@ -458,7 +517,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
if (ret == FAIL) {
|
||||
stmt->error_info = conn->error_info;
|
||||
stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
|
||||
if (conn->state == CONN_QUIT_SENT) {
|
||||
if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
|
||||
/* close the statement here, the connection has been closed */
|
||||
}
|
||||
} else {
|
||||
@ -500,7 +559,7 @@ MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
|
||||
if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
|
||||
stmt->cursor_exists = TRUE;
|
||||
conn->state = CONN_READY;
|
||||
CONN_SET_STATE(conn, CONN_READY);
|
||||
/* Only cursor read */
|
||||
stmt->default_rset_handler = stmt->m->use_result;
|
||||
DBG_INF("use_result");
|
||||
@ -539,17 +598,45 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
|
||||
{
|
||||
unsigned int i;
|
||||
MYSQLND_STMT *stmt = (MYSQLND_STMT *) param;
|
||||
uint field_count = result->meta->field_count;
|
||||
MYSQLND_RES_BUFFERED *set = result->stored_data;
|
||||
|
||||
DBG_ENTER("mysqlnd_fetch_stmt_row_buffered");
|
||||
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
|
||||
|
||||
/* If we haven't read everything */
|
||||
if (result->data->data_cursor &&
|
||||
(result->data->data_cursor - result->data->data) < result->data->row_count)
|
||||
if (set->data_cursor &&
|
||||
(set->data_cursor - set->data) < (set->row_count * field_count))
|
||||
{
|
||||
/* The user could have skipped binding - don't crash*/
|
||||
if (stmt->result_bind) {
|
||||
zval **current_row = *result->data->data_cursor;
|
||||
zval **current_row = set->data_cursor;
|
||||
|
||||
if (NULL == current_row[0]) {
|
||||
set->initialized_rows++;
|
||||
uint64 row_num = (set->data_cursor - set->data) / field_count;
|
||||
result->m.row_decoder(set->row_buffers[row_num],
|
||||
current_row,
|
||||
result->meta->field_count,
|
||||
result->meta->fields,
|
||||
result->conn TSRMLS_CC);
|
||||
if (stmt->update_max_length) {
|
||||
for (i = 0; i < result->field_count; i++) {
|
||||
/*
|
||||
NULL fields are 0 length, 0 is not more than 0
|
||||
String of zero size, definitely can't be the next max_length.
|
||||
Thus for NULL and zero-length we are quite efficient.
|
||||
*/
|
||||
if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
|
||||
unsigned long len = Z_STRLEN_P(current_row[i]);
|
||||
if (result->meta->fields[i].max_length < len) {
|
||||
result->meta->fields[i].max_length = len;
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
}
|
||||
|
||||
for (i = 0; i < result->field_count; i++) {
|
||||
/* Clean what we copied last time */
|
||||
#ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
|
||||
@ -578,13 +665,13 @@ mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param, unsigned int f
|
||||
}
|
||||
}
|
||||
}
|
||||
result->data->data_cursor++;
|
||||
set->data_cursor += field_count;
|
||||
*fetched_anything = TRUE;
|
||||
/* buffered result sets don't have a connection */
|
||||
MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
|
||||
DBG_INF("row fetched");
|
||||
} else {
|
||||
result->data->data_cursor = NULL;
|
||||
set->data_cursor = NULL;
|
||||
*fetched_anything = FALSE;
|
||||
DBG_INF("no more data");
|
||||
}
|
||||
@ -612,7 +699,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
|
||||
DBG_INF("eof reached");
|
||||
DBG_RETURN(PASS);
|
||||
}
|
||||
if (result->conn->state != CONN_FETCHING_DATA) {
|
||||
if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) {
|
||||
SET_CLIENT_ERROR(result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
|
||||
UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
|
||||
DBG_ERR("command out of sync");
|
||||
@ -638,6 +725,12 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
|
||||
row_packet->fields = NULL;
|
||||
row_packet->row_buffer = NULL;
|
||||
|
||||
result->m.row_decoder(result->unbuf->last_row_buffer,
|
||||
result->unbuf->last_row_data,
|
||||
row_packet->field_count,
|
||||
row_packet->fields_metadata,
|
||||
result->conn TSRMLS_CC);
|
||||
|
||||
for (i = 0; i < field_count; i++) {
|
||||
if (stmt->result_bind[i].bound == TRUE) {
|
||||
zval *data = result->unbuf->last_row_data[i];
|
||||
@ -676,7 +769,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
|
||||
the bound variables. Thus we need to do part of what it does or Zend will
|
||||
report leaks.
|
||||
*/
|
||||
mnd_efree(row_packet->row_buffer);
|
||||
row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC);
|
||||
row_packet->row_buffer = NULL;
|
||||
}
|
||||
} else if (ret == FAIL) {
|
||||
@ -685,7 +778,7 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
|
||||
stmt->error_info = row_packet->error_info;
|
||||
}
|
||||
*fetched_anything = FALSE;
|
||||
result->conn->state = CONN_READY;
|
||||
CONN_SET_STATE(result->conn, CONN_READY);
|
||||
result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
|
||||
} else if (row_packet->eof) {
|
||||
DBG_INF("EOF");
|
||||
@ -698,9 +791,9 @@ mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int
|
||||
destroying the result object
|
||||
*/
|
||||
if (result->conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {
|
||||
result->conn->state = CONN_NEXT_RESULT_PENDING;
|
||||
CONN_SET_STATE(result->conn, CONN_NEXT_RESULT_PENDING);
|
||||
} else {
|
||||
result->conn->state = CONN_READY;
|
||||
CONN_SET_STATE(result->conn, CONN_READY);
|
||||
}
|
||||
*fetched_anything = FALSE;
|
||||
}
|
||||
@ -722,8 +815,8 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT *stmt TSRMLS_DC)
|
||||
DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
|
||||
|
||||
if (!stmt->field_count ||
|
||||
(!stmt->cursor_exists && conn->state != CONN_FETCHING_DATA) ||
|
||||
(stmt->cursor_exists && conn->state != CONN_READY) ||
|
||||
(!stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_FETCHING_DATA) ||
|
||||
(stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) ||
|
||||
(stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
|
||||
{
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
|
||||
@ -740,7 +833,6 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT *stmt TSRMLS_DC)
|
||||
result->m.use_result(stmt->result, TRUE TSRMLS_CC);
|
||||
result->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
|
||||
mysqlnd_stmt_fetch_row_unbuffered;
|
||||
|
||||
stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
|
||||
|
||||
DBG_INF_FMT("%p", result);
|
||||
@ -798,9 +890,17 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
|
||||
|
||||
result->unbuf->last_row_data = row_packet->fields;
|
||||
result->unbuf->last_row_buffer = row_packet->row_buffer;
|
||||
|
||||
|
||||
row_packet->fields = NULL;
|
||||
row_packet->row_buffer = NULL;
|
||||
if (!row_packet->skip_extraction) {
|
||||
result->m.row_decoder(result->unbuf->last_row_buffer,
|
||||
result->unbuf->last_row_data,
|
||||
row_packet->field_count,
|
||||
row_packet->fields_metadata,
|
||||
result->conn TSRMLS_CC);
|
||||
|
||||
/* If no result bind, do nothing. We consumed the data */
|
||||
for (i = 0; i < field_count; i++) {
|
||||
if (stmt->result_bind[i].bound == TRUE) {
|
||||
@ -833,7 +933,7 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, void *param, unsigned int fla
|
||||
/* We asked for one row, the next one should be EOF, eat it */
|
||||
ret = PACKET_READ(row_packet, result->conn);
|
||||
if (row_packet->row_buffer) {
|
||||
mnd_efree(row_packet->row_buffer);
|
||||
row_packet->row_buffer->free_chunk(row_packet->row_buffer, TRUE TSRMLS_CC);
|
||||
row_packet->row_buffer = NULL;
|
||||
}
|
||||
MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
|
||||
@ -961,7 +1061,7 @@ MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
/* Now the line should be free, if it wasn't */
|
||||
|
||||
int4store(cmd_buf, stmt->stmt_id);
|
||||
if (conn->state == CONN_READY &&
|
||||
if (CONN_GET_STATE(conn) == CONN_READY &&
|
||||
FAIL == (ret = mysqlnd_simple_command(conn, COM_STMT_RESET, (char *)cmd_buf,
|
||||
sizeof(cmd_buf), PROT_OK_PACKET,
|
||||
FALSE TSRMLS_CC))) {
|
||||
@ -1026,7 +1126,7 @@ MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const stmt, unsigned
|
||||
one by one to the wire.
|
||||
*/
|
||||
|
||||
if (conn->state == CONN_READY) {
|
||||
if (CONN_GET_STATE(conn) == CONN_READY) {
|
||||
stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
|
||||
cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
|
||||
|
||||
@ -1149,6 +1249,8 @@ MYSQLND_METHOD(mysqlnd_stmt, bind_param)(MYSQLND_STMT * const stmt,
|
||||
static enum_func_status
|
||||
MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
{
|
||||
unsigned int i = 0;
|
||||
|
||||
DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
|
||||
DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
|
||||
|
||||
@ -1332,13 +1434,15 @@ MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const stmt TSRMLS_D
|
||||
DBG_ENTER("mysqlnd_stmt::result_metadata");
|
||||
DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
|
||||
|
||||
if (!stmt->field_count || !stmt->conn || !stmt->result ||
|
||||
!stmt->result->meta)
|
||||
{
|
||||
if (!stmt->field_count || !stmt->conn || !stmt->result || !stmt->result->meta) {
|
||||
DBG_INF("NULL");
|
||||
DBG_RETURN(NULL);
|
||||
}
|
||||
|
||||
if (stmt->update_max_length && stmt->result->stored_data) {
|
||||
/* stored result, we have to update the max_length before we clone the meta data :( */
|
||||
mysqlnd_res_initialize_result_set_rest(stmt->result TSRMLS_CC);
|
||||
}
|
||||
/*
|
||||
TODO: This implementation is kind of a hack,
|
||||
find a better way to do it. In different functions I have put
|
||||
@ -1472,7 +1576,7 @@ MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
|
||||
stmt->state = MYSQLND_STMT_PREPARED;
|
||||
|
||||
/* Line is free! */
|
||||
stmt->conn->state = CONN_READY;
|
||||
CONN_SET_STATE(stmt->conn, CONN_READY);
|
||||
|
||||
DBG_RETURN(PASS);
|
||||
}
|
||||
@ -1622,7 +1726,7 @@ MYSQLND_METHOD(mysqlnd_stmt, close)(MYSQLND_STMT * const stmt, zend_bool implici
|
||||
STAT_FREE_RESULT_EXPLICIT);
|
||||
|
||||
int4store(cmd_buf, stmt->stmt_id);
|
||||
if (conn->state == CONN_READY &&
|
||||
if (CONN_GET_STATE(conn) == CONN_READY &&
|
||||
FAIL == mysqlnd_simple_command(conn, COM_STMT_CLOSE, (char *)cmd_buf, sizeof(cmd_buf),
|
||||
PROT_LAST /* COM_STMT_CLOSE doesn't send an OK packet*/,
|
||||
FALSE TSRMLS_CC)) {
|
||||
@ -1679,6 +1783,7 @@ struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = {
|
||||
MYSQLND_METHOD(mysqlnd_stmt, execute),
|
||||
MYSQLND_METHOD(mysqlnd_stmt, use_result),
|
||||
MYSQLND_METHOD(mysqlnd_stmt, store_result),
|
||||
MYSQLND_METHOD(mysqlnd_stmt, background_store_result),
|
||||
MYSQLND_METHOD(mysqlnd_stmt, get_result),
|
||||
MYSQLND_METHOD(mysqlnd_stmt, free_result),
|
||||
MYSQLND_METHOD(mysqlnd_stmt, data_seek),
|
||||
|
File diff suppressed because it is too large
Load Diff
@ -31,11 +31,14 @@ enum_func_status
|
||||
mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
|
||||
MYSQLND_RES_METADATA *meta,
|
||||
zend_bool binary_protocol,
|
||||
zend_bool update_max_length,
|
||||
zend_bool to_cache TSRMLS_DC);
|
||||
|
||||
enum_func_status mysqlnd_query_read_result_set_header(MYSQLND *conn, MYSQLND_STMT *stmt TSRMLS_DC);
|
||||
|
||||
void mysqlnd_res_initialize_result_set_rest(MYSQLND_RES * const result TSRMLS_DC);
|
||||
|
||||
|
||||
enum_func_status mysqlnd_background_store_result_fetch_data(MYSQLND_RES *result TSRMLS_DC);
|
||||
#endif /* MYSQLND_RESULT_H */
|
||||
|
||||
/*
|
||||
|
@ -421,8 +421,8 @@ MYSQLND_RES_METADATA *mysqlnd_result_meta_init(unsigned int field_count TSRMLS_D
|
||||
/* +1 is to have empty marker at the end */
|
||||
ret = mnd_ecalloc(1, sizeof(MYSQLND_RES_METADATA));
|
||||
ret->field_count = field_count;
|
||||
ret->fields = ecalloc(field_count + 1, sizeof(MYSQLND_FIELD));
|
||||
ret->zend_hash_keys = ecalloc(field_count, sizeof(struct mysqlnd_field_hash_key));
|
||||
ret->fields = mnd_ecalloc(field_count + 1, sizeof(MYSQLND_FIELD));
|
||||
ret->zend_hash_keys = mnd_ecalloc(field_count, sizeof(struct mysqlnd_field_hash_key));
|
||||
|
||||
ret->m = & mysqlnd_mysqlnd_res_meta_methods;
|
||||
DBG_INF_FMT("meta=%p", ret);
|
||||
|
@ -23,6 +23,39 @@
|
||||
#ifndef MYSQLND_STRUCTS_H
|
||||
#define MYSQLND_STRUCTS_H
|
||||
|
||||
typedef struct st_mysqlnd_memory_pool MYSQLND_MEMORY_POOL;
|
||||
typedef struct st_mysqlnd_memory_pool_chunk MYSQLND_MEMORY_POOL_CHUNK;
|
||||
typedef struct st_mysqlnd_memory_pool_chunk_llist MYSQLND_MEMORY_POOL_CHUNK_LLIST;
|
||||
|
||||
|
||||
#define MYSQLND_MEMORY_POOL_CHUNK_LIST_SIZE 100
|
||||
|
||||
struct st_mysqlnd_memory_pool
|
||||
{
|
||||
zend_uchar *arena;
|
||||
uint refcount;
|
||||
uint arena_size;
|
||||
uint free_size;
|
||||
|
||||
MYSQLND_MEMORY_POOL_CHUNK* free_chunk_list[MYSQLND_MEMORY_POOL_CHUNK_LIST_SIZE];
|
||||
uint free_chunk_list_elements;
|
||||
|
||||
MYSQLND_MEMORY_POOL_CHUNK* (*get_chunk)(MYSQLND_MEMORY_POOL * pool, uint size TSRMLS_DC);
|
||||
void (*free_contents)(MYSQLND_MEMORY_POOL * pool TSRMLS_DC);
|
||||
};
|
||||
|
||||
struct st_mysqlnd_memory_pool_chunk
|
||||
{
|
||||
uint64 app;
|
||||
MYSQLND_MEMORY_POOL *pool;
|
||||
zend_uchar *ptr;
|
||||
uint size;
|
||||
void (*resize_chunk)(MYSQLND_MEMORY_POOL_CHUNK * chunk, uint size TSRMLS_DC);
|
||||
void (*free_chunk)(MYSQLND_MEMORY_POOL_CHUNK * chunk, zend_bool cache_it TSRMLS_DC);
|
||||
zend_bool from_pool;
|
||||
};
|
||||
|
||||
|
||||
typedef struct st_mysqlnd_cmd_buffer
|
||||
{
|
||||
zend_uchar *buffer;
|
||||
@ -162,6 +195,7 @@ typedef struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND;
|
||||
|
||||
typedef struct st_mysqlnd_result_metadata MYSQLND_RES_METADATA;
|
||||
typedef struct st_mysqlnd_buffered_result MYSQLND_RES_BUFFERED;
|
||||
typedef struct st_mysqlnd_background_buffered_result MYSQLND_RES_BG_BUFFERED;
|
||||
typedef struct st_mysqlnd_unbuffered_result MYSQLND_RES_UNBUFFERED;
|
||||
|
||||
typedef struct st_mysqlnd_debug MYSQLND_DEBUG;
|
||||
@ -205,6 +239,7 @@ struct st_mysqlnd_conn_methods
|
||||
enum_func_status (*query)(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC);
|
||||
MYSQLND_RES * (*use_result)(MYSQLND * const conn TSRMLS_DC);
|
||||
MYSQLND_RES * (*store_result)(MYSQLND * const conn TSRMLS_DC);
|
||||
MYSQLND_RES * (*background_store_result)(MYSQLND * const conn TSRMLS_DC);
|
||||
enum_func_status (*next_result)(MYSQLND * const conn TSRMLS_DC);
|
||||
zend_bool (*more_results)(const MYSQLND * const conn);
|
||||
|
||||
@ -249,6 +284,8 @@ struct st_mysqlnd_conn_methods
|
||||
|
||||
MYSQLND * (*get_reference)(MYSQLND * const conn);
|
||||
enum_func_status (*free_reference)(MYSQLND * const conn TSRMLS_DC);
|
||||
enum mysqlnd_connection_state (*get_state)(MYSQLND * const conn TSRMLS_DC);
|
||||
void (*set_state)(MYSQLND * const conn, enum mysqlnd_connection_state new_state TSRMLS_DC);
|
||||
};
|
||||
|
||||
|
||||
@ -260,6 +297,7 @@ struct st_mysqlnd_res_methods
|
||||
|
||||
MYSQLND_RES * (*use_result)(MYSQLND_RES * const result, zend_bool ps_protocol TSRMLS_DC);
|
||||
MYSQLND_RES * (*store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps TSRMLS_DC);
|
||||
MYSQLND_RES * (*background_store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps TSRMLS_DC);
|
||||
void (*fetch_into)(MYSQLND_RES *result, unsigned int flags, zval *return_value, enum_mysqlnd_extension ext TSRMLS_DC ZEND_FILE_LINE_DC);
|
||||
MYSQLND_ROW_C (*fetch_row_c)(MYSQLND_RES *result TSRMLS_DC);
|
||||
void (*fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
|
||||
@ -271,7 +309,7 @@ struct st_mysqlnd_res_methods
|
||||
MYSQLND_FIELD_OFFSET (*seek_field)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET field_offset);
|
||||
MYSQLND_FIELD_OFFSET (*field_tell)(const MYSQLND_RES * const result);
|
||||
MYSQLND_FIELD * (*fetch_field)(MYSQLND_RES * const result TSRMLS_DC);
|
||||
MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC);
|
||||
MYSQLND_FIELD * (*fetch_field_direct)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET fieldnr TSRMLS_DC);
|
||||
|
||||
enum_func_status (*read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn TSRMLS_DC);
|
||||
unsigned long * (*fetch_lengths)(MYSQLND_RES * const result);
|
||||
@ -279,6 +317,9 @@ struct st_mysqlnd_res_methods
|
||||
enum_func_status (*free_result)(MYSQLND_RES * result, zend_bool implicit TSRMLS_DC);
|
||||
void (*free_result_internal)(MYSQLND_RES *result TSRMLS_DC);
|
||||
void (*free_result_contents)(MYSQLND_RES *result TSRMLS_DC);
|
||||
|
||||
/* for decoding - binary or text protocol */
|
||||
void (*row_decoder)(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields, uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
|
||||
};
|
||||
|
||||
|
||||
@ -299,6 +340,7 @@ struct st_mysqlnd_stmt_methods
|
||||
enum_func_status (*execute)(MYSQLND_STMT * const stmt TSRMLS_DC);
|
||||
MYSQLND_RES * (*use_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
|
||||
MYSQLND_RES * (*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
|
||||
MYSQLND_RES * (*background_store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
|
||||
MYSQLND_RES * (*get_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
|
||||
enum_func_status (*free_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
|
||||
enum_func_status (*seek_data)(const MYSQLND_STMT * const stmt, uint64 row TSRMLS_DC);
|
||||
@ -405,6 +447,20 @@ struct st_mysqlnd_connection
|
||||
/* stats */
|
||||
MYSQLND_STATS stats;
|
||||
|
||||
#ifdef ZTS
|
||||
MUTEX_T LOCK_state;
|
||||
|
||||
pthread_cond_t COND_work_done;
|
||||
|
||||
pthread_mutex_t LOCK_work;
|
||||
pthread_cond_t COND_work;
|
||||
pthread_cond_t COND_thread_ended;
|
||||
zend_bool thread_is_running;
|
||||
zend_bool thread_killed;
|
||||
void *** tsrm_ls;
|
||||
#endif
|
||||
|
||||
|
||||
struct st_mysqlnd_conn_methods *m;
|
||||
};
|
||||
|
||||
@ -436,18 +492,43 @@ struct st_mysqlnd_result_metadata
|
||||
};
|
||||
|
||||
|
||||
struct st_mysqlnd_buffered_result
|
||||
struct st_mysqlnd_background_buffered_result
|
||||
{
|
||||
zval ***data;
|
||||
uint64 data_size;
|
||||
zval ***data_cursor;
|
||||
zend_uchar **row_buffers;
|
||||
MYSQLND_MEMORY_POOL_CHUNK **row_buffers;
|
||||
uint64 row_count;
|
||||
uint64 initialized_rows;
|
||||
zend_bool persistent;
|
||||
|
||||
MYSQLND_QCACHE *qcache;
|
||||
unsigned int references;
|
||||
|
||||
zend_bool decode_in_foreground;
|
||||
|
||||
#ifdef ZTS
|
||||
zend_bool bg_fetch_finished;
|
||||
MUTEX_T LOCK;
|
||||
#endif
|
||||
|
||||
mysqlnd_error_info error_info;
|
||||
mysqlnd_upsert_status upsert_status;
|
||||
};
|
||||
|
||||
|
||||
struct st_mysqlnd_buffered_result
|
||||
{
|
||||
zval **data;
|
||||
zval **data_cursor;
|
||||
MYSQLND_MEMORY_POOL_CHUNK **row_buffers;
|
||||
uint64 row_count;
|
||||
uint64 initialized_rows;
|
||||
zend_bool persistent;
|
||||
|
||||
MYSQLND_QCACHE *qcache;
|
||||
unsigned int references;
|
||||
|
||||
zend_bool async_invalid;
|
||||
mysqlnd_error_info error_info;
|
||||
};
|
||||
|
||||
@ -456,7 +537,7 @@ struct st_mysqlnd_unbuffered_result
|
||||
{
|
||||
/* For unbuffered (both normal and PS) */
|
||||
zval **last_row_data;
|
||||
zend_uchar *last_row_buffer;
|
||||
MYSQLND_MEMORY_POOL_CHUNK *last_row_buffer;
|
||||
|
||||
uint64 row_count;
|
||||
zend_bool eof_reached;
|
||||
@ -475,9 +556,9 @@ struct st_mysqlnd_res
|
||||
MYSQLND_RES_METADATA *meta;
|
||||
|
||||
/* To be used with store_result() - both normal and PS */
|
||||
MYSQLND_RES_BUFFERED *data;
|
||||
|
||||
MYSQLND_RES_UNBUFFERED *unbuf;
|
||||
MYSQLND_RES_BUFFERED *stored_data;
|
||||
MYSQLND_RES_BG_BUFFERED *bg_stored_data;
|
||||
MYSQLND_RES_UNBUFFERED *unbuf;
|
||||
|
||||
/*
|
||||
Column lengths of current row - both buffered and unbuffered.
|
||||
|
@ -43,12 +43,11 @@
|
||||
#define MYSQLND_DUMP_HEADER_N_BODY2
|
||||
#define MYSQLND_DUMP_HEADER_N_BODY_FULL2
|
||||
|
||||
#define MYSQLND_MAX_PACKET_SIZE (256L*256L*256L-1)
|
||||
|
||||
#define PACKET_READ_HEADER_AND_BODY(packet, conn, buf, buf_size, packet_type) \
|
||||
{ \
|
||||
if (FAIL == mysqlnd_read_header((conn), &((packet)->header) TSRMLS_CC)) {\
|
||||
conn->state = CONN_QUIT_SENT; \
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT); \
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
|
||||
DBG_ERR_FMT("Can't read %s's header", (packet_type)); \
|
||||
@ -60,7 +59,7 @@
|
||||
}\
|
||||
if (!mysqlnd_read_body((conn), (buf), \
|
||||
MIN((buf_size), (packet)->header.size) TSRMLS_CC)) { \
|
||||
conn->state = CONN_QUIT_SENT; \
|
||||
CONN_SET_STATE(conn, CONN_QUIT_SENT); \
|
||||
SET_CLIENT_ERROR(conn->error_info, CR_SERVER_GONE_ERROR, UNKNOWN_SQLSTATE, mysqlnd_server_gone);\
|
||||
php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", mysqlnd_server_gone); \
|
||||
DBG_ERR_FMT("Empty %s packet body", (packet_type)); \
|
||||
@ -490,7 +489,7 @@ size_t mysqlnd_read_body(MYSQLND *conn, zend_uchar *buf, size_t size TSRMLS_DC)
|
||||
net->stream->chunk_size = MIN(size, conn->options.net_read_buffer_size);
|
||||
do {
|
||||
size -= (ret = php_stream_read(net->stream, p, size));
|
||||
if (size || iter++) {
|
||||
if (size > 0 || iter++) {
|
||||
DBG_INF_FMT("read=%d buf=%p p=%p chunk_size=%d left=%d",
|
||||
ret, buf, p , net->stream->chunk_size, size);
|
||||
}
|
||||
@ -1234,13 +1233,13 @@ 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, zend_uchar **buf, int buf_size,
|
||||
size_t *data_size, zend_bool persistent_alloc,
|
||||
php_mysqlnd_read_row_ex(MYSQLND *conn, MYSQLND_MEMORY_POOL_CHUNK **buffer,
|
||||
uint64 *data_size, zend_bool persistent_alloc,
|
||||
unsigned int prealloc_more_bytes TSRMLS_DC)
|
||||
{
|
||||
enum_func_status ret = PASS;
|
||||
mysqlnd_packet_header header;
|
||||
zend_uchar *new_buf = NULL, *p = *buf;
|
||||
zend_uchar *p = NULL;
|
||||
zend_bool first_iteration = TRUE;
|
||||
|
||||
DBG_ENTER("php_mysqlnd_read_row_ex");
|
||||
@ -1262,13 +1261,14 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size,
|
||||
|
||||
*data_size += header.size;
|
||||
|
||||
if (first_iteration && header.size > buf_size) {
|
||||
if (first_iteration) {
|
||||
first_iteration = FALSE;
|
||||
/*
|
||||
We need a trailing \0 for the last string, in case of text-mode,
|
||||
to be able to implement read-only variables. Thus, we add + 1.
|
||||
*/
|
||||
p = new_buf = mnd_pemalloc(*data_size + 1, persistent_alloc);
|
||||
*buffer = mysqlnd_memory_pool.get_chunk(&mysqlnd_memory_pool, *data_size + 1 TSRMLS_CC);
|
||||
p = (*buffer)->ptr;
|
||||
} else if (!first_iteration) {
|
||||
/* Empty packet after MYSQLND_MAX_PACKET_SIZE packet. That's ok, break */
|
||||
if (!header.size) {
|
||||
@ -1281,9 +1281,9 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size,
|
||||
We need a trailing \0 for the last string, in case of text-mode,
|
||||
to be able to implement read-only variables.
|
||||
*/
|
||||
new_buf = mnd_perealloc(new_buf, *data_size + 1, persistent_alloc);
|
||||
(*buffer)->resize_chunk((*buffer), *data_size + 1 TSRMLS_CC);
|
||||
/* The position could have changed, recalculate */
|
||||
p = new_buf + (*data_size - header.size);
|
||||
p = (*buffer)->ptr + (*data_size - header.size);
|
||||
}
|
||||
|
||||
if (!mysqlnd_read_body(conn, p, header.size TSRMLS_CC)) {
|
||||
@ -1297,8 +1297,9 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size,
|
||||
break;
|
||||
}
|
||||
}
|
||||
if (ret == PASS && new_buf) {
|
||||
*buf = new_buf;
|
||||
if (ret == FAIL) {
|
||||
(*buffer)->free_chunk((*buffer), TRUE TSRMLS_CC);
|
||||
*buffer = NULL;
|
||||
}
|
||||
*data_size -= prealloc_more_bytes;
|
||||
DBG_RETURN(ret);
|
||||
@ -1306,11 +1307,11 @@ php_mysqlnd_read_row_ex(MYSQLND *conn, zend_uchar **buf, int buf_size,
|
||||
|
||||
|
||||
/* {{{ php_mysqlnd_rowp_read_binary_protocol */
|
||||
static
|
||||
void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND *conn,
|
||||
zend_uchar *p, size_t data_size TSRMLS_DC)
|
||||
void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
|
||||
uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC)
|
||||
{
|
||||
unsigned int i;
|
||||
int i;
|
||||
zend_uchar *p = row_buffer->ptr;
|
||||
zend_uchar *null_ptr, bit;
|
||||
zval **current_field, **end_field, **start_field;
|
||||
zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode;
|
||||
@ -1319,14 +1320,14 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND
|
||||
|
||||
DBG_ENTER("php_mysqlnd_rowp_read_binary_protocol");
|
||||
|
||||
end_field = (current_field = start_field = packet->fields) + packet->field_count;
|
||||
end_field = (current_field = start_field = fields) + field_count;
|
||||
|
||||
|
||||
/* skip the first byte, not 0xFE -> 0x0, status */
|
||||
p++;
|
||||
null_ptr= p;
|
||||
p += (packet->field_count + 9)/8; /* skip null bits */
|
||||
bit = 4; /* first 2 bits are reserved */
|
||||
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++) {
|
||||
#if 1
|
||||
@ -1344,8 +1345,8 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND
|
||||
if (*null_ptr & bit) {
|
||||
ZVAL_NULL(*current_field);
|
||||
} else {
|
||||
enum_mysqlnd_field_types type = packet->fields_metadata[i].type;
|
||||
mysqlnd_ps_fetch_functions[type].func(*current_field, &packet->fields_metadata[i],
|
||||
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 (!((bit<<=1) & 255)) {
|
||||
@ -1353,8 +1354,6 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND
|
||||
null_ptr++;
|
||||
}
|
||||
}
|
||||
/* Normal queries: The buffer has one more byte at the end, because we need it */
|
||||
packet->row_buffer[data_size] = '\0';
|
||||
|
||||
DBG_VOID_RETURN;
|
||||
}
|
||||
@ -1362,14 +1361,15 @@ void php_mysqlnd_rowp_read_binary_protocol(php_mysql_packet_row *packet, MYSQLND
|
||||
|
||||
|
||||
/* {{{ php_mysqlnd_rowp_read_text_protocol */
|
||||
static
|
||||
void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *conn,
|
||||
zend_uchar *p, size_t data_size TSRMLS_DC)
|
||||
void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
|
||||
uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC)
|
||||
{
|
||||
unsigned int i;
|
||||
zend_bool last_field_was_string;
|
||||
int i;
|
||||
zend_bool last_field_was_string = FALSE;
|
||||
zval **current_field, **end_field, **start_field;
|
||||
zend_uchar *bit_area = packet->row_buffer + data_size + 1; /* we allocate from here */
|
||||
zend_uchar *p = row_buffer->ptr;
|
||||
size_t data_size = row_buffer->app;
|
||||
zend_uchar *bit_area = (zend_uchar*) row_buffer->ptr + data_size + 1; /* we allocate from here */
|
||||
zend_bool as_unicode = conn->options.numeric_and_datetime_as_unicode;
|
||||
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
|
||||
zend_bool as_int = conn->options.int_and_year_as_int;
|
||||
@ -1377,7 +1377,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *
|
||||
|
||||
DBG_ENTER("php_mysqlnd_rowp_read_text_protocol");
|
||||
|
||||
end_field = (current_field = start_field = packet->fields) + packet->field_count;
|
||||
end_field = (current_field = start_field = fields) + field_count;
|
||||
for (i = 0; current_field < end_field; current_field++, i++) {
|
||||
/* Don't reverse the order. It is significant!*/
|
||||
void *obj;
|
||||
@ -1418,7 +1418,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *
|
||||
} else {
|
||||
#if PHP_MAJOR_VERSION >= 6 || defined(MYSQLND_STRING_TO_INT_CONVERSION)
|
||||
struct st_mysqlnd_perm_bind perm_bind =
|
||||
mysqlnd_ps_fetch_functions[packet->fields_metadata[i].type];
|
||||
mysqlnd_ps_fetch_functions[fields_metadata[i].type];
|
||||
#endif
|
||||
|
||||
#ifdef MYSQLND_STRING_TO_INT_CONVERSION
|
||||
@ -1453,7 +1453,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *
|
||||
*(p + len) = save;
|
||||
} else
|
||||
#endif
|
||||
if (packet->fields_metadata[i].type == MYSQL_TYPE_BIT) {
|
||||
if (fields_metadata[i].type == MYSQL_TYPE_BIT) {
|
||||
/*
|
||||
BIT fields are specially handled. As they come as bit mask, we have
|
||||
to convert it to human-readable representation. As the bits take
|
||||
@ -1464,7 +1464,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *
|
||||
Definitely not nice, _hackish_ :(, but works.
|
||||
*/
|
||||
zend_uchar *start = bit_area;
|
||||
ps_fetch_from_1_to_8_bytes(*current_field, &(packet->fields_metadata[i]),
|
||||
ps_fetch_from_1_to_8_bytes(*current_field, &(fields_metadata[i]),
|
||||
0, &p, as_unicode, len TSRMLS_CC);
|
||||
/*
|
||||
We have advanced in ps_fetch_from_1_to_8_bytes. We should go back because
|
||||
@ -1532,7 +1532,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *
|
||||
which will make with this `if` an `else if`.
|
||||
*/
|
||||
if ((perm_bind.is_possibly_blob == TRUE &&
|
||||
packet->fields_metadata[i].charsetnr == MYSQLND_BINARY_CHARSET_NR) ||
|
||||
fields_metadata[i].charsetnr == MYSQLND_BINARY_CHARSET_NR) ||
|
||||
(!as_unicode && perm_bind.can_ret_as_str_in_uni == TRUE))
|
||||
{
|
||||
/* BLOB - no conversion please */
|
||||
@ -1561,7 +1561,7 @@ void php_mysqlnd_rowp_read_text_protocol(php_mysql_packet_row *packet, MYSQLND *
|
||||
}
|
||||
if (last_field_was_string) {
|
||||
/* Normal queries: The buffer has one more byte at the end, because we need it */
|
||||
packet->row_buffer[data_size] = '\0';
|
||||
row_buffer->ptr[data_size] = '\0';
|
||||
}
|
||||
|
||||
DBG_VOID_RETURN;
|
||||
@ -1580,10 +1580,10 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC)
|
||||
MYSQLND_NET *net = &conn->net;
|
||||
zend_uchar *p;
|
||||
enum_func_status ret = PASS;
|
||||
size_t data_size = 0;
|
||||
size_t old_chunk_size = net->stream->chunk_size;
|
||||
php_mysql_packet_row *packet= (php_mysql_packet_row *) _packet;
|
||||
size_t post_alloc_for_bit_fields = 0;
|
||||
uint64 data_size = 0;
|
||||
|
||||
DBG_ENTER("php_mysqlnd_rowp_read");
|
||||
|
||||
@ -1593,17 +1593,18 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC)
|
||||
packet->bit_fields_total_len + packet->bit_fields_count;
|
||||
}
|
||||
|
||||
ret = php_mysqlnd_read_row_ex(conn, &packet->row_buffer, 0, &data_size,
|
||||
ret = php_mysqlnd_read_row_ex(conn, &packet->row_buffer, &data_size,
|
||||
packet->persistent_alloc, post_alloc_for_bit_fields
|
||||
TSRMLS_CC);
|
||||
if (FAIL == ret) {
|
||||
goto end;
|
||||
}
|
||||
|
||||
/* packet->row_buffer is of size 'data_size + 1' */
|
||||
/* packet->row_buffer->ptr is of size 'data_size + 1' */
|
||||
packet->header.size = data_size;
|
||||
packet->row_buffer->app = data_size;
|
||||
|
||||
if ((*(p = packet->row_buffer)) == 0xFF) {
|
||||
if ((*(p = packet->row_buffer->ptr)) == 0xFF) {
|
||||
/*
|
||||
Error message as part of the result set,
|
||||
not good but we should not hang. See:
|
||||
@ -1646,14 +1647,8 @@ php_mysqlnd_rowp_read(void *_packet, MYSQLND *conn TSRMLS_DC)
|
||||
but mostly like old-API unbuffered and thus will populate this array with
|
||||
value.
|
||||
*/
|
||||
packet->fields = (zval **) mnd_pemalloc(packet->field_count * sizeof(zval *),
|
||||
packet->persistent_alloc);
|
||||
}
|
||||
|
||||
if (packet->binary_protocol) {
|
||||
php_mysqlnd_rowp_read_binary_protocol(packet, conn, p, data_size TSRMLS_CC);
|
||||
} else {
|
||||
php_mysqlnd_rowp_read_text_protocol(packet, conn, p, data_size TSRMLS_CC);
|
||||
packet->fields = (zval **) mnd_pecalloc(packet->field_count, sizeof(zval *),
|
||||
packet->persistent_alloc);
|
||||
}
|
||||
} else {
|
||||
MYSQLND_INC_CONN_STATISTIC(&conn->stats,
|
||||
@ -1675,7 +1670,7 @@ void php_mysqlnd_rowp_free_mem(void *_packet, zend_bool alloca TSRMLS_DC)
|
||||
{
|
||||
php_mysql_packet_row *p= (php_mysql_packet_row *) _packet;
|
||||
if (p->row_buffer) {
|
||||
mnd_pefree(p->row_buffer, p->persistent_alloc);
|
||||
p->row_buffer->free_chunk(p->row_buffer, TRUE TSRMLS_CC);
|
||||
p->row_buffer = NULL;
|
||||
}
|
||||
/*
|
||||
|
@ -258,7 +258,7 @@ struct st_php_mysql_packet_row {
|
||||
mysqlnd_2b warning_count;
|
||||
mysqlnd_2b server_status;
|
||||
|
||||
zend_uchar *row_buffer;
|
||||
struct st_mysqlnd_memory_pool_chunk *row_buffer;
|
||||
|
||||
zend_bool skip_extraction;
|
||||
zend_bool binary_protocol;
|
||||
@ -323,6 +323,13 @@ zend_uchar * php_mysqlnd_net_store_length(zend_uchar *packet, uint64 length);
|
||||
|
||||
extern char * const mysqlnd_empty_string;
|
||||
|
||||
|
||||
void php_mysqlnd_rowp_read_binary_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
|
||||
uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
|
||||
|
||||
void php_mysqlnd_rowp_read_text_protocol(MYSQLND_MEMORY_POOL_CHUNK * row_buffer, zval ** fields,
|
||||
uint field_count, MYSQLND_FIELD *fields_metadata, MYSQLND *conn TSRMLS_DC);
|
||||
|
||||
#endif /* MYSQLND_WIREPROTOCOL_H */
|
||||
|
||||
/*
|
||||
|
Loading…
Reference in New Issue
Block a user