Author: ahristov
Date: 2007-03-08 10:15:49 +0100 (Thu, 08 Mar 2007)
New Revision: 94
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_ps_codec.c
Log:
Add empty mysqlnd_stmt_param_metadata()
Fix various bugs to pass stmt tests
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd.c 2007-03-07 17:52:02 UTC (rev 93)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd.c 2007-03-08 09:15:49 UTC (rev 94)
@@ -1456,11 +1456,17 @@
static enum_func_status
_mysqlnd_data_seek(MYSQLND_RES *result, mynd_ulonglong row)
{
- if (!result->data || row >= result->row_count) {
+ if (!result->data) {
return FAIL;
}
- result->data_cursor = result->data + row;
+ /* libmysql just moves to the end, it does traversing of a linked list */
+ if (row >= result->row_count) {
+ result->data_cursor = NULL;
+ } else {
+ result->data_cursor = result->data + row;
+ }
+
return PASS;
}
/* }}} */
@@ -1657,8 +1663,8 @@
a protocol of giving back -1. Thus we have to follow it :(
*/
conn->upsert_status.affected_rows = -1;
- } else {
- ret = mysqlnd_simple_command(conn, COM_PROCESS_KILL, buff, 4, PROT_LAST, FALSE
TSRMLS_CC);
+ } else if (PASS == (ret = mysqlnd_simple_command(conn, COM_PROCESS_KILL, buff,
+ 4, PROT_LAST, FALSE TSRMLS_CC))) {
conn->state = CONN_QUIT_SENT;
}
return ret;
@@ -1785,7 +1791,8 @@
/* {{{ _mysqlnd_num_fields */
mynd_ulonglong _mysqlnd_num_rows(const MYSQLND_RES * const res)
{
- return res->row_count;
+ /* Be compatible with libmysql. We count row_count, but will return 0 */
+ return res->data? res->row_count:0;
}
/* }}} */
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd.h
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd.h 2007-03-07 17:52:02 UTC (rev 93)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd.h 2007-03-08 09:15:49 UTC (rev 94)
@@ -24,7 +24,7 @@
#define MYSQLND_H
/* This forces inlining some accessor functions */
-#define MYSQLND_USE_OPTIMISATIONS 1
+#define MYSQLND_USE_OPTIMISATIONS 0
/*
This force mysqlnd to do a single (or more depending on ammount of data)
non-blocking read() calls before sending a command to the server. Useful
@@ -578,6 +578,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);
+
mynd_ulonglong (*get_last_insert_id)(const MYSQLND_STMT * const stmt);
mynd_ulonglong (*get_affected_rows)(const MYSQLND_STMT * const stmt);
mynd_ulonglong (*get_num_rows)(const MYSQLND_STMT * const stmt);
@@ -754,6 +756,7 @@
unsigned char send_types_to_server;
MYSQLND_PARAM_BIND *param_bind;
MYSQLND_RESULT_BIND *result_bind;
+ zend_bool result_zvals_separated_once;
mysqlnd_upsert_status upsert_status;
@@ -834,7 +837,7 @@
#define mysqlnd_get_proto_info(conn) (conn)->protocol_version
#define mysqlnd_thread_id(conn) (conn)->thread_id
-#define mysqlnd_num_rows(result) (result)->row_count
+#define mysqlnd_num_rows(result) ((result)->data? (result)->row_count:0)
#define mysqlnd_num_fields(result) (result)->field_count
#define mysqlnd_fetch_lengths(result) ((result)->m.fetch_lengths?
(result)->m.fetch_lengths((result)):NULL)
@@ -851,7 +854,7 @@
/* PS */
#define mysqlnd_stmt_insert_id(stmt) (stmt)->upsert_status.last_insert_id
#define mysqlnd_stmt_affected_rows(stmt) (stmt)->upsert_status.affected_rows
-#define mysqlnd_stmt_num_rows(stmt) ((stmt)->result?
(stmt)->result->row_count:0)
+#define mysqlnd_stmt_num_rows(stmt) (stmt)->result?
mysqlnd_num_rows((stmt)->result):0
#define mysqlnd_stmt_param_count(stmt) (stmt)->param_count
#define mysqlnd_stmt_field_count(stmt) (stmt)->field_count
#define mysqlnd_stmt_warning_count(stmt) (stmt)->upsert_status.warning_count
@@ -948,6 +951,7 @@
#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_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-07 17:52:02 UTC (rev 93)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c 2007-03-08 09:15:49 UTC (rev 94)
@@ -53,7 +53,7 @@
unsigned int flags,
zend_bool *fetched_anything TSRMLS_DC);
-void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT *stmt);
+void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
/* {{{ _mysqlnd_stmt_store_result */
@@ -352,11 +352,21 @@
SET_ERROR_AFF_ROWS(stmt->conn);
if (stmt->state > MYSQLND_STMT_PREPARED && stmt->field_count) {
- if (stmt->result_bind && stmt->state >= MYSQLND_STMT_USER_FETCHING) {
+ if (stmt->result_bind &&
+ stmt->result_zvals_separated_once == TRUE &&
+ stmt->state >= MYSQLND_STMT_USER_FETCHING)
+ {
/*
We need to copy the data from the buffers which we will clean.
The bound variables point to them only if the user has started
to fetch data (MYSQLND_STMT_USER_FETCHING).
+ We need to check 'result_zvals_separated_once' or we will leak
+ in the following scenation
+ prepare("select 1 from dual");
+ execute();
+ fetch(); <-- no binding, but that's not a problem
+ bind_result();
+ execute(); <-- here we will leak because we separate without need
*/
unsigned int i;
for (i = 0; i < stmt->field_count; i++) {
@@ -467,23 +477,26 @@
/* If we haven't read everything */
if (result->data_cursor && (result->data_cursor - result->data) <
result->row_count) {
- zval **current_row = *result->data_cursor;
- for (i = 0; i < result->field_count; i++) {
- /* copy the type */
- if (stmt->result_bind[i].bound == TRUE) {
- if (Z_TYPE_P(current_row[i]) != IS_NULL) {
- /*
- Copy the value.
- Pre-condition is that the zvals in the result_bind buffer
- have been ZVAL_NULL()-ed or to another simple type
- (int, double, bool but not string). Because of the reference
- counting the user can't delete the strings the variables point to.
- */
+ /* The user could have skipped binding - don't crash*/
+ if (stmt->result_bind) {
+ zval **current_row = *result->data_cursor;
+ for (i = 0; i < result->field_count; i++) {
+ /* copy the type */
+ if (stmt->result_bind[i].bound == TRUE) {
+ if (Z_TYPE_P(current_row[i]) != IS_NULL) {
+ /*
+ Copy the value.
+ Pre-condition is that the zvals in the result_bind buffer
+ have been ZVAL_NULL()-ed or to another simple type
+ (int, double, bool but not string). Because of the reference
+ counting the user can't delete the strings the variables point to.
+ */
- Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
- stmt->result_bind[i].zv->value = current_row[i]->value;
- } else {
- ZVAL_NULL(stmt->result_bind[i].zv);
+ Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
+ stmt->result_bind[i].zv->value = current_row[i]->value;
+ } else {
+ ZVAL_NULL(stmt->result_bind[i].zv);
+ }
}
}
}
@@ -521,7 +534,7 @@
return FAIL;
}
/* Let the row packet fill our buffer and skip additional malloc + memcpy */
- row_packet->skip_extraction = stmt? FALSE:TRUE;
+ row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
/*
If we skip rows (row == NULL) we have to
@@ -659,6 +672,8 @@
return FAIL;
}
+ row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
+
if (PASS == (ret = PACKET_READ(row_packet, result->conn)) &&
!row_packet->eof) {
unsigned int i, field_count = result->field_count;
mysqlnd_unbuffered_free_last_data(result);
@@ -667,21 +682,23 @@
result->last_row_buffer = row_packet->row_buffer;
row_packet->fields = NULL;
row_packet->row_buffer = NULL;
+ if (!row_packet->skip_extraction) {
+ /* If no result bind, do nothing. We consumed the data */
+ for (i = 0; i < field_count; i++) {
+ if (stmt->result_bind[i].bound == TRUE) {
+ zval *data = result->last_row_data[i];
+ /*
+ stmt->result_bind[i].zv has been already destructed
+ in mysqlnd_unbuffered_free_last_data()
+ */
- for (i = 0; i < field_count; i++) {
- if (stmt->result_bind[i].bound == TRUE) {
- zval *data = result->last_row_data[i];
- /*
- stmt->result_bind[i].zv has been already destructed
- in mysqlnd_unbuffered_free_last_data()
- */
-
- if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
- stmt->result_bind[i].zv->value = data->value;
- if ((Z_TYPE_P(data) == IS_STRING || Z_TYPE_P(data) == IS_UNICODE)
- && (result->fields[i].max_length < Z_STRLEN_P(data)))
- {
- result->fields[i].max_length = Z_STRLEN_P(data);
+ if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
+ stmt->result_bind[i].zv->value = data->value;
+ if ((Z_TYPE_P(data) == IS_STRING || Z_TYPE_P(data) == IS_UNICODE)
+ && (result->fields[i].max_length < Z_STRLEN_P(data)))
+ {
+ result->fields[i].max_length = Z_STRLEN_P(data);
+ }
}
}
}
@@ -723,16 +740,22 @@
enum_func_status
mysqlnd_stmt_fetch(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything
TSRMLS_DC)
{
- if (!stmt->result || !stmt->result_bind ||
+ if (!stmt->result ||
stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
return FAIL;
} else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
/* Execute only once. We have to free the previous contents of user's bound vars */
stmt->default_rset_handler(stmt TSRMLS_CC);
+ stmt->state = MYSQLND_STMT_USER_FETCHING;
}
/* no else please */
- if (stmt->state == MYSQLND_STMT_USE_OR_STORE_CALLED) {
+
+ /*
+ The user might have not bound any variables for result.
+ Do the binding once she does it.
+ */
+ if (stmt->result_bind && !stmt->result_zvals_separated_once) {
unsigned int i;
/*
mysqlnd_stmt_store_result() has been called free the bind
@@ -744,9 +767,8 @@
ZVAL_NULL(stmt->result_bind[i].zv);
}
}
- stmt->state = MYSQLND_STMT_USER_FETCHING;
+ stmt->result_zvals_separated_once = TRUE;
}
- /* no else clause here please */
MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT);
@@ -989,6 +1011,7 @@
_mysqlnd_stmt_bind_result(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const
result_bind)
{
int i = 0;
+
if (stmt->state < MYSQLND_STMT_PREPARED) {
SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
return FAIL;
@@ -997,11 +1020,10 @@
if (stmt->field_count) {
if (!result_bind) {
return FAIL;
- } else if (stmt->result_bind) {
- mysqlnd_stmt_separate_result_bind(stmt);
- efree(stmt->result_bind);
}
+ mysqlnd_stmt_separate_result_bind(stmt);
+
stmt->result_bind = result_bind;
for (i = 0; i < stmt->field_count; i++) {
/* Prevent from freeing */
@@ -1038,7 +1060,7 @@
static
mynd_ulonglong _mysqlnd_stmt_num_rows(const MYSQLND_STMT * const stmt)
{
- return stmt->result? stmt->result->row_count:0;
+ return stmt->result? mysqlnd_num_rows(stmt->result):0;
}
/* }}} */
@@ -1106,6 +1128,19 @@
/* }}} */
+/* {{{ _mysqlnd_stmt_param_metadata */
+static
+MYSQLND_RES * _mysqlnd_stmt_param_metadata(MYSQLND_STMT * const stmt)
+{
+ if (!stmt->param_count) {
+ return NULL;
+ }
+
+ return NULL;
+}
+/* }}} */
+
+
/* {{{ _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)
@@ -1188,9 +1223,7 @@
Separate the bound variables, which point to the result set, then
destroy the set.
*/
- if (stmt->result_bind) {
- mysqlnd_stmt_separate_result_bind(stmt);
- }
+ mysqlnd_stmt_separate_result_bind(stmt);
/* Now we can destroy the result set */
stmt->result->m.free_result_buffers(stmt->result);
@@ -1208,12 +1241,14 @@
/* {{{ mysqlnd_stmt_separate_result_bind */
-void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT *stmt)
+void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt)
{
int i;
+
if (!stmt->result_bind) {
return;
}
+
/*
Because only the bound variables can point to our internal buffers, then
separate or free only them. Free is possible because the user could have
@@ -1248,6 +1283,8 @@
}
}
}
+ efree(stmt->result_bind);
+ stmt->result_bind = NULL;
}
/* }}} */
@@ -1278,12 +1315,7 @@
First separate the bound variables, which point to the result set, then
destroy the set.
*/
- if (stmt->result_bind) {
- mysqlnd_stmt_separate_result_bind(stmt);
-
- efree(stmt->result_bind);
- stmt->result_bind = NULL;
- }
+ mysqlnd_stmt_separate_result_bind(stmt);
/* Not every statement has a result set attached */
if (stmt->result) {
mysqlnd_internal_free_result(stmt->result TSRMLS_CC);
@@ -1321,6 +1353,7 @@
_mysqlnd_stmt_bind_param,
_mysqlnd_stmt_bind_result,
_mysqlnd_stmt_send_long_data,
+ _mysqlnd_stmt_param_metadata,
_mysqlnd_stmt_insert_id,
_mysqlnd_stmt_affected_rows,
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd_ps_codec.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd_ps_codec.c 2007-03-07 17:52:02 UTC (rev 93)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd_ps_codec.c 2007-03-08 09:15:49 UTC (rev 94)
@@ -155,7 +155,8 @@
* use MYSQLND_LL_SPEC.
*/
sprintf((char *)&tmp, uns == TRUE? MYSQLND_LLU_SPEC : MYSQLND_LL_SPEC, llval);
- ZVAL_UTF8_STRING(zv, tmp, ZSTR_DUPLICATE);
+// ZVAL_UTF8_STRING(zv, tmp, ZSTR_DUPLICATE);
+ ZVAL_STRING(zv, tmp, 1);
} else {
ZVAL_LONG(zv, llval);
}
| Thread |
|---|
| • PHP mysqlnd svn commit: r94 - trunk/ext/mysqli/mysqlnd | ahristov | 8 Mar |