Author: ahristov
Date: 2007-05-09 12:09:41 +0200 (Wed, 09 May 2007)
New Revision: 364
Modified:
branches/qcache/mysqlnd/mysqlnd.c
branches/qcache/mysqlnd/mysqlnd.h
branches/qcache/mysqlnd/mysqlnd_charset.c
branches/qcache/mysqlnd/mysqlnd_charset.h
branches/qcache/mysqlnd/mysqlnd_palloc.c
branches/qcache/mysqlnd/mysqlnd_ps.c
Log:
Merge from trunk
Modified: branches/qcache/mysqlnd/mysqlnd.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd.c 2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd.c 2007-05-09 10:09:41 UTC (rev 364)
@@ -24,6 +24,7 @@
#include "mysqlnd_wireprotocol.h"
#include "mysqlnd_priv.h"
#include "mysqlnd_statistics.h"
+#include "mysqlnd_charset.h"
#include "ext/standard/basic_functions.h"
#define MYSQLND_SILENT
@@ -120,26 +121,26 @@
}
if (unbuf->last_row_data) {
- int i;
+ unsigned int i, ctor_called_count = 0;
zend_bool copy_ctor_called;
+ MYSQLND_STATS *global_stats = result->conn? &result->conn->stats:NULL;
for (i = 0; i < result->field_count; i++) {
- if (result->type == MYSQLND_RES_PS) {
- /* Do nothing, before assigning we will clean */
- zval_ptr_dtor(&unbuf->last_row_data[i]);
- } else {
- mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]),
- result->zval_cache, FALSE,
- ©_ctor_called TSRMLS_CC);
- if (copy_ctor_called) {
- MYSQLND_INC_CONN_STATISTIC(&result->conn->stats,
- STAT_COPY_ON_WRITE_PERFORMED);
- /* Increase global stats */
- } else {
- MYSQLND_INC_CONN_STATISTIC(&result->conn->stats,
- STAT_COPY_ON_WRITE_SAVED);
- }
+ mysqlnd_palloc_zval_ptr_dtor(&(unbuf->last_row_data[i]),
+ result->zval_cache,
+ result->type == MYSQLND_RES_PS,
+ ©_ctor_called TSRMLS_CC);
+ if (copy_ctor_called) {
+ 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,
+ 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);
+
/* Free last row's zvals */
efree(unbuf->last_row_data);
unbuf->last_row_data = NULL;
@@ -1616,13 +1617,102 @@
#define STORE_RESULT_PREALLOCATED_SET 32
+static enum_func_status
+_mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES_BUFFERED *set,
+ MYSQLND_RES_METADATA *meta TSRMLS_DC)
+{
+ enum_func_status ret;
+ php_mysql_packet_row row_packet;
+ unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET, free_rows;
+
+ free_rows = next_extend;
+
+ PACKET_INIT_ALLOCA(row_packet, PROT_ROW_PACKET);
+ row_packet.field_count = meta->field_count;
+ row_packet.binary_protocol = FALSE;
+ row_packet.fields_metadata = meta->fields;
+ /* Let the row packet fill our buffer and skip additional malloc + memcpy */
+ while (FAIL != (ret = PACKET_READ_ALLOCA(row_packet, conn)) && !row_packet.eof)
{
+ int i;
+ zval **current_row;
+
+ if (!free_rows) {
+ unsigned long total_rows = free_rows = next_extend = next_extend * 5 / 3; /* extend
with 33% */
+ total_rows += set->row_count;
+ set->data = perealloc(set->data,
+ total_rows * sizeof(zval **), set->persistent);
+
+ set->row_buffers = perealloc(set->row_buffers,
+ total_rows * sizeof(zend_uchar *), set->persistent);
+ }
+ free_rows--;
+ current_row = set->data[set->row_count] = row_packet.fields;
+ set->row_buffers[set->row_count] = row_packet.row_buffer;
+ set->row_count++;
+
+ /* So row_packet's destructor function won't efree() it */
+ row_packet.fields = NULL;
+ row_packet.row_buffer = NULL;
+
+ for (i = 0; i < row_packet.field_count; i++) {
+ unsigned long len;
+ /*
+ 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_NULL &&
+ (len = Z_STRLEN_P(current_row[i])) &&
+ meta->fields[i].max_length < len)
+ {
+ meta->fields[i].max_length = len;
+ }
+ }
+ /*
+ No need to FREE_ALLOCA as we can reuse the
+ 'lengths' and 'fields' arrays. For lengths its absolutely safe.
+ 'fields' is reused because the ownership of the strings has been
+ transfered above.
+ */
+ }
+ MYSQLND_INC_CONN_STATISTIC_W_VALUE(&conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT,
+ set->row_count);
+
+ /* Finally clean */
+ if (row_packet.eof) {
+ conn->upsert_status.warning_count = row_packet.warning_count;
+ conn->upsert_status.server_status = row_packet.server_status;
+ }
+ /* save some memory */
+ if (free_rows) {
+ set->data = perealloc(set->data,
+ set->row_count * sizeof(zval **),
+ set->persistent);
+ set->row_buffers = perealloc(set->row_buffers,
+ set->row_count * sizeof(zend_uchar *),
+ set->persistent);
+ }
+
+ if (conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {
+ conn->state = CONN_NEXT_RESULT_PENDING;
+ } else {
+ conn->state = CONN_READY;
+ }
+
+ if (ret == FAIL) {
+ set->error_info = row_packet.error_info;
+ }
+ PACKET_FREE_ALLOCA(row_packet);
+
+ return ret;
+}
+
+
/* {{{ mysqlnd_store_result */
static
MYSQLND_RES *_mysqlnd_store_result(MYSQLND * const conn, zend_bool to_cache TSRMLS_DC)
{
enum_func_status ret;
- unsigned int next_extend = STORE_RESULT_PREALLOCATED_SET, free_rows;
- php_mysql_packet_row row_packet;
MYSQLND_RES *result;
if (!conn->current_result) {
@@ -1656,8 +1746,8 @@
/* Create room for 'next_extend' rows */
result->data = pecalloc(1, sizeof(MYSQLND_RES_BUFFERED), to_cache);
- result->data->data = pemalloc(next_extend * sizeof(zval **), to_cache);
- result->data->row_buffers = pemalloc(next_extend * sizeof(zend_uchar *),
to_cache);
+ result->data->data = pemalloc(STORE_RESULT_PREALLOCATED_SET * sizeof(zval **),
to_cache);
+ result->data->row_buffers = pemalloc(STORE_RESULT_PREALLOCATED_SET *
sizeof(zend_uchar *), to_cache);
result->data->references = 1;
result->data->persistent = to_cache;
if (to_cache) {
@@ -1667,7 +1757,20 @@
result->conn_hash_key_len = conn->hash_key_len;
}
-
+ ret = _mysqlnd_store_result_fetch_data(conn, result->data, result->meta
TSRMLS_CC);
+ if (PASS == ret) {
+ /* Position at the first row */
+ result->data->data_cursor = result->data->data;
+ /* libmysql's documentation says it should be so for SELECT statements */
+ conn->upsert_status.affected_rows = result->data->row_count;
+ } else {
+ conn->error_info = result->data->error_info;
+ mysqlnd_internal_free_result(result TSRMLS_CC);
+ result = NULL;
+ }
+ return result;
+
+#if 0
free_rows = next_extend;
PACKET_INIT_ALLOCA(row_packet, PROT_ROW_PACKET);
@@ -1762,6 +1865,7 @@
PACKET_FREE_ALLOCA(row_packet);
return result;
+#endif
}
/* }}} */
@@ -1861,49 +1965,7 @@
static
ulong _mysqlnd_real_escape_quotes(const MYSQLND * const conn, char *newstr, const char
*escapestr, int escapestr_len)
{
- const char *newstr_s = newstr;
- const char *newstr_e = newstr + 2 * escapestr_len;
- const char *end = escapestr + escapestr_len;
- zend_bool escape_overflow = FALSE;
-
- for (;escapestr < end; escapestr++) {
- /* check unicode characters */
- if (conn->charset->char_maxlen > 1 &&
conn->charset->mb_charlen(*escapestr) > 1) {
- uint len = conn->charset->mb_valid(escapestr, end);
-
- /* check possible overflow */
- if ((newstr + len) > newstr_e) {
- escape_overflow = TRUE;
- break;
- }
- /* copy mb char without escaping it */
- while (len--) {
- *newstr++ = *escapestr++;
- }
- escapestr--;
- continue;
- }
- if (*newstr == '\'') {
- if (newstr + 2 > newstr_e) {
- escape_overflow = TRUE;
- break;
- }
- *newstr++ = '\'';
- *newstr++ = '\'';
- } else {
- if (newstr + 1 > newstr_e) {
- escape_overflow = TRUE;
- break;
- }
- *newstr++= *escapestr;
- }
- }
- *newstr = '\0';
-
- if (escape_overflow) {
- return (ulong)~0;
- }
- return (ulong)(newstr - newstr_s);
+ return mysqlnd_cset_escape_quotes(conn->charset, newstr, escapestr, escapestr_len);
}
/* }}} */
@@ -1912,76 +1974,7 @@
static
ulong _mysqlnd_real_escape_slashes(const MYSQLND * const conn, char *newstr, const char
*escapestr, int escapestr_len)
{
- const char *newstr_s = newstr;
- const char *newstr_e = newstr + 2 * escapestr_len;
- const char *end = escapestr + escapestr_len;
- zend_bool escape_overflow = FALSE;
-
- for (;escapestr < end; escapestr++) {
- char esc = '\0';
-
- /* check unicode characters */
- if (conn->charset->char_maxlen > 1 &&
conn->charset->mb_charlen(*escapestr) > 1) {
- uint len = conn->charset->mb_valid(escapestr, end);
-
- /* check possible overflow */
- if ((newstr + len) > newstr_e) {
- escape_overflow = TRUE;
- break;
- }
- /* copy mb char without escaping it */
- while (len--) {
- *newstr++ = *escapestr++;
- }
- escapestr--;
- continue;
- }
- if (conn->charset->char_maxlen > 1 &&
conn->charset->mb_charlen(*escapestr) > 1) {
- esc = *escapestr;
- } else {
- switch (*escapestr) {
- case 0:
- esc = '0';
- break;
- case '\n':
- esc = 'n';
- break;
- case '\r':
- esc = 'r';
- break;
- case '\\':
- case '\'':
- case '"':
- esc = *escapestr;
- break;
- case '\032':
- esc = 'Z';
- break;
- }
- }
- if (esc) {
- if (newstr + 2 > newstr_e) {
- escape_overflow = TRUE;
- break;
- }
- /* copy escaped character */
- *newstr++ = '\\';
- *newstr++ = esc;
- } else {
- if (newstr + 1 > newstr_e) {
- escape_overflow = TRUE;
- break;
- }
- /* copy non escaped character */
- *newstr++ = *escapestr;
- }
- }
- *newstr = '\0';
-
- if (escape_overflow) {
- return (ulong)~0;
- }
- return (ulong)(newstr - newstr_s);
+ return mysqlnd_cset_escape_slashes(conn->charset, newstr, escapestr, escapestr_len);
}
/* }}} */
Modified: branches/qcache/mysqlnd/mysqlnd.h
===================================================================
--- branches/qcache/mysqlnd/mysqlnd.h 2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd.h 2007-05-09 10:09:41 UTC (rev 364)
@@ -742,6 +742,9 @@
/* qcache */
MYSQLND_QCACHE *qcache;
unsigned int references;
+
+ zend_bool async_invalid;
+ mysqlnd_error_info error_info;
};
Modified: branches/qcache/mysqlnd/mysqlnd_charset.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_charset.c 2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_charset.c 2007-05-09 10:09:41 UTC (rev 364)
@@ -465,3 +465,130 @@
return NULL;
}
/* }}} */
+
+
+/* {{{ mysqlnd_cset_escape_quotes */
+ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char *newstr,
const char *escapestr, int escapestr_len)
+{
+ const char *newstr_s = newstr;
+ const char *newstr_e = newstr + 2 * escapestr_len;
+ const char *end = escapestr + escapestr_len;
+ zend_bool escape_overflow = FALSE;
+
+ for (;escapestr < end; escapestr++) {
+ /* check unicode characters */
+ if (charset->char_maxlen > 1 && charset->mb_charlen(*escapestr) >
1) {
+ uint len = charset->mb_valid(escapestr, end);
+
+ /* check possible overflow */
+ if ((newstr + len) > newstr_e) {
+ escape_overflow = TRUE;
+ break;
+ }
+ /* copy mb char without escaping it */
+ while (len--) {
+ *newstr++ = *escapestr++;
+ }
+ escapestr--;
+ continue;
+ }
+ if (*newstr == '\'') {
+ if (newstr + 2 > newstr_e) {
+ escape_overflow = TRUE;
+ break;
+ }
+ *newstr++ = '\'';
+ *newstr++ = '\'';
+ } else {
+ if (newstr + 1 > newstr_e) {
+ escape_overflow = TRUE;
+ break;
+ }
+ *newstr++= *escapestr;
+ }
+ }
+ *newstr = '\0';
+
+ if (escape_overflow) {
+ return (ulong)~0;
+ }
+ return (ulong)(newstr - newstr_s);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_cset_escape_slashes */
+ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr, const
char *escapestr, int escapestr_len)
+{
+ const char *newstr_s = newstr;
+ const char *newstr_e = newstr + 2 * escapestr_len;
+ const char *end = escapestr + escapestr_len;
+ zend_bool escape_overflow = FALSE;
+
+ for (;escapestr < end; escapestr++) {
+ char esc = '\0';
+
+ /* check unicode characters */
+ if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
+ uint len = cset->mb_valid(escapestr, end);
+
+ /* check possible overflow */
+ if ((newstr + len) > newstr_e) {
+ escape_overflow = TRUE;
+ break;
+ }
+ /* copy mb char without escaping it */
+ while (len--) {
+ *newstr++ = *escapestr++;
+ }
+ escapestr--;
+ continue;
+ }
+ if (cset->char_maxlen > 1 && cset->mb_charlen(*escapestr) > 1) {
+ esc = *escapestr;
+ } else {
+ switch (*escapestr) {
+ case 0:
+ esc = '0';
+ break;
+ case '\n':
+ esc = 'n';
+ break;
+ case '\r':
+ esc = 'r';
+ break;
+ case '\\':
+ case '\'':
+ case '"':
+ esc = *escapestr;
+ break;
+ case '\032':
+ esc = 'Z';
+ break;
+ }
+ }
+ if (esc) {
+ if (newstr + 2 > newstr_e) {
+ escape_overflow = TRUE;
+ break;
+ }
+ /* copy escaped character */
+ *newstr++ = '\\';
+ *newstr++ = esc;
+ } else {
+ if (newstr + 1 > newstr_e) {
+ escape_overflow = TRUE;
+ break;
+ }
+ /* copy non escaped character */
+ *newstr++ = *escapestr;
+ }
+ }
+ *newstr = '\0';
+
+ if (escape_overflow) {
+ return (ulong)~0;
+ }
+ return (ulong)(newstr - newstr_s);
+}
+/* }}} */
Modified: branches/qcache/mysqlnd/mysqlnd_charset.h
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_charset.h 2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_charset.h 2007-05-09 10:09:41 UTC (rev 364)
@@ -20,3 +20,5 @@
#include "php.h"
#include "php_globals.h"
+ulong mysqlnd_cset_escape_quotes(const MYSQLND_CHARSET * const charset, char *newstr,
const char *escapestr, int escapestr_len);
+ulong mysqlnd_cset_escape_slashes(const MYSQLND_CHARSET * const cset, char *newstr, const
char *escapestr, int escapestr_len);
Modified: branches/qcache/mysqlnd/mysqlnd_palloc.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_palloc.c 2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_palloc.c 2007-05-09 10:09:41 UTC (rev 364)
@@ -291,7 +291,8 @@
#ifndef MYSQLND_SILENT
php_printf("[mysqlnd_palloc_get_zval %p] *last_added=%p free_items=%d\n",
- cache, cache? cache->free_list.last_added:NULL, cache->free_items);
+ thd_cache, thd_cache? thd_cache->parent->free_list.last_added:NULL,
+ thd_cache->parent->free_items);
#endif
if (thd_cache) {
@@ -338,7 +339,11 @@
{
MYSQLND_ZVAL_PCACHE *cache;
#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] *zv=%p ps=%d refc=%d\n", cache, *zv, ps,
ZVAL_REFCOUNT(*zv));
+ php_printf("[mysqlnd_palloc_zval_ptr_dtor %p] parent_block=%p last_in_block=%p *zv=%p
ps=%d refc=%d\n",
+ thd_cache,
+ thd_cache->parent? thd_cache->parent->block:NULL,
+ thd_cache->parent? thd_cache->parent->last_in_block:NULL,
+ *zv, ps, ZVAL_REFCOUNT(*zv));
#endif
*copy_ctor_called = FALSE;
/* Check whether cache is used and the zval is from the cache */
@@ -349,7 +354,9 @@
Thus the refcount is -1 than of a zval from the cache,
because the zvals from the cache are owned by it.
*/
- if (ZVAL_REFCOUNT(*zv) > 1) {
+ if (ps == TRUE) {
+ ZVAL_REFCOUNT(*zv) = 1;
+ } else if (ZVAL_REFCOUNT(*zv) > 1) {
if (ps == FALSE) {
/*
Not a prepared statement, then we have to
@@ -465,7 +472,7 @@
MYSQLND_ZVAL_PCACHE *cache;
mysqlnd_zval **p;
#ifndef MYSQLND_SILENT
- php_printf("[mysqlnd_palloc_rshutdown %p]\n", cache);
+ php_printf("[mysqlnd_palloc_rshutdown %p]\n", thd_cache);
#endif
if (!thd_cache || !(cache = thd_cache->parent)) {
return;
Modified: branches/qcache/mysqlnd/mysqlnd_ps.c
===================================================================
--- branches/qcache/mysqlnd/mysqlnd_ps.c 2007-05-09 09:30:56 UTC (rev 363)
+++ branches/qcache/mysqlnd/mysqlnd_ps.c 2007-05-09 10:09:41 UTC (rev 364)
@@ -92,7 +92,7 @@
result->type = MYSQLND_RES_PS;
result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
result->m.fetch_lengths = NULL;/* makes no sense */
- result->zval_cache = NULL;
+ result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
/* Create room for 'next_extend' rows */
@@ -666,7 +666,7 @@
result->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
mysqlnd_stmt_fetch_row_unbuffered;
result->m.fetch_lengths = NULL; /* makes no sense */
- result->zval_cache = NULL;
+ result->zval_cache = mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache);
result->unbuf = ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
@@ -1160,7 +1160,6 @@
MYSQLND_RES * _mysqlnd_stmt_result_metadata(MYSQLND_STMT * const stmt)
{
MYSQLND_RES *result;
- MYSQLND_THD_ZVAL_PCACHE * cache;
if (!stmt->field_count || !stmt->conn || !stmt->result) {
return NULL;
@@ -1171,10 +1170,11 @@
find a better way to do it. In different functions I have put
fuses to check for result->m.fetch_row() being NULL. This should
be handled in a better way.
-
+
+ In the meantime we don't need a zval cache reference for this fake
+ result set, so we don't get one.
*/
- cache = mysqlnd_palloc_get_thd_cache_reference(stmt->conn->zval_cache);
- result = mysqlnd_result_init(stmt->field_count, cache);
+ result = mysqlnd_result_init(stmt->field_count, NULL);
result->type = MYSQLND_RES_NORMAL;
result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
result->unbuf = ecalloc(1, sizeof(MYSQLND_RES_UNBUFFERED));
| Thread |
|---|
| • PHP mysqlnd svn commit: r364 - branches/qcache/mysqlnd | ahristov | 9 May |