Author: ahristov
Date: 2007-03-12 10:58:08 +0100 (Mon, 12 Mar 2007)
New Revision: 95
Modified:
trunk/ext/mysqli/mysqlnd/mysqlnd.c
trunk/ext/mysqli/mysqlnd/mysqlnd.h
trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c
trunk/ext/mysqli/mysqlnd/mysqlnd_wireprotocol.c
Log:
Fix stmt_metadata crash, because we didn't close the
metadata and were doing double free.
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd.c 2007-03-08 09:15:49 UTC (rev 94)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd.c 2007-03-12 09:58:08 UTC (rev 95)
@@ -803,6 +803,7 @@
result->fields = NULL;
efree(result->zend_hash_keys);
+ result->zend_hash_keys = NULL;
}
/* +1 is to have empty marker at the end */
result->fields = ecalloc(result->field_count + 1, sizeof(MYSQLND_FIELD));
@@ -1030,27 +1031,29 @@
MYSQLND_ROW ret = NULL;
zend_bool fetched_anything;
- MAKE_STD_ZVAL(row);
- mysqlnd_array_init(row, result->field_count);
+ if (result->m.fetch_row) {
+ MAKE_STD_ZVAL(row);
+ mysqlnd_array_init(row, result->field_count);
- if (PASS == result->m.fetch_row(result, row, flags, &fetched_anything TSRMLS_CC)
&&
- fetched_anything == TRUE)
- {
- zval **entry;
- uint i = 0;
- if (!result->last_row) {
- result->last_row = emalloc(result->field_count * sizeof(char *));
- }
- ret = result->last_row;
+ if (PASS == result->m.fetch_row(result, row, flags, &fetched_anything TSRMLS_CC)
&&
+ fetched_anything == TRUE)
+ {
+ zval **entry;
+ uint i = 0;
+ if (!result->last_row) {
+ result->last_row = emalloc(result->field_count * sizeof(char *));
+ }
+ ret = result->last_row;
- zend_hash_internal_pointer_reset(Z_ARRVAL_P(row));
- while (zend_hash_get_current_data(Z_ARRVAL_P(row), (void **)&entry) == SUCCESS) {
- /* Everything is a string */
- ret[i++] = Z_STRVAL_PP(entry);
- zend_hash_move_forward(Z_ARRVAL_P(row));
+ zend_hash_internal_pointer_reset(Z_ARRVAL_P(row));
+ while (zend_hash_get_current_data(Z_ARRVAL_P(row), (void **)&entry) == SUCCESS) {
+ /* Everything is a string */
+ ret[i++] = Z_STRVAL_PP(entry);
+ zend_hash_move_forward(Z_ARRVAL_P(row));
+ }
}
+ zval_ptr_dtor(&row);
}
- zval_ptr_dtor(&row);
return ret;
}
/* }}} */
@@ -1223,7 +1226,7 @@
conn->current_result = NULL;
result->type = MYSQLND_RES_NORMAL;
- result->m.fetch_row = mysqlnd_fetch_row_unbuffered;
+ result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
result->m.fetch_lengths = mysqlnd_fetch_lengths_unbuffered;
result->m.fetch_row_old_way = _mysqlnd_fetch_row;
@@ -1319,7 +1322,7 @@
conn->current_result = NULL;
result->type = MYSQLND_RES_NORMAL;
- result->m.fetch_row = mysqlnd_fetch_row_buffered;
+ result->m.fetch_row = result->m.fetch_row_normal_buffered;
result->m.fetch_lengths = mysqlnd_fetch_lengths_buffered;
result->m.fetch_row_old_way = _mysqlnd_fetch_row;
@@ -1330,7 +1333,7 @@
/* Create room for 'next_extend' rows */
result->conn = NULL; /* store result does not reference the connection */
- result->data = emalloc(next_extend * sizeof(zval **));
+ result->data = emalloc(next_extend * sizeof(zval **));
result->row_buffers = emalloc(next_extend * sizeof(zend_uchar *));
free_rows = next_extend;
@@ -1367,7 +1370,8 @@
*/
if (Z_TYPE_P(current_row[i]) != IS_NULL &&
(len = Z_STRLEN_P(current_row[i])) &&
- result->fields[i].max_length < len) {
+ result->fields[i].max_length < len)
+ {
result->fields[i].max_length = len;
}
}
@@ -2209,6 +2213,9 @@
{
zend_bool fetched_anything;
+ if (!result->m.fetch_row) {
+ RETURN_NULL();
+ }
/*
Hint Zend how many elements we will have in the hash. Thus it won't
extend and rehash the hash constantly.
@@ -2338,6 +2345,8 @@
ret->m.field_tell = _mysqlnd_field_tell;
ret->m.fetch_field = _mysqlnd_fetch_field;
ret->m.fetch_field_direct = _mysqlnd_fetch_field_direct;
+ ret->m.fetch_row_normal_buffered = mysqlnd_fetch_row_buffered;
+ ret->m.fetch_row_normal_unbuffered = mysqlnd_fetch_row_unbuffered;
return ret;
}
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd.h
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd.h 2007-03-08 09:15:49 UTC (rev 94)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd.h 2007-03-12 09:58:08 UTC (rev 95)
@@ -371,6 +371,7 @@
unsigned int charsetnr; /* Character set */
enum mysqlnd_field_types type; /* Type of field. See mysql_com.h for types */
char *root;
+ size_t root_len;
} MYSQLND_FIELD;
@@ -545,6 +546,8 @@
struct st_mysqlnd_res_methods {
mysqlnd_fetch_row_func fetch_row;
+ mysqlnd_fetch_row_func fetch_row_normal_buffered; /* private */
+ mysqlnd_fetch_row_func fetch_row_normal_unbuffered; /* private */
void (*fetch_into)(MYSQLND_RES *result, unsigned int flags, zval *return_value
TSRMLS_DC ZEND_FILE_LINE_DC);
void (*fetch_all)(MYSQLND_RES *result, unsigned int flags, zval *return_value
TSRMLS_DC ZEND_FILE_LINE_DC);
mynd_ulonglong (*num_rows)(const MYSQLND_RES * const result);
@@ -578,7 +581,8 @@
enum_func_status (*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const
result_bind);
enum_func_status (*send_long_data)(MYSQLND_STMT * const stmt, unsigned int param_num,
const char * const data, unsigned long length TSRMLS_DC);
- MYSQLND_RES (*get_param_metadata)(MYSQLND_STMT * const stmt);
+ MYSQLND_RES * (*get_parameter_metadata)(MYSQLND_STMT * const stmt);
+ MYSQLND_RES * (*get_result_metadata)(MYSQLND_STMT * const stmt);
mynd_ulonglong (*get_last_insert_id)(const MYSQLND_STMT * const stmt);
mynd_ulonglong (*get_affected_rows)(const MYSQLND_STMT * const stmt);
@@ -951,7 +955,8 @@
#define mysqlnd_stmt_send_long_data(s,p,d,l) (s)->m->send_long_data((s), (p), (d),
(l) TSRMLS_CC)
#define mysqlnd_stmt_bind_param(stmt,bind) (stmt)->m->bind_param((stmt), (bind))
#define mysqlnd_stmt_bind_result(stmt,bind) (stmt)->m->bind_result((stmt), (bind))
-#define mysqlnd_stmt_param_metadata(stmt) (stmt)->m->get_param_metadata((stmt))
+#define mysqlnd_stmt_param_metadata(stmt) (stmt)->m->get_parameter_metadata((stmt))
+#define mysqlnd_stmt_result_metadata(stmt) (stmt)->m->get_result_metadata((stmt))
#define mysqlnd_stmt_free_result(stmt) (stmt)->m->free_result((stmt) TSRMLS_CC)
#define mysqlnd_stmt_close(stmt, implicit) (stmt)->m->dtor((stmt), (implicit)
TSRMLS_CC)
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c 2007-03-08 09:15:49 UTC (rev 94)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c 2007-03-12 09:58:08 UTC (rev 95)
@@ -1141,6 +1141,76 @@
/* }}} */
+/* {{{ mysqlnd_result_metadata_clone_metadata */
+static
+MYSQLND_FIELD * mysqlnd_result_metadata_clone_metadata(MYSQLND_RES * const result)
+{
+ unsigned int i;
+ /* +1 is to have empty marker at the end */
+ MYSQLND_FIELD *new_meta = ecalloc(result->field_count + 1, sizeof(MYSQLND_FIELD));
+ MYSQLND_FIELD *original_meta = result->fields;
+
+ /*
+ This will copy also the strings and the root, which we will have
+ to adjust in the loop
+ */
+ memcpy(new_meta, original_meta, (result->field_count) * sizeof(MYSQLND_FIELD));
+ for (i = 0; i < result->field_count; i++) {
+ /* First copy the root, then field by field adjust the pointers */
+ new_meta[i].root = emalloc(original_meta[i].root_len);
+ memcpy(new_meta[i].root, original_meta[i].root, new_meta[i].root_len);
+
+ new_meta[i].name = new_meta[i].root + (original_meta[i].name -
original_meta[i].root);
+ new_meta[i].org_name = new_meta[i].root + (original_meta[i].org_name -
original_meta[i].root);
+
+ new_meta[i].table = new_meta[i].root + (original_meta[i].table -
original_meta[i].root);
+ new_meta[i].org_table = new_meta[i].root + (original_meta[i].org_table -
original_meta[i].root);
+
+ new_meta[i].db = new_meta[i].root + (original_meta[i].db - original_meta[i].root);
+ new_meta[i].catalog = new_meta[i].root + (original_meta[i].catalog -
original_meta[i].root);
+ /* def is not on the root, if allocated at all */
+ if (original_meta[i].def) {
+ new_meta[i].def = emalloc(original_meta[i].def_length + 1);
+ /* copy the trailing \0 too */
+ memcpy(new_meta[i].def, original_meta[i].def, original_meta[i].def_length + 1);
+ }
+ }
+
+ return new_meta;
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_stmt_param_metadata */
+static
+MYSQLND_RES * _mysqlnd_stmt_result_metadata(MYSQLND_STMT * const stmt)
+{
+ MYSQLND_RES *result;
+ MYSQLND_ZVAL_PCACHE * cache;
+
+ if (!stmt->field_count || !stmt->conn || !stmt->result) {
+ return NULL;
+ }
+
+ /*
+ TODO: This implementation is kind of a hack,
+ 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.
+
+ */
+ cache = mysqlnd_palloc_get_cache_reference(stmt->conn->zval_cache);
+ result = mysqlnd_result_init(stmt->field_count, cache);
+ result->type = MYSQLND_RES_NORMAL;
+ result->m.fetch_row = result->m.fetch_row_normal_unbuffered;
+ result->eof_reached = TRUE;
+ result->fields= mysqlnd_result_metadata_clone_metadata(stmt->result);
+
+ return result;
+}
+/* }}} */
+
+
/* {{{ _mysqlnd_stmt_attr_set */
static enum_func_status
_mysqlnd_stmt_attr_set(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, const
void * const value)
@@ -1354,6 +1424,7 @@
_mysqlnd_stmt_bind_result,
_mysqlnd_stmt_send_long_data,
_mysqlnd_stmt_param_metadata,
+ _mysqlnd_stmt_result_metadata,
_mysqlnd_stmt_insert_id,
_mysqlnd_stmt_affected_rows,
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd_wireprotocol.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd_wireprotocol.c 2007-03-08 09:15:49 UTC (rev 94)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd_wireprotocol.c 2007-03-12 09:58:08 UTC (rev 95)
@@ -959,6 +959,7 @@
/* 2 byte filler */
p +=2;
+ /* def could be empty, thus don't allocate on the root */
if (packet->header.size > (p - buf) && (len =
php_mysqlnd_net_field_length(&p))) {
meta->def = emalloc(len + 1);
memcpy(meta->def, p, len);
@@ -968,6 +969,7 @@
}
root_ptr = meta->root = emalloc(total_len);
+ meta->root_len = total_len;
/* Now do allocs */
if (meta->catalog) {
len = meta->catalog_length;
| Thread |
|---|
| • PHP mysqlnd svn commit: r95 - trunk/ext/mysqli/mysqlnd | ahristov | 12 Mar |