Author: ahristov
Date: 2007-02-26 20:43:04 +0100 (Mon, 26 Feb 2007)
New Revision: 66
Modified:
trunk/ext/mysqli/mysqlnd/mysqlnd.c
trunk/ext/mysqli/mysqlnd/mysqlnd.h
trunk/ext/mysqli/mysqlnd/mysqlnd_priv.h
trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c
Log:
mysqlnd updates. MYSQLND_STMT also now has methods, being
C++ like object
Added :
- mysqlnd_stmt_data_seek()
- mysqlnd_stmt_num_rows()
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd.c 2007-02-26 14:59:58 UTC (rev 65)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd.c 2007-02-26 19:43:04 UTC (rev 66)
@@ -140,6 +140,8 @@
}
/* }}} */
+
+/* {{{ mysqlnd_internal_free_result_buffers */
void mysqlnd_internal_free_result_buffers(MYSQLND_RES *result)
{
int i;
@@ -204,7 +206,9 @@
result->lengths = NULL;
}
}
+/* }}} */
+
/* {{{ mysqlnd_internal_free_result_contents */
void mysqlnd_internal_free_result_contents(MYSQLND_RES *result)
{
@@ -311,7 +315,7 @@
conn->last_message = NULL;
}
if (conn->options.num_commands) {
- uint i;
+ unsigned int i;
for (i=0; i < conn->options.num_commands; i++) {
pefree(conn->options.init_commands[i], conn->persistent);
}
@@ -359,6 +363,7 @@
/* {{{ _mysqlnd_conn_dtor */
+static
void _mysqlnd_conn_dtor(MYSQLND *conn TSRMLS_DC)
{
conn->m->free_contents(conn TSRMLS_CC);
@@ -984,7 +989,7 @@
If conn->error_info.error_no is not zero, then we had an error.
Still the result from the query is PASS
*/
-enum_func_status
+static enum_func_status
_mysqlnd_query(MYSQLND *conn, const char *query, unsigned int query_len TSRMLS_DC)
{
@@ -1188,7 +1193,8 @@
/* {{{ mysqlnd_use_result */
-MYSQLND_RES *_mysqlnd_use_result(MYSQLND * const conn TSRMLS_DC)
+static
+MYSQLND_RES * _mysqlnd_use_result(MYSQLND * const conn TSRMLS_DC)
{
MYSQLND_RES *result;
@@ -1229,7 +1235,7 @@
/* {{{ mysqlnd_fetch_row_buffered */
-enum_func_status
+static enum_func_status
mysqlnd_fetch_row_buffered(MYSQLND_RES *result, void *param, unsigned int flags,
zend_bool *fetched_anything TSRMLS_DC)
{
@@ -1280,6 +1286,7 @@
#define STORE_RESULT_PREALLOCATED_SET 32
/* {{{ mysqlnd_store_result */
+static
MYSQLND_RES *_mysqlnd_store_result(MYSQLND * const conn TSRMLS_DC)
{
enum_func_status ret;
@@ -2200,7 +2207,9 @@
/* }}} */
+MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn);
+
static
struct st_mysqlnd_connection_methods mysqlnd_connection_methods = {
_mysqlnd_real_escape_string,
@@ -2211,6 +2220,8 @@
_mysqlnd_next_result,
_mysqlnd_more_results,
+ _mysqlnd_stmt_init,
+
_mysqlnd_shutdown,
_mysqlnd_refresh,
@@ -2276,7 +2287,7 @@
ret->m.num_fields = _mysqlnd_num_fields;
ret->m.fetch_into = _mysqlnd_fetch_into;
ret->m.fetch_all = _mysqlnd_fetch_all;
- ret->m.field_seek = _mysqlnd_field_seek;
+ ret->m.seek_field = _mysqlnd_field_seek;
ret->m.field_tell = _mysqlnd_field_tell;
ret->m.fetch_field = _mysqlnd_fetch_field;
ret->m.fetch_field_direct = _mysqlnd_fetch_field_direct;
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd.h
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd.h 2007-02-26 14:59:58 UTC (rev 65)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd.h 2007-02-26 19:43:04 UTC (rev 66)
@@ -23,7 +23,7 @@
#ifndef MYSQLND_H
#define MYSQLND_H
-#define MYSQLND_INLINE_OPTIMISATIONS 1
+#define MYSQLND_INLINE_OPTIMISATIONS 0
#include "portability.h"
@@ -265,6 +265,23 @@
MYSQLND_STMT_USER_FETCHING, /* fetch_row_buff or fetch_row_unbuf */
} enum_mysqlnd_stmt_state;
+/* PS */
+enum mysqlnd_stmt_attr
+{
+ STMT_ATTR_UPDATE_MAX_LENGTH,
+ STMT_ATTR_CURSOR_TYPE,
+ STMT_ATTR_PREFETCH_ROWS
+};
+
+enum myslqnd_cursor_type
+{
+ CURSOR_TYPE_NO_CURSOR= 0,
+ CURSOR_TYPE_READ_ONLY= 1,
+ CURSOR_TYPE_FOR_UPDATE= 2,
+ CURSOR_TYPE_SCROLLABLE= 4
+};
+
+
enum {
STAT_BYTES_SENT,
STAT_BYTES_RECEIVED,
@@ -444,6 +461,8 @@
enum_func_status (*next_result)(MYSQLND * const conn TSRMLS_DC);
zend_bool (*more_results)(const MYSQLND * const conn);
+ MYSQLND_STMT * (*stmt_init)(MYSQLND * const conn);
+
enum_func_status (*shutdown_server)(MYSQLND *conn, unsigned long level TSRMLS_DC);
enum_func_status (*refresh_server)(MYSQLND *conn, unsigned long options TSRMLS_DC);
@@ -454,7 +473,7 @@
enum_func_status (*change_user)(MYSQLND *conn, const char * user, const char * passwd,
const char * db TSRMLS_DC);
unsigned int (*get_error_no)(const MYSQLND * const conn);
- const char * (*get_error)(const MYSQLND * const conn);
+ const char * (*get_error_str)(const MYSQLND * const conn);
const char * (*get_sqlstate)(const MYSQLND * const conn);
mynd_ulonglong (*get_thread_id)(const MYSQLND * const conn);
void (*get_statistics)(MYSQLND *conn, zval *return_value TSRMLS_DC
ZEND_FILE_LINE_DC);
@@ -488,7 +507,7 @@
unsigned int (*num_fields)(const MYSQLND_RES * const result);
enum_func_status (*skip_result)(MYSQLND_RES * const result TSRMLS_DC);
enum_func_status (*seek_data)(MYSQLND_RES * result, mynd_ulonglong row);
- MYSQLND_FIELD_OFFSET (*field_seek)(MYSQLND_RES * const result, MYSQLND_FIELD_OFFSET
field_offset);
+ 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);
MYSQLND_FIELD * (*fetch_field_direct)(const MYSQLND_RES * const result,
MYSQLND_FIELD_OFFSET fieldnr);
@@ -500,6 +519,30 @@
};
+struct st_mysqlnd_stmt_methods {
+ enum_func_status (*prepare)(MYSQLND_STMT * const stmt, const char * const query,
unsigned int query_len TSRMLS_DC);
+ enum_func_status (*execute)(MYSQLND_STMT * const stmt TSRMLS_DC);
+ MYSQLND_RES * (*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
+ enum_func_status (*seek_data)(const MYSQLND_STMT * const stmt, mynd_ulonglong row);
+ enum_func_status (*close)(MYSQLND_STMT * const stmt TSRMLS_DC);
+
+ 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);
+
+ unsigned int (*get_param_count)(const MYSQLND_STMT * const stmt);
+ unsigned int (*get_field_count)(const MYSQLND_STMT * const stmt);
+ unsigned int (*get_warning_count)(const MYSQLND_STMT * const stmt);
+
+ unsigned int (*get_error_no)(const MYSQLND_STMT * const stmt);
+ const char * (*get_error_str)(const MYSQLND_STMT * const stmt);
+ const char * (*get_sqlstate)(const MYSQLND_STMT * const stmt);
+
+ enum_func_status (*get_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr
attr_type, void * const value);
+ enum_func_status (*set_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr
attr_type, const void * const value);
+};
+
+
struct st_mysqlnd_connection {
/* Operation related */
MYSQLND_NET net;
@@ -629,21 +672,7 @@
-enum mysqlnd_stmt_attr
-{
- STMT_ATTR_UPDATE_MAX_LENGTH,
- STMT_ATTR_CURSOR_TYPE,
- STMT_ATTR_PREFETCH_ROWS
-};
-enum myslqnd_cursor_type
-{
- CURSOR_TYPE_NO_CURSOR= 0,
- CURSOR_TYPE_READ_ONLY= 1,
- CURSOR_TYPE_FOR_UPDATE= 2,
- CURSOR_TYPE_SCROLLABLE= 4
-};
-
#define DEFAULT_PREFETCH_ROWS (ulong) 1
typedef struct st_mysqlnd_param_bind {
@@ -683,6 +712,8 @@
mysqlnd_stmt_use_or_store_func default_rset_handler;
MYSQLND_CMD_BUFFER cmd_buffer;
+
+ struct st_mysqlnd_stmt_methods *m;
};
@@ -692,6 +723,7 @@
void mysqlnd_library_end();
void mysqlnd_restart_psession(MYSQLND *conn);
void mysqlnd_end_psession(MYSQLND *conn);
+#define mysqlnd_thread_safe() TRUE
const MYSQLND_CHARSET * mysqlnd_find_charset_nr(uint charsetno);
const MYSQLND_CHARSET * mysqlnd_find_charset_name(const char * const charsetname);
@@ -753,7 +785,7 @@
#define mysqlnd_fetch_lengths(result) ((result)->m.fetch_lengths?
(result)->m.fetch_lengths((result)):NULL)
-#define mysqlnd_field_seek(result, ofs) (result)->m.field_seek((result), (ofs))
+#define mysqlnd_field_seek(result, ofs) (result)->m.seek_field((result), (ofs))
#define mysqlnd_field_tell(result) (result)->current_field
#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result))
#define mysqlnd_fetch_field_direct(result,fnr) &((result)->fields[(fnr)])
@@ -768,7 +800,7 @@
/* Errors */
#define mysqlnd_errno(conn) (conn)->m->get_error_no(conn)
-#define mysqlnd_error(conn) (conn)->m->get_error(conn)
+#define mysqlnd_error(conn) (conn)->m->get_error_str(conn)
#define mysqlnd_sqlstate(conn) (conn)->m->get_sqlstate(conn)
/* Simple metadata */
@@ -788,14 +820,14 @@
unsigned long * _mysqlnd_fetch_lengths(MYSQLND_RES * const result);
#define mysqlnd_fetch_lengths(result) _mysqlnd_fetch_lengths((result))
-#define mysqlnd_field_seek(result, ofs) (result)->m.field_seek((result), (ofs))
+#define mysqlnd_field_seek(result, ofs) (result)->m.seek_field((result), (ofs))
#define mysqlnd_field_tell(result) (result)->m.field_tell((result))
#define mysqlnd_fetch_field(result) (result)->m.fetch_field((result))
#define
mysqlnd_fetch_field_direct(result,fnr) (result)->m.fetch_field_direct((result), (fnr))
/* mysqlnd metadata */
const char * _mysqlnd_get_client_info();
-unsigned int mysqlnd_get_client_version();
+unsigned int _mysqlnd_get_client_version();
#define mysqlnd_get_client_info _mysqlnd_get_client_info
#define mysqlnd_get_client_version _mysqlnd_get_client_version
@@ -832,26 +864,33 @@
/* PS */
-MYSQLND_STMT * mysqlnd_stmt_init(MYSQLND * const conn);
-MYSQLND_RES * mysqlnd_stmt_store_result(MYSQLND_STMT * const stmt TSRMLS_DC);
-enum_func_status mysqlnd_stmt_prepare(MYSQLND_STMT * const stmt, const char * const
query, unsigned int query_len TSRMLS_DC);
-enum_func_status mysqlnd_stmt_execute(MYSQLND_STMT * const stmt TSRMLS_DC);
+#define mysqlnd_stmt_init(conn) (conn)->m->stmt_init((conn))
+#define mysqlnd_stmt_store_result(stmt) (stmt)->m->store_result((stmt) TSRMLS_CC)
+#define mysqlnd_stmt_data_seek(stmt, row) (stmt)->m->seek_data((stmt), (row))
+#define mysqlnd_stmt_prepare(stmt, q, qlen) (stmt)->m->prepare((stmt), (q), (qlen)
TSRMLS_CC)
+#define mysqlnd_stmt_execute(stmt) (stmt)->m->execute((stmt) TSRMLS_CC)
+#define mysqlnd_stmt_close(stmt) (stmt)->m->close((stmt) TSRMLS_CC)
+
+#define mysqlnd_stmt_insert_id(stmt) (stmt)->m->get_last_insert_id((stmt))
+#define mysqlnd_stmt_affected_rows(stmt) (stmt)->m->get_affected_rows((stmt))
+#define mysqlnd_stmt_num_rows(stmt) (stmt)->m->get_num_rows((stmt))
+#define mysqlnd_stmt_param_count(stmt) (stmt)->m->get_param_count((stmt))
+#define mysqlnd_stmt_field_count(stmt) (stmt)->m->get_field_count((stmt))
+#define mysqlnd_stmt_warning_count(stmt) (stmt)->m->get_warning_count((stmt))
+#define mysqlnd_stmt_errno(stmt) (stmt)->m->get_error_no((stmt))
+#define mysqlnd_stmt_error(stmt) (stmt)->m->get_error_str((stmt))
+#define mysqlnd_stmt_sqlstate(stmt) (stmt)->m->get_sqlstate((stmt))
+
+#define mysqlnd_stmt_attr_get(stmt, attr, value) (stmt)->m->get_attribute((stmt),
(attr), (value))
+#define mysqlnd_stmt_attr_set(stmt, attr, value) (stmt)->m->set_attribute((stmt),
(attr), (value))
+
+
enum_func_status mysqlnd_stmt_fetch(MYSQLND_STMT * const stmt, zend_bool * const
fetched_anything TSRMLS_DC);
-enum_func_status mysqlnd_stmt_close(MYSQLND_STMT * const stmt TSRMLS_DC);
-enum_func_status mysqlnd_stmt_bind_param(MYSQLND_STMT *stmt, MYSQLND_PARAM_BIND *
param_bind);
+enum_func_status mysqlnd_stmt_bind_param(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND *
const param_bind);
enum_func_status mysqlnd_stmt_bind_result(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND
* const result_bind);
-mynd_ulonglong mysqlnd_stmt_insert_id(const MYSQLND_STMT * const stmt);
-mynd_ulonglong mysqlnd_stmt_affected_rows(const MYSQLND_STMT * const stmt);
-unsigned int mysqlnd_stmt_field_count(const MYSQLND_STMT * const stmt);
-unsigned int mysqlnd_stmt_param_count(const MYSQLND_STMT * const stmt);
-unsigned int mysqlnd_stmt_warning_count(const MYSQLND_STMT * const stmt);
-unsigned int mysqlnd_stmt_errno(const MYSQLND_STMT * const stmt);
-const char * mysqlnd_stmt_error(const MYSQLND_STMT * const stmt);
-const char * mysqlnd_stmt_sqlstate(const MYSQLND_STMT * const stmt);
-enum_func_status mysqlnd_stmt_attr_set(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr
attr_type, unsigned long value);
-enum_func_status mysqlnd_stmt_attr_get(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr
attr_type, void * const value);
+
/* Performance statistics */
void _mysqlnd_get_client_stats(zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC);
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd_priv.h
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd_priv.h 2007-02-26 14:59:58 UTC (rev 65)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd_priv.h 2007-02-26 19:43:04 UTC (rev 66)
@@ -77,6 +77,8 @@
#define MAX_CHARSET_LEN 32
+#define SET_ERROR_AFF_ROWS(s) s->upsert_status.affected_rows = (mynd_ulonglong) ~0
+
/* Error handling */
#define SET_NEW_MESSAGE(buf, buf_len, message, len) \
{\
Modified: trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c
===================================================================
--- trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c 2007-02-26 14:59:58 UTC (rev 65)
+++ trunk/ext/mysqli/mysqlnd/mysqlnd_ps.c 2007-02-26 19:43:04 UTC (rev 66)
@@ -40,7 +40,7 @@
zend_bool *free_buffer);
-MYSQLND_RES *mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC);
+MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC);
enum_func_status mysqlnd_fetch_stmt_row_buffered(MYSQLND_RES *result, void *param,
unsigned int flags,
@@ -53,24 +53,115 @@
void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT *stmt);
-
-/* {{{ mysqlnd_stmt_init */
-MYSQLND_STMT *mysqlnd_stmt_init(MYSQLND * const conn)
+/* {{{ _mysqlnd_stmt_store_result */
+static
+MYSQLND_RES * _mysqlnd_stmt_store_result(MYSQLND_STMT * const stmt TSRMLS_DC)
{
- MYSQLND_STMT *stmt = ecalloc(1, sizeof(MYSQLND_STMT));
+ enum_func_status ret;
+ MYSQLND *conn = stmt->conn;
+ int next_extend = 32, free_rows;
+ php_mysql_packet_row row_packet;
+ MYSQLND_RES *result;
- stmt->state = MYSQLND_STMT_INITTED;
- stmt->conn = conn;
- stmt->cmd_buffer.length = 4096;
- stmt->cmd_buffer.buffer = emalloc(stmt->cmd_buffer.length);
- /*
- Mark that we reference the connection, thus it won't be
- be destructed till there is open statements. The last statement
- or normal query result will close it then.
- */
- conn->references++;
- return stmt;
+ if (stmt->cursor_exists) {
+ /* Silently convert buffered to unbuffered, for now */
+ return _mysqlnd_stmt_use_result(stmt TSRMLS_CC);
+ }
+
+ /* Nothing to store for UPSERT/LOAD DATA*/
+ if (!stmt->field_count ||
+ conn->state != 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);
+ return NULL;
+ }
+
+ MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_PS_BUFFERED_SETS);
+
+ result = stmt->result;
+ result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
+ result->m.fetch_lengths = NULL;/* makes no sense */
+ result->zval_cache = NULL;
+
+ /* Create room for 'next_extend' rows */
+
+ result->conn->references--; /* increased in prepare */
+ result->conn = NULL; /* store result does not reference the connection */
+ result->data = emalloc(next_extend * sizeof(zval **));
+ result->row_buffers = emalloc(next_extend * sizeof(zend_uchar *));
+
+ free_rows = next_extend;
+
+ PACKET_INIT_ALLOCA(row_packet, PROT_ROW_PACKET);
+ row_packet.field_count = stmt->field_count;
+ row_packet.binary_protocol = TRUE;
+ row_packet.fields_metadata = stmt->result->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 += result->row_count;
+ result->data = erealloc(result->data, total_rows * sizeof(zval **));
+ result->row_buffers = erealloc(result->row_buffers, total_rows *
sizeof(zend_uchar *));
+ }
+ free_rows--;
+ current_row = result->data[result->row_count] = row_packet.fields;
+ result->row_buffers[result->row_count] = row_packet.row_buffer;
+ result->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++) {
+ if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
+ unsigned long len = Z_STRLEN_P(current_row[i]);
+ if (result->fields[i].max_length < len) {
+ result->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.
+ */
+ }
+ /* Finally clean */
+ if (row_packet.eof) {
+ conn->upsert_status.warning_count = row_packet.warning_count;
+ conn->upsert_status.server_status = row_packet.server_status;
+ }
+ PACKET_FREE_ALLOCA(row_packet);
+ /* We can realloc here to save some memory, if free_rows > 0 ?*/
+
+ if (conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {
+ conn->state = CONN_NEXT_RESULT_PENDING;
+ } else {
+ conn->state = CONN_READY;
+ }
+
+ if (PASS == ret) {
+ /* Position at the first row */
+ result->data_cursor = result->data;
+ stmt->state = MYSQLND_STMT_FETCH_FINISHED;
+ /* No multithreading issues as we don't share the connection :) */
+ } else {
+ mysqlnd_internal_free_result_contents(stmt->result);
+ efree(stmt->result);
+ stmt->result = NULL;
+ php_error_docref(NULL TSRMLS_CC, E_WARNING, "Pretty serious error");
+ stmt->state = MYSQLND_STMT_PREPARED;
+ }
+ conn->state = CONN_READY;
+ return result;
}
/* }}} */
@@ -152,13 +243,16 @@
/* }}} */
-/* {{{ mysqlnd_stmt_prepare */
-enum_func_status
-mysqlnd_stmt_prepare(MYSQLND_STMT * const stmt, const char * const query, unsigned int
query_len TSRMLS_DC)
+/* {{{ _mysqlnd_stmt_prepare */
+static enum_func_status
+_mysqlnd_stmt_prepare(MYSQLND_STMT * const stmt, const char * const query, unsigned int
query_len TSRMLS_DC)
{
enum_func_status ret;
MYSQLND_RES *result = NULL;
+ SET_ERROR_AFF_ROWS(stmt);
+ SET_ERROR_AFF_ROWS(stmt->conn);
+
if (stmt->state > MYSQLND_STMT_INITTED) {
result = NULL;
/* close previously alloced resources and prepare the new statement */
@@ -166,9 +260,12 @@
/* CLEAN BUFFERS !!!!!!!!!!!!!!!!!!*/
}
- if (FAIL == mysqlnd_simple_command(stmt->conn, COM_STMT_PREPARE, query, query_len,
- PROT_LAST /* we will handle the OK packet*/,
- FALSE TSRMLS_CC)) {
+ ret = mysqlnd_simple_command(stmt->conn, COM_STMT_PREPARE, query, query_len,
+ PROT_LAST /* we will handle the OK packet*/,
+ FALSE TSRMLS_CC);
+ stmt->upsert_status = stmt->conn->upsert_status;
+
+ if (FAIL == ret) {
return FAIL;
}
@@ -207,9 +304,9 @@
/* }}} */
-/* {{{ mysqlnd_stmt_execute */
-enum_func_status
-mysqlnd_stmt_execute(MYSQLND_STMT * const stmt TSRMLS_DC)
+/* {{{ _mysqlnd_stmt_execute */
+static enum_func_status
+_mysqlnd_stmt_execute(MYSQLND_STMT * const stmt TSRMLS_DC)
{
enum_func_status ret;
zend_bool free_request;
@@ -217,6 +314,9 @@
size_t request_len;
MYSQLND *conn = stmt->conn;
+ SET_ERROR_AFF_ROWS(stmt);
+ 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) {
/*
@@ -252,18 +352,18 @@
return FAIL;
}
-
request = mysqlnd_stmt_execute_generate_request(stmt, &request_len,
&free_request);
/* support for buffer types should be added here ! */
- ret = mysqlnd_simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request,
request_len,
- PROT_LAST /* we will handle the response packet*/,
- FALSE TSRMLS_CC);
+ ret = mysqlnd_simple_command(stmt->conn, COM_STMT_EXECUTE, (char *)request,
request_len,
+ PROT_LAST /* we will handle the response packet*/,
+ FALSE TSRMLS_CC);
+
if (free_request) {
efree(request);
}
- stmt->upsert_status = stmt->conn->upsert_status;
+
if (ret == FAIL) {
stmt->error_info = conn->error_info;
return FAIL;
@@ -295,7 +395,7 @@
stmt->cursor_exists = TRUE;
conn->state = CONN_READY;
/* Only cursor read */
- stmt->default_rset_handler = mysqlnd_stmt_use_result;
+ stmt->default_rset_handler = _mysqlnd_stmt_use_result;
} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
/*
We have asked for CURSOR but got no cursor, because the condition
@@ -308,10 +408,10 @@
precached on client and server's resources are freed.
*/
/* preferred is buffered read */
- stmt->default_rset_handler = mysqlnd_stmt_store_result;
+ stmt->default_rset_handler = _mysqlnd_stmt_store_result;
} else {
/* preferred is unbuffered read */
- stmt->default_rset_handler = mysqlnd_stmt_use_result;
+ stmt->default_rset_handler = _mysqlnd_stmt_use_result;
}
}
}
@@ -366,118 +466,6 @@
/* }}} */
-/* {{{ mysqlnd_stmt_store_result */
-MYSQLND_RES *mysqlnd_stmt_store_result(MYSQLND_STMT * const stmt TSRMLS_DC)
-{
- enum_func_status ret;
- MYSQLND *conn = stmt->conn;
- int next_extend = 32, free_rows;
- php_mysql_packet_row row_packet;
- MYSQLND_RES *result;
-
-
- if (stmt->cursor_exists) {
- /* Silently convert buffered to unbuffered, for now */
- return mysqlnd_stmt_use_result(stmt TSRMLS_CC);
- }
-
- /* Nothing to store for UPSERT/LOAD DATA*/
- if (!stmt->field_count ||
- conn->state != 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);
- return NULL;
- }
-
- MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_PS_BUFFERED_SETS);
-
- result = stmt->result;
- result->m.fetch_row = mysqlnd_fetch_stmt_row_buffered;
- result->m.fetch_lengths = NULL;/* makes no sense */
- result->zval_cache = NULL;
-
- /* Create room for 'next_extend' rows */
-
- result->conn->references--; /* increased in prepare */
- result->conn = NULL; /* store result does not reference the connection */
- result->data = emalloc(next_extend * sizeof(zval **));
- result->row_buffers = emalloc(next_extend * sizeof(zend_uchar *));
-
- free_rows = next_extend;
-
- PACKET_INIT_ALLOCA(row_packet, PROT_ROW_PACKET);
- row_packet.field_count = stmt->field_count;
- row_packet.binary_protocol = TRUE;
- row_packet.fields_metadata = stmt->result->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 += result->row_count;
- result->data = erealloc(result->data, total_rows * sizeof(zval **));
- result->row_buffers = erealloc(result->row_buffers, total_rows *
sizeof(zend_uchar *));
- }
- free_rows--;
- current_row = result->data[result->row_count] = row_packet.fields;
- result->row_buffers[result->row_count] = row_packet.row_buffer;
- result->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++) {
- if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
- unsigned long len = Z_STRLEN_P(current_row[i]);
- if (result->fields[i].max_length < len) {
- result->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.
- */
- }
- /* Finally clean */
- if (row_packet.eof) {
- conn->upsert_status.warning_count = row_packet.warning_count;
- conn->upsert_status.server_status = row_packet.server_status;
- }
- PACKET_FREE_ALLOCA(row_packet);
- /* We can realloc here to save some memory, if free_rows > 0 ?*/
-
- if (conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) {
- conn->state = CONN_NEXT_RESULT_PENDING;
- } else {
- conn->state = CONN_READY;
- }
-
- if (PASS == ret) {
- /* Position at the first row */
- result->data_cursor = result->data;
- stmt->state = MYSQLND_STMT_FETCH_FINISHED;
- /* No multithreading issues as we don't share the connection :) */
- } else {
- mysqlnd_internal_free_result_contents(stmt->result);
- efree(stmt->result);
- stmt->result = NULL;
- php_error_docref(NULL TSRMLS_CC, E_WARNING, "Pretty serious error");
- stmt->state = MYSQLND_STMT_PREPARED;
- }
- conn->state = CONN_READY;
- return result;
-}
-/* }}} */
-
-
/* {{{ mysqlnd_stmt_fetch_row_unbuffered */
enum_func_status
mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES *result, void *param, unsigned int flags,
@@ -559,7 +547,7 @@
/* {{{ mysqlnd_stmt_use_result */
-MYSQLND_RES *mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC)
+MYSQLND_RES * _mysqlnd_stmt_use_result(MYSQLND_STMT *stmt TSRMLS_DC)
{
MYSQLND_RES *result;
MYSQLND *conn = stmt->conn;
@@ -730,9 +718,9 @@
/* }}} */
-/* {{{ mysqlnd_stmt_close */
-enum_func_status
-mysqlnd_stmt_close(MYSQLND_STMT * const stmt TSRMLS_DC)
+/* {{{ _mysqlnd_stmt_close */
+static enum_func_status
+_mysqlnd_stmt_close(MYSQLND_STMT * const stmt TSRMLS_DC)
{
MYSQLND * conn = stmt->conn;
zend_uchar buf[STMT_ID_LENGTH /* statement id */];
@@ -753,7 +741,7 @@
/* {{{ mysqlnd_stmt_bind_param */
enum_func_status
-mysqlnd_stmt_bind_param(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND *param_bind)
+mysqlnd_stmt_bind_param(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const param_bind)
{
int i = 0;
@@ -833,91 +821,122 @@
/* }}} */
-/* {{{ mysqlnd_stmt_insert_id */
-unsigned long long mysqlnd_stmt_insert_id(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_insert_id */
+static
+mynd_ulonglong _mysqlnd_stmt_insert_id(const MYSQLND_STMT * const stmt)
{
return stmt->upsert_status.last_insert_id;
}
/* }}} */
-/* {{{ mysqlnd_stmt_affected_rows */
-unsigned long long mysqlnd_stmt_affected_rows(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_affected_rows */
+static
+mynd_ulonglong _mysqlnd_stmt_affected_rows(const MYSQLND_STMT * const stmt)
{
return stmt->upsert_status.affected_rows;
}
/* }}} */
-/* {{{ mysqlnd_stmt_warning_count */
-unsigned int mysqlnd_stmt_warning_count(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_num_rows */
+static
+mynd_ulonglong _mysqlnd_stmt_num_rows(const MYSQLND_STMT * const stmt)
{
+ return stmt->result->row_count;
+}
+/* }}} */
+
+
+/* {{{ _mysqlnd_stmt_warning_count */
+static
+unsigned int _mysqlnd_stmt_warning_count(const MYSQLND_STMT * const stmt)
+{
return stmt->upsert_status.warning_count;
}
/* }}} */
-/* {{{ mysqlnd_stmt_field_count */
-unsigned int mysqlnd_stmt_field_count(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_field_count */
+static
+unsigned int _mysqlnd_stmt_field_count(const MYSQLND_STMT * const stmt)
{
return stmt->field_count;
}
/* }}} */
-/* {{{ mysqlnd_stmt_param_count */
-unsigned int mysqlnd_stmt_param_count(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_param_count */
+static
+unsigned int _mysqlnd_stmt_param_count(const MYSQLND_STMT * const stmt)
{
return stmt->param_count;
}
/* }}} */
-/* {{{ mysqlnd_stmt_errno */
-unsigned int mysqlnd_stmt_errno(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_errno */
+static
+unsigned int _mysqlnd_stmt_errno(const MYSQLND_STMT * const stmt)
{
return stmt->error_info.error_no;
}
/* }}} */
-/* {{{ mysqlnd_stmt_error */
-const char *mysqlnd_stmt_error(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_error */
+static
+const char * _mysqlnd_stmt_error(const MYSQLND_STMT * const stmt)
{
return stmt->error_info.error;
}
/* }}} */
-/* {{{ mysqlnd_stmt_sqlstate */
-const char *mysqlnd_stmt_sqlstate(const MYSQLND_STMT * const stmt)
+/* {{{ _mysqlnd_stmt_sqlstate */
+static
+const char * _mysqlnd_stmt_sqlstate(const MYSQLND_STMT * const stmt)
{
return stmt->error_info.sqlstate[0] ?
stmt->error_info.sqlstate:MYSQLND_SQLSTATE_NULL;
}
/* }}} */
-/* {{{ mysqlnd_stmt_attr_set */
-enum_func_status
-mysqlnd_stmt_attr_set(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type,
unsigned long value)
+/* {{{ _mysqlnd_stmt_sqlstate */
+static
+enum_func_status _mysqlnd_stmt_data_seek(const MYSQLND_STMT * const stmt, mynd_ulonglong
row)
{
+ return stmt->result? stmt->result->m.seek_data(stmt->result, row) : FAIL;
+}
+/* }}} */
+
+
+/* {{{ _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)
+{
+ unsigned long val = *(unsigned long *) value;
switch (attr_type) {
case STMT_ATTR_UPDATE_MAX_LENGTH:
- stmt->update_max_length = value? TRUE:FALSE;
+ /*
+ XXX : libmysql uses my_bool, but mysqli uses ulong as storage on the stack
+ and mysqlnd won't be used out of the scope of PHP -> use ulong.
+ */
+ stmt->update_max_length = val? TRUE:FALSE;
break;
case STMT_ATTR_CURSOR_TYPE: {
- if (value > (unsigned long) CURSOR_TYPE_READ_ONLY) {
+ if (val > (unsigned long) CURSOR_TYPE_READ_ONLY) {
SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
return FAIL;
}
- stmt->flags = value;
+ stmt->flags = val;
break;
}
case STMT_ATTR_PREFETCH_ROWS: {
- if (value == 0) {
- value = DEFAULT_PREFETCH_ROWS;
+ if (val == 0) {
+ val = DEFAULT_PREFETCH_ROWS;
}
- stmt->prefetch_rows = value;
+ stmt->prefetch_rows = val;
break;
}
default:
@@ -929,9 +948,9 @@
/* }}} */
-/* {{{ mysqlnd_stmt_attr_get */
-enum_func_status
-mysqlnd_stmt_attr_get(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, void *
const value)
+/* {{{ _mysqlnd_stmt_attr_get */
+static enum_func_status
+_mysqlnd_stmt_attr_get(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr attr_type, void
* const value)
{
switch (attr_type) {
case STMT_ATTR_UPDATE_MAX_LENGTH:
@@ -1055,3 +1074,51 @@
}
}
/* }}} */
+
+
+static
+struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = {
+ _mysqlnd_stmt_prepare,
+ _mysqlnd_stmt_execute,
+ _mysqlnd_stmt_store_result,
+ _mysqlnd_stmt_data_seek,
+ _mysqlnd_stmt_close,
+
+ _mysqlnd_stmt_insert_id,
+ _mysqlnd_stmt_affected_rows,
+ _mysqlnd_stmt_num_rows,
+
+ _mysqlnd_stmt_param_count,
+ _mysqlnd_stmt_field_count,
+ _mysqlnd_stmt_warning_count,
+
+ _mysqlnd_stmt_errno,
+ _mysqlnd_stmt_error,
+ _mysqlnd_stmt_sqlstate,
+
+ _mysqlnd_stmt_attr_get,
+ _mysqlnd_stmt_attr_set,
+};
+
+
+/* {{{ _mysqlnd_stmt_init */
+MYSQLND_STMT * _mysqlnd_stmt_init(MYSQLND * const conn)
+{
+ MYSQLND_STMT *stmt = ecalloc(1, sizeof(MYSQLND_STMT));
+
+ stmt->m = &mysqlnd_stmt_methods;
+ stmt->state = MYSQLND_STMT_INITTED;
+ stmt->conn = conn;
+ stmt->cmd_buffer.length = 4096;
+ stmt->cmd_buffer.buffer = emalloc(stmt->cmd_buffer.length);
+ /*
+ Mark that we reference the connection, thus it won't be
+ be destructed till there is open statements. The last statement
+ or normal query result will close it then.
+ */
+ conn->references++;
+
+
+ return stmt;
+}
+/* }}} */
| Thread |
|---|
| • PHP mysqlnd svn commit: r66 - trunk/ext/mysqli/mysqlnd | ahristov | 26 Feb |