List:Commits« Previous MessageNext Message »
From:ahristov Date:February 26 2007 7:43pm
Subject:PHP mysqlnd svn commit: r66 - trunk/ext/mysqli/mysqlnd
View as plain text  
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/mysqlndahristov26 Feb