List:Commits« Previous MessageNext Message »
From:ahristov Date:June 19 2007 10:33am
Subject:PHP mysqlnd svn commit: r397 - in trunk: mysqlnd php5/ext/mysqli php6/ext/mysqli tests/ext/mysqli
View as plain text  
Author: ahristov
Date: 2007-06-19 12:33:30 +0200 (Tue, 19 Jun 2007)
New Revision: 397

Added:
   trunk/tests/ext/mysqli/mysqli_stmt_get_result.phpt
Modified:
   trunk/mysqlnd/mysqlnd.c
   trunk/mysqlnd/mysqlnd.h
   trunk/mysqlnd/mysqlnd_ps.c
   trunk/mysqlnd/mysqlnd_result.c
   trunk/php5/ext/mysqli/mysqli_fe.c
   trunk/php5/ext/mysqli/mysqli_nonapi.c
   trunk/php5/ext/mysqli/php_mysqli.h
   trunk/php6/ext/mysqli/mysqli_api.c
   trunk/php6/ext/mysqli/mysqli_fe.c
   trunk/php6/ext/mysqli/mysqli_nonapi.c
   trunk/php6/ext/mysqli/php_mysqli.h
   trunk/tests/ext/mysqli/002.phpt
Log:
Here comes mysql_stmt_get_result(). With this changeset
we freeze features before the RC. Comes time to check the problems
found by commitbuild.


Modified: trunk/mysqlnd/mysqlnd.c
===================================================================
--- trunk/mysqlnd/mysqlnd.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/mysqlnd/mysqlnd.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -855,9 +855,9 @@
 /* }}} */
 
 
-/* {{{ _mysqlnd_send_close */
+/* {{{ mysqlnd_send_close */
 static enum_func_status
-_mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
+mysqlnd_send_close(MYSQLND * conn TSRMLS_DC)
 {
 	enum_func_status ret = PASS;
 	switch (conn->state) {
@@ -914,7 +914,7 @@
 
 	MYSQLND_INC_CONN_STATISTIC(NULL, stat);
 
-	_mysqlnd_send_close(conn TSRMLS_CC);
+	mysqlnd_send_close(conn TSRMLS_CC);
 
 	conn->m->free_reference(conn TSRMLS_CC);
 
@@ -943,7 +943,7 @@
 		  This will free the object too, of course because references has
 		  reached zero.
 		*/
-		_mysqlnd_send_close(conn TSRMLS_CC);
+		mysqlnd_send_close(conn TSRMLS_CC);
 		conn->m->dtor(conn TSRMLS_CC);
 	}
 }
@@ -995,18 +995,16 @@
 /* }}} */
 
 
-/* {{{ mysqlnd_conn::client_info */
-PHPAPI const char *
-MYSQLND_METHOD(mysqlnd_conn, get_client_info)()
+/* {{{ mysqlnd_get_client_info */
+PHPAPI const char * mysqlnd_get_client_info()
 {
 	return MYSQLND_VERSION;
 }
 /* }}} */
 
 
-/* {{{ mysqlnd_conn::get_client_version */
-PHPAPI unsigned int
-MYSQLND_METHOD(mysqlnd_conn, get_client_version)()
+/* {{{ mysqlnd_get_client_version */
+PHPAPI unsigned int mysqlnd_get_client_version()
 {
 	return MYSQLND_VERSION_ID;
 }
@@ -1338,7 +1336,7 @@
 	conn->current_result = NULL;
 	result->conn = conn->m->get_reference(conn);
 
-	return result->m.use_result(result TSRMLS_CC);
+	return result->m.use_result(result, FALSE TSRMLS_CC);
 }
 /* }}} */
 
@@ -1365,7 +1363,7 @@
 	result = conn->current_result;
 	conn->current_result = NULL;
 
-	return result->m.store_result(result, conn TSRMLS_CC);
+	return result->m.store_result(result, conn, FALSE TSRMLS_CC);
 }
 /* }}} */
 

Modified: trunk/mysqlnd/mysqlnd.h
===================================================================
--- trunk/mysqlnd/mysqlnd.h	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/mysqlnd/mysqlnd.h	2007-06-19 10:33:30 UTC (rev 397)
@@ -28,7 +28,7 @@
 
 
 /* This forces inlining of some accessor functions */
-#define MYSQLND_USE_OPTIMISATIONS 1
+#define MYSQLND_USE_OPTIMISATIONS 0
 
 /* #define MYSQLND_STRING_TO_INT_CONVERSION */
 /*
@@ -368,8 +368,8 @@
 	mysqlnd_fetch_row_func	fetch_row_normal_buffered; /* private */
 	mysqlnd_fetch_row_func	fetch_row_normal_unbuffered; /* private */
 
-	MYSQLND_RES *		(*use_result)(MYSQLND_RES * const result TSRMLS_DC);
-	MYSQLND_RES *		(*store_result)(MYSQLND_RES * result, MYSQLND * const conn TSRMLS_DC);
+	MYSQLND_RES *		(*use_result)(MYSQLND_RES * const result, zend_bool ps_protocol
TSRMLS_DC);
+	MYSQLND_RES *		(*store_result)(MYSQLND_RES * result, MYSQLND * const conn, zend_bool ps
TSRMLS_DC);
 	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);
@@ -402,6 +402,7 @@
 	enum_func_status	(*execute)(MYSQLND_STMT * const stmt TSRMLS_DC);
 	MYSQLND_RES *		(*use_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
 	MYSQLND_RES *		(*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
+	MYSQLND_RES *		(*get_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
 	enum_func_status	(*free_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
 	enum_func_status	(*seek_data)(const MYSQLND_STMT * const stmt, mynd_ulonglong row);
 	enum_func_status	(*reset)(MYSQLND_STMT * const stmt TSRMLS_DC);
@@ -409,7 +410,6 @@
 	enum_func_status	(*dtor)(MYSQLND_STMT * const stmt, zend_bool implicit TSRMLS_DC); /*
use this for mysqlnd_stmt_close */
 
 	enum_func_status	(*fetch)(MYSQLND_STMT * const stmt, zend_bool * const fetched_anything
TSRMLS_DC);
-	void 				(*fetch_into)(MYSQLND_STMT *stmt, unsigned int flags, zval *return_value
TSRMLS_DC ZEND_FILE_LINE_DC);
 
 	enum_func_status	(*bind_param)(MYSQLND_STMT * const stmt, MYSQLND_PARAM_BIND * const
param_bind);
 	enum_func_status	(*bind_result)(MYSQLND_STMT * const stmt, MYSQLND_RESULT_BIND * const
result_bind);
@@ -557,6 +557,8 @@
 
 
 struct st_mysqlnd_res {
+	struct st_mysqlnd_res_methods m;
+
 	MYSQLND					*conn;
 	enum_mysqlnd_res_type	type;
 	unsigned int			field_count;
@@ -580,9 +582,6 @@
 	/* zval cache */
 	MYSQLND_THD_ZVAL_PCACHE		*zval_cache;
 
-	unsigned int			references;
-
-	struct st_mysqlnd_res_methods m;
 };
 
 
@@ -616,7 +615,6 @@
 	MYSQLND_PARAM_BIND			*param_bind;
 	MYSQLND_RESULT_BIND			*result_bind;
 	zend_bool					result_zvals_separated_once;
-	zend_bool					old_style_fetch;
 
 	mysqlnd_upsert_status		upsert_status;
 
@@ -746,8 +744,7 @@
 #define mysqlnd_num_rows(result)		(result)->m.num_rows((result))
 #define mysqlnd_num_fields(result)		(result)->m.num_fields((result))
 
-PHPAPI unsigned long *	_mysqlnd_fetch_lengths(MYSQLND_RES * const result);
-#define mysqlnd_fetch_lengths(result)	_mysqlnd_fetch_lengths((result))
+PHPAPI unsigned long * mysqlnd_fetch_lengths(MYSQLND_RES * const result);
 
 #define mysqlnd_field_seek(result, ofs)			(result)->m.seek_field((result), (ofs))
 #define mysqlnd_field_tell(result)				(result)->m.field_tell((result))
@@ -755,12 +752,9 @@
 #define
mysqlnd_fetch_field_direct(result,fnr)	(result)->m.fetch_field_direct((result), (fnr))
 
 /* mysqlnd metadata */
-PHPAPI const char *	_mysqlnd_get_client_info();
-PHPAPI unsigned int	_mysqlnd_get_client_version();
-#define mysqlnd_get_client_info			_mysqlnd_get_client_info
-#define mysqlnd_get_client_version		_mysqlnd_get_client_version
+PHPAPI const char *	mysqlnd_get_client_info();
+PHPAPI unsigned int	mysqlnd_get_client_version();
 
-
 /* PS */
 #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))
@@ -776,7 +770,7 @@
 
 
 
-const char *		mysqlnd_field_type_name(enum mysqlnd_field_types field_type);
+const char * mysqlnd_field_type_name(enum mysqlnd_field_types field_type);
 
 /* LOAD DATA LOCAL */
 PHPAPI void mysqlnd_local_infile_default(MYSQLND *conn);
@@ -806,6 +800,7 @@
 /* PS */
 #define mysqlnd_stmt_init(conn)				(conn)->m->stmt_init((conn))
 #define mysqlnd_stmt_store_result(stmt)		(!mysqlnd_stmt_field_count((stmt)) ?
PASS:((stmt)->m->store_result((stmt) TSRMLS_CC)? PASS:FAIL))
+#define mysqlnd_stmt_get_result(stmt)		(stmt)->m->get_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)
@@ -823,8 +818,6 @@
 #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))
 
-#define mysqlnd_stmt_fetch_into(s, f, ret)	(s)->m->fetch_into((s), (f), (ret)
TSRMLS_CC ZEND_FILE_LINE_CC)
-
 #define mysqlnd_stmt_fetch(stmt, fetched)	(stmt)->m->fetch((stmt), (fetched)
TSRMLS_CC)
 
 

Modified: trunk/mysqlnd/mysqlnd_ps.c
===================================================================
--- trunk/mysqlnd/mysqlnd_ps.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/mysqlnd/mysqlnd_ps.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -129,6 +129,61 @@
 /* }}} */
 
 
+/* {{{ mysqlnd_stmt::get_result */
+static MYSQLND_RES *
+MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const stmt TSRMLS_DC)
+{
+	MYSQLND *conn = stmt->conn;
+	MYSQLND_RES *result;
+
+	/* be compliant with libmysql - NULL will turn */
+	if (!stmt->field_count) {
+		return NULL;
+	}
+
+	if (stmt->cursor_exists) {
+		/* Silently convert buffered to unbuffered, for now */
+		return stmt->m->use_result(stmt TSRMLS_CC);
+	}
+
+	/* Nothing to store for UPSERT/LOAD DATA*/
+	if (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;
+	}
+
+	SET_EMPTY_ERROR(stmt->error_info);
+	SET_EMPTY_ERROR(stmt->conn->error_info);
+	MYSQLND_INC_CONN_STATISTIC(&conn->stats, STAT_BUFFERED_SETS);
+
+	result = mysqlnd_result_init(stmt->result->field_count,
+								 mysqlnd_palloc_get_thd_cache_reference(conn->zval_cache));	
+
+	result->meta =
stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE);
+
+	/* Not set for SHOW statements at PREPARE stage */
+	if (stmt->result->conn) {
+		stmt->result->conn->m->free_reference(stmt->result->conn TSRMLS_CC);
+		stmt->result->conn = NULL;	/* store result does not reference  the connection */
+	}
+
+	if ((result = result->m.store_result(result, conn, TRUE TSRMLS_CC))) {
+		stmt->upsert_status.affected_rows = result->data->row_count;	
+		stmt->state = MYSQLND_STMT_PREPARED;
+		result->type = MYSQLND_RES_PS;
+	} else {
+		stmt->error_info = conn->error_info;
+		stmt->state = MYSQLND_STMT_PREPARED;
+	}
+
+	return result;
+}
+/* }}} */
+
+
 /* {{{ mysqlnd_stmt_skip_metadata */
 static enum_func_status
 mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
@@ -317,7 +372,7 @@
 			  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
+			  in the following scenario
 			  prepare("select 1 from dual");
 			  execute();
 			  fetch(); <-- no binding, but that's not a problem
@@ -758,16 +813,8 @@
 		/* 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;
-	} else {
-		if (stmt->old_style_fetch == TRUE) {
-			SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
-						   "Cannot mix normal fetching with bound variables fetching");
-			return FAIL;
-		}
-		stmt->state = MYSQLND_STMT_USER_FETCHING;
 	}
-	stmt->old_style_fetch = FALSE;
+	stmt->state = MYSQLND_STMT_USER_FETCHING;
 
 	SET_EMPTY_ERROR(stmt->error_info);
 	SET_EMPTY_ERROR(stmt->conn->error_info);
@@ -1014,18 +1061,6 @@
 		return FAIL;
 	}
 
-	if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE &&
-		stmt->old_style_fetch == TRUE)
-	{
-		SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
-					   "Cannot mix bound variables fetching with normal fetching. "
-					   "Normal fetch already started.");
-		if (result_bind) {
-			efree(result_bind);
-		}
-		return FAIL;
-	}
-
 	if (stmt->field_count) {
 		if (!result_bind) {
 			return FAIL;
@@ -1158,7 +1193,9 @@
 {
 	MYSQLND_RES *result;
 
-	if (!stmt->field_count || !stmt->conn || !stmt->result) {
+	if (!stmt->field_count || !stmt->conn || !stmt->result ||
+		!stmt->result->meta)
+	{
 		return NULL;
 	}
 
@@ -1441,71 +1478,13 @@
 /* }}} */
 
 
-/* {{{ mysqlnd_stmt::fetch_into */
-static void
-MYSQLND_METHOD(mysqlnd_stmt, fetch_into)(MYSQLND_STMT *stmt, unsigned int flags,
-										 zval *return_value TSRMLS_DC ZEND_FILE_LINE_DC)
-{
-	zend_bool fetched_anything;
-
-	if (!stmt->result || stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
-		RETURN_NULL();
-	} else if (stmt->default_rset_handler == stmt->m->use_result) {
-		SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
-					   "Unbuffered old style fetching is not supported");
-		RETURN_NULL();		
-	} 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;
-		stmt->result->m.fetch_row = stmt->result->m.fetch_row_normal_buffered;
-		stmt->old_style_fetch = TRUE;
-	} else if (stmt->state == MYSQLND_STMT_USE_OR_STORE_CALLED) {
-		stmt->state = MYSQLND_STMT_USER_FETCHING;
-		stmt->result->m.fetch_row = stmt->result->m.fetch_row_normal_buffered;
-		stmt->old_style_fetch = TRUE;
-	} else {
-		if (stmt->old_style_fetch != TRUE) {
-			SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE,
-						   "Cannot mix binding with normal fetching");
-			RETURN_NULL();		
-		}	
-	}
-
-	SET_EMPTY_ERROR(stmt->error_info);
-	SET_EMPTY_ERROR(stmt->conn->error_info);
-	MYSQLND_INC_CONN_STATISTIC(&stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT);
-
-	/*
-	  Hint Zend how many elements we will have in the hash. Thus it won't
-	  extend and rehash the hash constantly.
-	*/
-	mysqlnd_array_init(return_value, mysqlnd_num_fields(stmt->result) * 2);
-	if (FAIL == stmt->result->m.fetch_row(stmt->result, (void *)return_value,
flags,
-										  &fetched_anything TSRMLS_CC))
-	{
-		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Error while reading a row");
-		RETURN_FALSE;
-	} else if (fetched_anything == FALSE) {
-		zval_dtor(return_value);
-		RETURN_NULL();
-	}
-	/*
-	  return_value is IS_NULL for no more data and an array for data. Thus it's ok
-	  to return here.
-	*/
-}
-/* }}} */
-
-
-
 static
 struct st_mysqlnd_stmt_methods mysqlnd_stmt_methods = {
 	MYSQLND_METHOD(mysqlnd_stmt, prepare),
 	MYSQLND_METHOD(mysqlnd_stmt, execute),
 	MYSQLND_METHOD(mysqlnd_stmt, use_result),
 	MYSQLND_METHOD(mysqlnd_stmt, store_result),
+	MYSQLND_METHOD(mysqlnd_stmt, get_result),
 	MYSQLND_METHOD(mysqlnd_stmt, free_result),
 	MYSQLND_METHOD(mysqlnd_stmt, data_seek),
 	MYSQLND_METHOD(mysqlnd_stmt, reset),
@@ -1513,7 +1492,6 @@
 	MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, dtor),
 
 	MYSQLND_METHOD(mysqlnd_stmt, fetch),
-	MYSQLND_METHOD(mysqlnd_stmt, fetch_into),
 
 	MYSQLND_METHOD(mysqlnd_stmt, bind_param),
 	MYSQLND_METHOD(mysqlnd_stmt, bind_result),

Modified: trunk/mysqlnd/mysqlnd_result.c
===================================================================
--- trunk/mysqlnd/mysqlnd_result.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/mysqlnd/mysqlnd_result.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -134,20 +134,14 @@
 /* }}} */
 
 
-
-
 /* {{{ mysqlnd_internal_free_result_contents */
+static
 void mysqlnd_internal_free_result_contents(MYSQLND_RES *result TSRMLS_DC)
 {
-
 	result->m.free_result_buffers(result TSRMLS_CC);
 
 	if (result->row_packet) {
-		if (result->type == MYSQLND_RES_NORMAL) {
-			PACKET_FREE(result->row_packet);
-		} else {
-			PACKET_FREE(result->row_packet);
-		}
+		PACKET_FREE(result->row_packet);
 		result->row_packet = NULL;
 	}
 
@@ -167,12 +161,13 @@
 
 
 /* {{{ mysqlnd_internal_free_result */
+static
 void mysqlnd_internal_free_result(MYSQLND_RES *result TSRMLS_DC)
 {
 	/*
 	  result->conn is an address if this is an unbuffered query.
 	  In this case, decrement the reference counter in the connection
-	  object and if needed free the latter. If quit_sent is no
+	  object and if needed free the latter.
 	*/
 	if (result->conn) {
 		result->conn->m->free_reference(result->conn TSRMLS_CC);
@@ -185,6 +180,7 @@
 /* }}} */
 
 
+/* {{{ mysqlnd_res::read_result_metadata */
 static enum_func_status
 MYSQLND_METHOD(mysqlnd_res, read_result_metadata)(MYSQLND_RES *result, MYSQLND *conn
TSRMLS_DC)
 {
@@ -192,7 +188,7 @@
 	  Make it safe to call it repeatedly for PS -
 	  better free and allocate a new because the number of field might change 
 	  (select *) with altered table. Also for statements which skip the PS
-	  infrastructure.
+	  infrastructure!
 	*/
 	if (result->meta) {
 		result->meta->m->free_metadata(result->meta, FALSE TSRMLS_CC);
@@ -218,6 +214,7 @@
 
 	return PASS;
 }
+/* }}} */
 
 
 /* {{{ mysqlnd_query_read_result_set_header */
@@ -392,7 +389,7 @@
 	/*
 	  If:
 	  - unbuffered result
-	  - first row hs not been read
+	  - first row has not been read
 	  - last_row has been read
 	*/
 	if (result->data->data_cursor == NULL ||
@@ -421,9 +418,8 @@
 /* }}} */
 
 
-/* {{{ _mysqlnd_fetch_lengths */
-PHPAPI unsigned long *
-MYSQLND_METHOD(mysqlnd_res, fetch_lengths)(MYSQLND_RES * const result)
+/* {{{ mysqlnd_res::fetch_lengths */
+PHPAPI unsigned long * mysqlnd_fetch_lengths(MYSQLND_RES * const result)
 {
 	return result->m.fetch_lengths? result->m.fetch_lengths(result):NULL;
 }
@@ -562,7 +558,7 @@
 
 /* {{{ mysqlnd_res::use_result */
 MYSQLND_RES *
-MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result TSRMLS_DC)
+MYSQLND_METHOD(mysqlnd_res, use_result)(MYSQLND_RES * const result, zend_bool ps
TSRMLS_DC)
 {
 	result->type			= MYSQLND_RES_NORMAL;
 	result->m.fetch_row		= result->m.fetch_row_normal_unbuffered;
@@ -663,6 +659,7 @@
 
 #define STORE_RESULT_PREALLOCATED_SET 32
 
+/* {{{ mysqlnd_store_result_fetch_data */
 enum_func_status
 mysqlnd_store_result_fetch_data(MYSQLND * const conn, MYSQLND_RES *result,
 								MYSQLND_RES_METADATA *meta,
@@ -770,12 +767,14 @@
 
 	return ret;
 }
+/* }}} */
 
 
-/* {{{ _mysqlnd_store_result */
+/* {{{ mysqlnd_res::store_result */
 MYSQLND_RES *
 MYSQLND_METHOD(mysqlnd_res, store_result)(MYSQLND_RES * result,
-										  MYSQLND * const conn TSRMLS_DC)
+										  MYSQLND * const conn,
+										  zend_bool ps_protocol TSRMLS_DC)
 {
 	enum_func_status ret;
 	zend_bool to_cache = FALSE;
@@ -790,7 +789,7 @@
 	result->lengths = ecalloc(result->field_count, sizeof(unsigned long));
 
 	ret = mysqlnd_store_result_fetch_data(conn, result, result->meta,
-										  FALSE, TRUE, to_cache TSRMLS_CC);
+										  ps_protocol, TRUE, to_cache TSRMLS_CC);
 	if (PASS == ret) {
 		/* libmysql's documentation says it should be so for SELECT statements */
 		conn->upsert_status.affected_rows = result->data->row_count;
@@ -1000,7 +999,6 @@
 
 	ret->field_count	= field_count;
 	ret->zval_cache		= cache;
-	ret->references		= 1;
 
 	ret->m.use_result	= MYSQLND_METHOD(mysqlnd_res, use_result);
 	ret->m.store_result	= MYSQLND_METHOD(mysqlnd_res, store_result);

Modified: trunk/php5/ext/mysqli/mysqli_fe.c
===================================================================
--- trunk/php5/ext/mysqli/mysqli_fe.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php5/ext/mysqli/mysqli_fe.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -148,6 +148,9 @@
 	PHP_FE(mysqli_stmt_bind_result,						second_arg_force_by_ref_rest)
 	PHP_FE(mysqli_stmt_fetch,							NULL)
 	PHP_FE(mysqli_stmt_free_result,						NULL)
+#if defined(HAVE_MYSQLND)
+	PHP_FE(mysqli_stmt_get_result,						NULL)
+#endif
 	PHP_FE(mysqli_stmt_get_warnings,					NULL)
 	PHP_FE(mysqli_stmt_insert_id,						NULL)
 	PHP_FE(mysqli_stmt_reset,							NULL)
@@ -301,6 +304,9 @@
 	PHP_FALIAS(reset,mysqli_stmt_reset,NULL)
 	PHP_FALIAS(prepare,mysqli_stmt_prepare, NULL)
 	PHP_FALIAS(store_result,mysqli_stmt_store_result,NULL)
+#if defined(HAVE_MYSQLND)
+	PHP_FALIAS(get_result,mysqli_stmt_get_result,NULL)
+#endif
 	{NULL, NULL, NULL}
 };
 /* }}} */

Modified: trunk/php5/ext/mysqli/mysqli_nonapi.c
===================================================================
--- trunk/php5/ext/mysqli/mysqli_nonapi.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php5/ext/mysqli/mysqli_nonapi.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -436,6 +436,36 @@
 }
 /* }}} */
 
+
+#if defined(HAVE_MYSQLND)
+/* {{{ proto object mysqli_stmt_get_result(object link) U
+   Buffer result set on client */
+PHP_FUNCTION(mysqli_stmt_get_result)
+{
+	MYSQL_RES 		*result;
+	MYSQLI_RESOURCE	*mysqli_resource;
+	MY_STMT			*stmt;
+	zval 			*mysql_stmt;
+
+	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
+		return;
+	}
+	MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt",
MYSQLI_STATUS_VALID);
+
+	if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
+		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
+		RETURN_FALSE;
+	}
+
+	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
+	mysqli_resource->ptr = (void *)result;
+	mysqli_resource->status = MYSQLI_STATUS_VALID;
+	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);	
+}
+/* }}} */
+#endif
+
+
 /* {{{ proto object mysqli_get_warnings(object link) */
 PHP_FUNCTION(mysqli_get_warnings)
 {

Modified: trunk/php5/ext/mysqli/php_mysqli.h
===================================================================
--- trunk/php5/ext/mysqli/php_mysqli.h	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php5/ext/mysqli/php_mysqli.h	2007-06-19 10:33:30 UTC (rev 397)
@@ -438,6 +438,9 @@
 PHP_FUNCTION(mysqli_stmt_errno);
 PHP_FUNCTION(mysqli_stmt_error);
 PHP_FUNCTION(mysqli_stmt_free_result);
+#if defined(HAVE_MYSQLND)
+PHP_FUNCTION(mysqli_stmt_get_result);
+#endif
 PHP_FUNCTION(mysqli_stmt_get_warnings);
 PHP_FUNCTION(mysqli_stmt_reset);
 PHP_FUNCTION(mysqli_stmt_insert_id);

Modified: trunk/php6/ext/mysqli/mysqli_api.c
===================================================================
--- trunk/php6/ext/mysqli/mysqli_api.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php6/ext/mysqli/mysqli_api.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -2308,6 +2308,7 @@
 }
 /* }}} */
 
+
 /* {{{ proto int mysqli_thread_id(object link) U
    Return the current thread ID */
 PHP_FUNCTION(mysqli_thread_id)

Modified: trunk/php6/ext/mysqli/mysqli_fe.c
===================================================================
--- trunk/php6/ext/mysqli/mysqli_fe.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php6/ext/mysqli/mysqli_fe.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -154,6 +154,9 @@
 	PHP_FE(mysqli_stmt_fetch,							NULL)
 	PHP_FE(mysqli_stmt_free_result,						NULL)
 	PHP_FE(mysqli_stmt_get_warnings,					NULL)
+#if defined(HAVE_MYSQLND)
+	PHP_FE(mysqli_stmt_get_result,						NULL)
+#endif
 	PHP_FE(mysqli_stmt_insert_id,						NULL)
 	PHP_FE(mysqli_stmt_reset,							NULL)
 	PHP_FE(mysqli_stmt_param_count,						NULL)
@@ -301,6 +304,7 @@
 	PHP_FALIAS(reset,mysqli_stmt_reset,NULL)
 	PHP_FALIAS(prepare,mysqli_stmt_prepare, NULL)
 	PHP_FALIAS(store_result,mysqli_stmt_store_result,NULL)
+	PHP_FALIAS(get_result,mysqli_stmt_get_result,NULL)
 	{NULL, NULL, NULL}
 };
 /* }}} */

Modified: trunk/php6/ext/mysqli/mysqli_nonapi.c
===================================================================
--- trunk/php6/ext/mysqli/mysqli_nonapi.c	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php6/ext/mysqli/mysqli_nonapi.c	2007-06-19 10:33:30 UTC (rev 397)
@@ -447,6 +447,36 @@
 }
 /* }}} */
 
+
+#if defined(HAVE_MYSQLND)
+/* {{{ proto object mysqli_stmt_get_result(object link) U
+   Buffer result set on client */
+PHP_FUNCTION(mysqli_stmt_get_result)
+{
+	MYSQL_RES 		*result;
+	MYSQLI_RESOURCE	*mysqli_resource;
+	MY_STMT			*stmt;
+	zval 			*mysql_stmt;
+
+	if (zend_parse_method_parameters(ZEND_NUM_ARGS() TSRMLS_CC, getThis(), "O",
&mysql_stmt, mysqli_stmt_class_entry) == FAILURE) {
+		return;
+	}
+	MYSQLI_FETCH_RESOURCE(stmt, MY_STMT *, &mysql_stmt, "mysqli_stmt",
MYSQLI_STATUS_VALID);
+
+	if (!(result = mysqlnd_stmt_get_result(stmt->stmt))) {
+		MYSQLI_REPORT_STMT_ERROR(stmt->stmt);
+		RETURN_FALSE;
+	}
+
+	mysqli_resource = (MYSQLI_RESOURCE *)ecalloc (1, sizeof(MYSQLI_RESOURCE));
+	mysqli_resource->ptr = (void *)result;
+	mysqli_resource->status = MYSQLI_STATUS_VALID;
+	MYSQLI_RETURN_RESOURCE(mysqli_resource, mysqli_result_class_entry);	
+}
+/* }}} */
+#endif
+
+
 /* {{{ proto object mysqli_get_warnings(object link) U */ 
 PHP_FUNCTION(mysqli_get_warnings)
 {

Modified: trunk/php6/ext/mysqli/php_mysqli.h
===================================================================
--- trunk/php6/ext/mysqli/php_mysqli.h	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/php6/ext/mysqli/php_mysqli.h	2007-06-19 10:33:30 UTC (rev 397)
@@ -447,6 +447,9 @@
 PHP_FUNCTION(mysqli_stmt_errno);
 PHP_FUNCTION(mysqli_stmt_error);
 PHP_FUNCTION(mysqli_stmt_free_result);
+#if defined(HAVE_MYSQLND)
+PHP_FUNCTION(mysqli_stmt_get_result);
+#endif
 PHP_FUNCTION(mysqli_stmt_get_warnings);
 PHP_FUNCTION(mysqli_stmt_reset);
 PHP_FUNCTION(mysqli_stmt_insert_id);

Modified: trunk/tests/ext/mysqli/002.phpt
===================================================================
--- trunk/tests/ext/mysqli/002.phpt	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/tests/ext/mysqli/002.phpt	2007-06-19 10:33:30 UTC (rev 397)
@@ -92,4 +92,4 @@
   [10]=>
   unicode(4) "1000"
 }
-done!
\ No newline at end of file
+done!

Added: trunk/tests/ext/mysqli/mysqli_stmt_get_result.phpt
===================================================================
--- trunk/tests/ext/mysqli/mysqli_stmt_get_result.phpt	2007-06-19 09:52:38 UTC (rev 396)
+++ trunk/tests/ext/mysqli/mysqli_stmt_get_result.phpt	2007-06-19 10:33:30 UTC (rev 397)
@@ -0,0 +1,178 @@
+--TEST--
+mysqli_stmt_get_result()
+--SKIPIF--
+<?php require_once('skipif.inc'); ?>
+<?php require_once('skipifemb.inc'); ?>
+<?php if (!function_exists('mysqli_stmt_get_result')) die('skip mysqli_stmt_get_result
not available')?>
+--FILE--
+<?php
+	/*
+	NOTE: no datatype tests here! This is done by
+	mysqli_stmt_bind_result.phpt already. Restrict
+	this test case to the basics.
+	*/	
+	include "connect.inc";
+
+	$tmp	= NULL;   
+	$link   = NULL;	
+	
+	if (!is_null($tmp = @mysqli_stmt_fetch()))
+		printf("[001] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);
+		
+	if (!is_null($tmp = @mysqli_stmt_fetch($link)))
+		printf("[002] Expecting NULL, got %s/%s\n", gettype($tmp), $tmp);		 
+	
+	require('table.inc');	
+	
+	if (!$stmt = mysqli_stmt_init($link))
+		printf("[003] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+		
+	// stmt object status test
+	if (NULL !== ($tmp = mysqli_stmt_fetch($stmt)))
+		printf("[004] Expecting NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));   
+		
+	if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+		printf("[005] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+		
+	// FIXME - different versions return different values ?!
+	if ((NULL !== ($tmp = mysqli_stmt_get_result($stmt))) && (false !== $tmp))
+		printf("[006] Expecting NULL or boolean/false, got %s/%s\n", gettype($tmp),
var_export($tmp, 1));
+	
+	if (!mysqli_stmt_execute($stmt)) 
+		printf("[007] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+	if (!mysqli_stmt_store_result($stmt)) 
+		printf("[008] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+		
+	if (is_object($tmp = mysqli_stmt_store_result($stmt)))
+		printf("[009] non-object, got %s/%s\n", gettype($tmp), var_export($tmp, 1));		
+		
+	mysqli_stmt_close($stmt);
+
+	if (!$stmt = mysqli_stmt_init($link))
+		printf("[010] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+		
+	// stmt object status test
+	if (NULL !== ($tmp = mysqli_stmt_fetch($stmt)))
+		printf("[011] Expecting NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));   
+		
+	if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+		printf("[012] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+		
+	// FIXME - different versions return different values ?!
+	if ((NULL !== ($tmp = mysqli_stmt_get_result($stmt))) && (false !== $tmp))
+		printf("[013] Expecting NULL or boolean/false, got %s/%s\n", gettype($tmp),
var_export($tmp, 1));
+	
+	if (!mysqli_stmt_execute($stmt)) 
+		printf("[014] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+		
+	if (!is_object($tmp = mysqli_stmt_get_result($stmt)))
+		printf("[016] NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));		
+
+	mysqli_free_result($tmp);
+	mysqli_stmt_close($stmt);
+
+	if (!$stmt = mysqli_stmt_init($link))
+		printf("[017] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+		
+	// stmt object status test
+	if (NULL !== ($tmp = mysqli_stmt_get_result($stmt)))
+		printf("[018] Expecting NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));   
+		
+	if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+		printf("[019] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+	if (false !== ($tmp = mysqli_stmt_get_result($stmt)))
+		printf("[020] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));   
+	
+	if (!mysqli_stmt_execute($stmt)) 
+		printf("[023] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+	if (!is_object($tmp = mysqli_stmt_get_result($stmt)))
+		printf("[024] Expecting object, got %s/%s\n", gettype($tmp), var_export($tmp, 1));   
+		
+	if (false !== ($tmp = mysqli_stmt_fetch($stmt)))
+		printf("[025] false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));		
+
+	if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label))) {
+		printf("[026] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+		printf("[027] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
+		printf("[028] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp,
1));
+	}
+
+	if (false !== ($tmp = mysqli_stmt_fetch($stmt)))
+		printf("[029] false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));		
+		
+	mysqli_stmt_close($stmt);
+
+	if (!$stmt = mysqli_stmt_init($link))
+		printf("[032] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+
+	if (!mysqli_stmt_prepare($stmt, "SELECT id, label FROM test ORDER BY id LIMIT 2"))
+		printf("[033] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));		   
+	  
+	if (!mysqli_stmt_execute($stmt)) 
+		printf("[034] [%d] %s\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+		
+	$id = NULL;
+	$label = NULL;	
+	if (true !== ($tmp = mysqli_stmt_bind_result($stmt, $id, $label))) 
+		printf("[035] Expecting boolean/true, got %s/%s\n", gettype($tmp), var_export($tmp,
1));
+		
+	if (!is_object($tmp = $result = mysqli_stmt_get_result($stmt)))
+		printf("[036] Expecting array, got %s/%s, [%d] %s\n", 
+			gettype($tmp), var_export($tmp, 1),
+			mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+	if (false !== ($tmp = mysqli_stmt_fetch($stmt)))
+		printf("[037] Expecting boolean/false, got %s/%s, [%d] %s\n", 
+			gettype($tmp), $tmp, mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+
+	printf("[038] [%d] [%s]\n", mysqli_stmt_errno($stmt), mysqli_stmt_error($stmt));
+	printf("[039] [%d] [%s]\n", mysqli_errno($link), mysqli_error($link));
+	while ($row = mysqli_fetch_assoc($result)) {
+		var_dump($row);
+	}
+	mysqli_free_result($result);
+		
+	if (!mysqli_kill($link, mysqli_thread_id($link)))
+		printf("[040] [%d] %s\n", mysqli_errno($link), mysqli_error($link));
+	
+	if (false !== ($tmp = mysqli_stmt_get_result($stmt))) 
+		printf("[041] Expecting false, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+				
+	mysqli_stmt_close($stmt);
+	
+	if (NULL !== ($tmp = mysqli_stmt_fetch($stmt))) 
+		printf("[042] Expecting NULL, got %s/%s\n", gettype($tmp), var_export($tmp, 1));
+		
+	mysqli_close($link);	
+	
+	print "done!\n";
+?>
+--EXPECTF--
+Warning: mysqli_stmt_fetch(): invalid object or resource mysqli_stmt
+ in %s on line %d
+
+Warning: mysqli_stmt_fetch(): invalid object or resource mysqli_stmt
+ in %s on line %d
+
+Warning: mysqli_stmt_get_result(): invalid object or resource mysqli_stmt
+ in %s on line %d
+[038] [0] []
+[039] [0] []
+array(2) {
+  ["id"]=>
+  int(1)
+  ["label"]=>
+  %s(1) "a"
+}
+array(2) {
+  ["id"]=>
+  int(2)
+  ["label"]=>
+  %s(1) "b"
+}
+
+Warning: mysqli_stmt_fetch(): Couldn't fetch mysqli_stmt in %s on line %d
+done! 

Thread
PHP mysqlnd svn commit: r397 - in trunk: mysqlnd php5/ext/mysqli php6/ext/mysqli tests/ext/mysqliahristov19 Jun