List:Commits« Previous MessageNext Message »
From:ahristov Date:April 18 2008 1:57am
Subject:PHP mysqlnd svn commit: r1497 - in trunk: mysqlnd php5/ext/mysqli php6/ext/mysqli tests/ext/mysqli
View as plain text  
Author: ahristov
Date: 2008-04-18 03:57:48 +0200 (Fri, 18 Apr 2008)
New Revision: 1497

Modified:
   trunk/mysqlnd/mysqlnd.c
   trunk/mysqlnd/mysqlnd.h
   trunk/mysqlnd/mysqlnd_enum_n_def.h
   trunk/mysqlnd/mysqlnd_priv.h
   trunk/mysqlnd/mysqlnd_ps.c
   trunk/mysqlnd/mysqlnd_result.c
   trunk/mysqlnd/mysqlnd_structs.h
   trunk/mysqlnd/mysqlnd_wireprotocol.c
   trunk/php5/ext/mysqli/mysqli_api.c
   trunk/php5/ext/mysqli/mysqli_fe.c
   trunk/php5/ext/mysqli/php_mysqli_structs.h
   trunk/php6/ext/mysqli/mysqli_api.c
   trunk/php6/ext/mysqli/mysqli_fe.c
   trunk/php6/ext/mysqli/php_mysqli_structs.h
   trunk/tests/ext/mysqli/mysqli_class_mysqli_stmt_interface.phpt
Log:
Added mysqlnd_stmt_more_results() and mysqlnd_stmt_next_result()

The corresponding mysqli_stmt_more_results() and mysqli_stmt_next_result()
are not available for libmysql builds as libmysql doesn't provide the API.
The sole reason for not providing the API is that libmysql can't handle,
not programmed, multiple result sets coming as a result of a prepared
statement (like CALL()).

I hope these two new functions will be helpful to pdo_mysqlnd.


Modified: trunk/mysqlnd/mysqlnd.c
===================================================================
--- trunk/mysqlnd/mysqlnd.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -1665,10 +1665,11 @@
 
 /* {{{ mysqlnd_conn::more_results */
 static zend_bool
-MYSQLND_METHOD(mysqlnd_conn, more_results)(const MYSQLND * const conn)
+MYSQLND_METHOD(mysqlnd_conn, more_results)(const MYSQLND * const conn TSRMLS_DC)
 {
+	DBG_ENTER("mysqlnd_conn::more_results");
 	/* (conn->state == CONN_NEXT_RESULT_PENDING) too */
-	return conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS?
TRUE:FALSE;
+	DBG_RETURN(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS?
TRUE:FALSE);
 }
 /* }}} */
 

Modified: trunk/mysqlnd/mysqlnd.h
===================================================================
--- trunk/mysqlnd/mysqlnd.h	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd.h	2008-04-18 01:57:48 UTC (rev 1497)
@@ -116,7 +116,7 @@
 #define mysqlnd_store_result(conn)		(conn)->m->store_result((conn) TSRMLS_CC)
 #define mysqlnd_bg_store_result(conn) 	(conn)->m->background_store_result((conn)
TSRMLS_CC)
 #define mysqlnd_next_result(conn)		(conn)->m->next_result((conn) TSRMLS_CC)
-#define mysqlnd_more_results(conn)		(conn)->m->more_results((conn))
+#define mysqlnd_more_results(conn)		(conn)->m->more_results((conn) TSRMLS_CC)
 #define
mysqlnd_free_result(r,e_or_i)	((MYSQLND_RES*)r)->m.free_result(((MYSQLND_RES*)(r)),
(e_or_i) TSRMLS_CC)
 #define mysqlnd_data_seek(result, row)	(result)->m.seek_data((result), (row)
TSRMLS_CC)
 
@@ -266,6 +266,8 @@
 #define mysqlnd_stmt_store_result(stmt)		(!mysqlnd_stmt_field_count((stmt)) ?
PASS:((stmt)->m->store_result((stmt) TSRMLS_CC)? PASS:FAIL))
 #define mysqlnd_stmt_bg_store_result(stmt)	(!mysqlnd_stmt_field_count((stmt)) ?
PASS:((stmt)->m->background_store_result((stmt) TSRMLS_CC)? PASS:FAIL))
 #define mysqlnd_stmt_get_result(stmt)		(stmt)->m->get_result((stmt) TSRMLS_CC)
+#define mysqlnd_stmt_more_results(stmt)		(stmt)->m->more_results((stmt) TSRMLS_CC)
+#define mysqlnd_stmt_next_result(stmt)		(stmt)->m->next_result((stmt) TSRMLS_CC)
 #define mysqlnd_stmt_data_seek(stmt, row)	(stmt)->m->seek_data((stmt), (row)
TSRMLS_CC)
 #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)

Modified: trunk/mysqlnd/mysqlnd_enum_n_def.h
===================================================================
--- trunk/mysqlnd/mysqlnd_enum_n_def.h	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd_enum_n_def.h	2008-04-18 01:57:48 UTC (rev 1497)
@@ -28,9 +28,27 @@
 #define MYSQLND_SQLSTATE_LENGTH		5
 #define MYSQLND_SQLSTATE_NULL		"00000"
 
+#define SERVER_STATUS_IN_TRANS					1	/* Transaction has started */
+#define SERVER_STATUS_AUTOCOMMIT				2	/* Server in auto_commit mode */
+#define SERVER_MORE_RESULTS_EXISTS				8	/* Multi query - next query exists */
 #define MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED	16
 #define MYSQLND_SERVER_QUERY_NO_INDEX_USED		32
+/*
+  The server was able to fulfill the clients request and opened a
+  read-only non-scrollable cursor for a query. This flag comes
+  in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
+*/
+#define SERVER_STATUS_CURSOR_EXISTS				64
+/*
+  This flag is sent when a read-only cursor is exhausted, in reply to
+  COM_STMT_FETCH command.
+*/
+#define SERVER_STATUS_LAST_ROW_SENT				128
+#define SERVER_STATUS_DB_DROPPED				256 /* A database was dropped */
+#define SERVER_STATUS_NO_BACKSLASH_ESCAPES		512
+#define SERVER_QUERY_WAS_SLOW					1024
 
+
 #define MYSQLND_NO_DATA			100
 #define MYSQLND_DATA_TRUNCATED	101
 

Modified: trunk/mysqlnd/mysqlnd_priv.h
===================================================================
--- trunk/mysqlnd/mysqlnd_priv.h	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd_priv.h	2008-04-18 01:57:48 UTC (rev 1497)
@@ -74,23 +74,6 @@
 
 
 
-#define SERVER_STATUS_IN_TRANS				1	/* Transaction has started */
-#define SERVER_STATUS_AUTOCOMMIT			2	/* Server in auto_commit mode */
-#define SERVER_MORE_RESULTS_EXISTS			8	/* Multi query - next query exists */
-/*
-  The server was able to fulfill the clients request and opened a
-  read-only non-scrollable cursor for a query. This flag comes
-  in reply to COM_STMT_EXECUTE and COM_STMT_FETCH commands.
-*/
-#define SERVER_STATUS_CURSOR_EXISTS			64
-/*
-  This flag is sent when a read-only cursor is exhausted, in reply to
-  COM_STMT_FETCH command.
-*/
-#define SERVER_STATUS_LAST_ROW_SENT			128
-#define SERVER_STATUS_DB_DROPPED			256 /* A database was dropped */
-#define SERVER_STATUS_NO_BACKSLASH_ESCAPES	512
-#define SERVER_QUERY_WAS_SLOW				1024
 
 
 /* Client Error codes */

Modified: trunk/mysqlnd/mysqlnd_ps.c
===================================================================
--- trunk/mysqlnd/mysqlnd_ps.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd_ps.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -59,6 +59,8 @@
 static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
 static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, uint
param_no TSRMLS_DC);
 
+static void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC);
+static enum_func_status mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt
TSRMLS_DC);
 
 /* {{{ mysqlnd_stmt::store_result */
 static MYSQLND_RES *
@@ -253,6 +255,45 @@
 /* }}} */
 
 
+/* {{{ mysqlnd_stmt::more_results */
+static zend_bool
+MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * stmt TSRMLS_DC)
+{
+	DBG_ENTER("mysqlnd_stmt::more_results");
+	/* (conn->state == CONN_NEXT_RESULT_PENDING) too */
+	DBG_RETURN((stmt->conn && (stmt->conn->upsert_status.server_status
&
+							   SERVER_MORE_RESULTS_EXISTS))?
+									TRUE:
+									FALSE);
+}
+/* }}} */
+
+
+/* {{{ mysqlnd_stmt::next_result */
+static enum_func_status
+MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * stmt TSRMLS_DC)
+{
+	MYSQLND *conn = stmt->conn;
+
+	DBG_ENTER("mysqlnd_stmt::next_result");
+	DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
+
+	if (!conn ||
+		CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING ||
+		!(conn->upsert_status.server_status & SERVER_MORE_RESULTS_EXISTS) ||
+		!stmt->result)
+	{
+		DBG_RETURN(FAIL);
+	}
+
+	/* Free space for next result */
+	mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
+
+	DBG_RETURN(mysqlnd_stmt_execute_parse_response(stmt TSRMLS_CC));
+}
+/* }}} */
+
+
 /* {{{ mysqlnd_stmt_skip_metadata */
 static enum_func_status
 mysqlnd_stmt_skip_metadata(MYSQLND_STMT *stmt TSRMLS_DC)
@@ -441,6 +482,92 @@
 /* }}} */
 
 
+/* {{{ mysqlnd_stmt_execute_parse_response */
+static enum_func_status
+mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const stmt TSRMLS_DC)
+{
+	enum_func_status ret;
+	MYSQLND	*conn = stmt->conn;
+
+	DBG_ENTER("mysqlnd_stmt_execute_parse_response");
+
+	CONN_SET_STATE(conn, CONN_QUERY_SENT);
+
+	ret = mysqlnd_query_read_result_set_header(stmt->conn, stmt TSRMLS_CC);
+	if (ret == FAIL) {
+		stmt->error_info = conn->error_info;
+		stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
+		if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
+			/* close the statement here, the connection has been closed */
+		}
+		stmt->state = MYSQLND_STMT_PREPARED;
+	} else {
+		SET_EMPTY_ERROR(stmt->error_info);
+		SET_EMPTY_ERROR(stmt->conn->error_info);
+		stmt->send_types_to_server = 0;
+		stmt->upsert_status = conn->upsert_status;
+		stmt->state = MYSQLND_STMT_EXECUTED;
+		if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type ==
QUERY_LOAD_LOCAL) {
+			DBG_INF("PASS");
+			DBG_RETURN(PASS);
+		}
+
+		stmt->result->type = MYSQLND_RES_PS_BUF;
+		if (!stmt->result->conn) {
+			/*
+			  For SHOW we don't create (bypasses PS in server)
+			  a result set at prepare and thus a connection was missing
+			*/
+			stmt->result->conn = stmt->conn->m->get_reference(stmt->conn
TSRMLS_CC);
+		}
+
+		/* Update stmt->field_count as SHOW sets it to 0 at prepare */
+		stmt->field_count = stmt->result->field_count = conn->field_count;
+		stmt->result->lengths = NULL;
+		if (stmt->field_count) {
+			stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
+			/*
+			  We need to set this because the user might not call
+			  use_result() or store_result() and we should be able to scrap the
+			  data on the line, if he just decides to close the statement.
+			*/
+			DBG_INF_FMT("server_status=%d cursor=%d", stmt->upsert_status.server_status,
+						stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
+
+			if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
+				stmt->cursor_exists = TRUE;
+				CONN_SET_STATE(conn, CONN_READY);
+				/* Only cursor read */
+				stmt->default_rset_handler = stmt->m->use_result;
+				DBG_INF("use_result");
+			} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
+				/*
+				  We have asked for CURSOR but got no cursor, because the condition
+				  above is not fulfilled. Then...
+
+				  This is a single-row result set, a result set with no rows, EXPLAIN,
+				  SHOW VARIABLES, or some other command which either a) bypasses the
+				  cursors framework in the server and writes rows directly to the
+				  network or b) is more efficient if all (few) result set rows are
+				  precached on client and server's resources are freed.
+				*/
+				/* preferred is buffered read */
+				stmt->default_rset_handler = stmt->m->store_result;
+				DBG_INF("store_result");
+			} else {
+				/* preferred is unbuffered read */
+				stmt->default_rset_handler = stmt->m->use_result;
+				DBG_INF("use_result");
+			}
+		}
+	}
+
+	DBG_INF(ret == PASS? "PASS":"FAIL");
+	DBG_RETURN(ret);
+}
+/* }}} */
+
+
 /* {{{ mysqlnd_stmt::execute */
 static enum_func_status
 MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const stmt TSRMLS_DC)
@@ -570,79 +697,7 @@
 	}
 	stmt->execute_count++;
 
-	CONN_SET_STATE(conn, CONN_QUERY_SENT);
-
-	ret = mysqlnd_query_read_result_set_header(stmt->conn, stmt TSRMLS_CC);
-	if (ret == FAIL) {
-		stmt->error_info = conn->error_info;
-		stmt->upsert_status.affected_rows = conn->upsert_status.affected_rows;
-		if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
-			/* close the statement here, the connection has been closed */
-		}
-		stmt->state = MYSQLND_STMT_PREPARED;
-	} else {
-		SET_EMPTY_ERROR(stmt->error_info);
-		SET_EMPTY_ERROR(stmt->conn->error_info);
-		stmt->send_types_to_server = 0;
-		stmt->upsert_status = conn->upsert_status;
-		stmt->state = MYSQLND_STMT_EXECUTED;
-		if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type ==
QUERY_LOAD_LOCAL) {
-			DBG_INF("PASS");
-			DBG_RETURN(PASS);
-		}
-
-		stmt->result->type = MYSQLND_RES_PS_BUF;
-		if (!stmt->result->conn) {
-			/*
-			  For SHOW we don't create (bypasses PS in server)
-			  a result set at prepare and thus a connection was missing
-			*/
-			stmt->result->conn = stmt->conn->m->get_reference(stmt->conn
TSRMLS_CC);
-		}
-
-		/* Update stmt->field_count as SHOW sets it to 0 at prepare */
-		stmt->field_count = stmt->result->field_count = conn->field_count;
-		stmt->result->lengths = NULL;
-		if (stmt->field_count) {
-			stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
-			/*
-			  We need to set this because the user might not call
-			  use_result() or store_result() and we should be able to scrap the
-			  data on the line, if he just decides to close the statement.
-			*/
-			DBG_INF_FMT("server_status=%d cursor=%d", stmt->upsert_status.server_status,
-						stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS);
-
-			if (stmt->upsert_status.server_status & SERVER_STATUS_CURSOR_EXISTS) {
-				stmt->cursor_exists = TRUE;
-				CONN_SET_STATE(conn, CONN_READY);
-				/* Only cursor read */
-				stmt->default_rset_handler = stmt->m->use_result;
-				DBG_INF("use_result");
-			} else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
-				/*
-				  We have asked for CURSOR but got no cursor, because the condition
-				  above is not fulfilled. Then...
-
-				  This is a single-row result set, a result set with no rows, EXPLAIN,
-				  SHOW VARIABLES, or some other command which either a) bypasses the
-				  cursors framework in the server and writes rows directly to the
-				  network or b) is more efficient if all (few) result set rows are
-				  precached on client and server's resources are freed.
-				*/
-				/* preferred is buffered read */
-				stmt->default_rset_handler = stmt->m->store_result;
-				DBG_INF("store_result");
-			} else {
-				/* preferred is unbuffered read */
-				stmt->default_rset_handler = stmt->m->use_result;
-				DBG_INF("use_result");
-			}
-		}
-	}
-
-	DBG_INF(ret == PASS? "PASS":"FAIL");
-	DBG_RETURN(ret);
+	DBG_RETURN(mysqlnd_stmt_execute_parse_response(stmt TSRMLS_CC));
 }
 /* }}} */
 
@@ -1016,7 +1071,7 @@
 		stmt->conn->upsert_status.server_status =
 			row_packet->server_status;
 
-	DBG_INF_FMT("ret=%s fetched=%d s_status=%d warns=%d eof=%d",
+	DBG_INF_FMT("ret=%s fetched=%d server_status=%d warnings=%d eof=%d",
 				ret == PASS? "PASS":"FAIL", *fetched_anything,
 				row_packet->server_status, row_packet->warning_count,
 				result->unbuf->eof_reached);
@@ -1701,7 +1756,7 @@
 
 /* {{{ mysqlnd_stmt::attr_get */
 static enum_func_status
-MYSQLND_METHOD(mysqlnd_stmt, attr_get)(MYSQLND_STMT * const stmt,
+MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const stmt,
 									   enum mysqlnd_stmt_attr attr_type,
 									   void * const value TSRMLS_DC)
 {
@@ -1876,9 +1931,10 @@
 }
 /* }}} */
 
+
 /* {{{ mysqlnd_internal_free_stmt_content */
 static
-void mysqlnd_internal_free_stmt_content(MYSQLND_STMT *stmt TSRMLS_DC)
+void mysqlnd_internal_free_stmt_content(MYSQLND_STMT * const stmt TSRMLS_DC)
 {
 	DBG_ENTER("mysqlnd_internal_free_stmt_content");
 	DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u",
@@ -1917,16 +1973,7 @@
 		stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
 		stmt->result = NULL;
 	}
-	if (stmt->execute_cmd_buffer.buffer) {
-		mnd_efree(stmt->execute_cmd_buffer.buffer);
-		stmt->execute_cmd_buffer.buffer = NULL;
-	}
 
-	if (stmt->conn) {
-		stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
-		stmt->conn = NULL;
-	}
-
 	DBG_VOID_RETURN;
 }
 /* }}} */
@@ -1993,8 +2040,18 @@
 		MYSQLND_INC_CONN_STATISTIC(&conn->stats, stat);
 	}
 
+	if (stmt->execute_cmd_buffer.buffer) {
+		mnd_efree(stmt->execute_cmd_buffer.buffer);
+		stmt->execute_cmd_buffer.buffer = NULL;
+	}
+
 	mysqlnd_internal_free_stmt_content(stmt TSRMLS_CC);
 
+	if (stmt->conn) {
+		stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
+		stmt->conn = NULL;
+	}
+
 	DBG_RETURN(PASS);
 }
 /* }}} */
@@ -2028,6 +2085,8 @@
 	MYSQLND_METHOD(mysqlnd_stmt, store_result),
 	MYSQLND_METHOD(mysqlnd_stmt, background_store_result),
 	MYSQLND_METHOD(mysqlnd_stmt, get_result),
+	MYSQLND_METHOD(mysqlnd_stmt, more_results),
+	MYSQLND_METHOD(mysqlnd_stmt, next_result),
 	MYSQLND_METHOD(mysqlnd_stmt, free_result),
 	MYSQLND_METHOD(mysqlnd_stmt, data_seek),
 	MYSQLND_METHOD(mysqlnd_stmt, reset),

Modified: trunk/mysqlnd/mysqlnd_result.c
===================================================================
--- trunk/mysqlnd/mysqlnd_result.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd_result.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -582,8 +582,15 @@
 						stmt->state = MYSQLND_STMT_INITTED;
 					}
 				} else {
-					DBG_INF_FMT("warns=%u status=%u", fields_eof.warning_count,
fields_eof.server_status);
+					DBG_INF_FMT("warnings=%u server_status=%u", fields_eof.warning_count,
fields_eof.server_status);
 					conn->upsert_status.warning_count = fields_eof.warning_count;
+					/*
+					  If SERVER_MORE_RESULTS_EXISTS is set then this is either MULTI_QUERY or a CALL()
+					  The first packet after sending the query/com_execute has the bit set only
+					  in this cases. Not sure why it's a needed but it marks that the whole stream
+					  will include many result sets. What actually matters are the bits set at the end
+					  of every result set (the EOF packet).
+					*/
 					conn->upsert_status.server_status = fields_eof.server_status;
 					if (fields_eof.server_status & MYSQLND_SERVER_QUERY_NO_GOOD_INDEX_USED) {
 						stat = STAT_BAD_INDEX_USED;
@@ -791,7 +798,7 @@
 		result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
 	} else if (row_packet->eof) {
 		/* Mark the connection as usable again */
-		DBG_INF_FMT("warns=%u status=%u", row_packet->warning_count,
row_packet->server_status);
+		DBG_INF_FMT("warningss=%u server_status=%u", row_packet->warning_count,
row_packet->server_status);
 		result->unbuf->eof_reached = TRUE;
 		result->conn->upsert_status.warning_count = row_packet->warning_count;
 		result->conn->upsert_status.server_status = row_packet->server_status;
@@ -931,7 +938,7 @@
 		result->unbuf->eof_reached = TRUE; /* so next time we won't get an error */
 	} else if (row_packet->eof) {
 		/* Mark the connection as usable again */
-		DBG_INF_FMT("warns=%u status=%u", row_packet->warning_count,
row_packet->server_status);
+		DBG_INF_FMT("warnings=%u server_status=%u", row_packet->warning_count,
row_packet->server_status);
 		result->unbuf->eof_reached = TRUE;
 		result->conn->upsert_status.warning_count = row_packet->warning_count;
 		result->conn->upsert_status.server_status = row_packet->server_status;
@@ -1263,7 +1270,7 @@
 	}
 	PACKET_FREE(row_packet);
 
-	DBG_INF_FMT("ret=%s row_count=%u warns=%u status=%u", ret == PASS? "PASS":"FAIL",
+	DBG_INF_FMT("ret=%s row_count=%u warnings=%u server_status=%u", ret == PASS?
"PASS":"FAIL",
 				set->row_count, conn->upsert_status.warning_count,
conn->upsert_status.server_status);
 	DBG_RETURN(ret);
 }
@@ -1558,7 +1565,7 @@
 	} else {
 		CONN_SET_STATE(conn, CONN_READY);
 	}
-	DBG_INF_FMT("ret=%s row_count=%u warns=%u status=%u", ret == PASS? "PASS":"FAIL",
+	DBG_INF_FMT("ret=%s row_count=%u warnings=%u server_status=%u", ret == PASS?
"PASS":"FAIL",
 				set->row_count, conn->upsert_status.warning_count,
conn->upsert_status.server_status);
 	DBG_RETURN(ret);
 }

Modified: trunk/mysqlnd/mysqlnd_structs.h
===================================================================
--- trunk/mysqlnd/mysqlnd_structs.h	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd_structs.h	2008-04-18 01:57:48 UTC (rev 1497)
@@ -243,7 +243,7 @@
 	MYSQLND_RES *		(*store_result)(MYSQLND * const conn TSRMLS_DC);
 	MYSQLND_RES *		(*background_store_result)(MYSQLND * const conn TSRMLS_DC);
 	enum_func_status	(*next_result)(MYSQLND * const conn TSRMLS_DC);
-	zend_bool			(*more_results)(const MYSQLND * const conn);
+	zend_bool			(*more_results)(const MYSQLND * const conn TSRMLS_DC);
 
 	MYSQLND_STMT *		(*stmt_init)(MYSQLND * const conn TSRMLS_DC);
 
@@ -346,6 +346,8 @@
 	MYSQLND_RES *		(*store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
 	MYSQLND_RES *		(*background_store_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
 	MYSQLND_RES *		(*get_result)(MYSQLND_STMT * const stmt TSRMLS_DC);
+	zend_bool			(*more_results)(const MYSQLND_STMT * const stmt TSRMLS_DC);
+	enum_func_status	(*next_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, uint64 row TSRMLS_DC);
 	enum_func_status	(*reset)(MYSQLND_STMT * const stmt TSRMLS_DC);
@@ -378,7 +380,7 @@
 	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 TSRMLS_DC);
+	enum_func_status	(*get_attribute)(const MYSQLND_STMT * const stmt, enum
mysqlnd_stmt_attr attr_type, void * const value TSRMLS_DC);
 	enum_func_status	(*set_attribute)(MYSQLND_STMT * const stmt, enum mysqlnd_stmt_attr
attr_type, const void * const value TSRMLS_DC);
 };
 

Modified: trunk/mysqlnd/mysqlnd_wireprotocol.c
===================================================================
--- trunk/mysqlnd/mysqlnd_wireprotocol.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/mysqlnd/mysqlnd_wireprotocol.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -587,6 +587,13 @@
 	} else {
 		packet->pre41 = TRUE;
 	}
+
+	DBG_INF_FMT("proto=%d server=%s thread_id=%ld",
+				packet->protocol_version, packet->server_version, packet->thread_id);
+
+	DBG_INF_FMT("server_capabilities=%d charset_no=%d server_status=%d",
+				packet->server_capabilities, packet->charset_no, packet->server_status);
+
 	if (p - begin > packet->header.size) {
 		DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin -
packet->header.size);
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet %d bytes shorter than
expected. PID=%d",
@@ -783,8 +790,8 @@
 	}
 
 	DBG_INF_FMT("OK packet: aff_rows=%lld last_ins_id=%ld server_status=%d warnings=%d",
-					packet->affected_rows, packet->last_insert_id, packet->server_status,
-					packet->warning_count);
+				packet->affected_rows, packet->last_insert_id, packet->server_status,
+				packet->warning_count);
 
 	if (p - begin > packet->header.size) {
 		DBG_ERR_FMT("OK packet %d bytes shorter than expected", p - begin -
packet->header.size);
@@ -865,7 +872,8 @@
 						 p - begin - packet->header.size, getpid());
 	}
 	
-	DBG_INF_FMT("EOF packet: status=%d warnings=%d", packet->server_status,
packet->warning_count);
+	DBG_INF_FMT("EOF packet: fields=%d status=%d warnings=%d",
+				packet->field_count, packet->server_status, packet->warning_count);
 
 	DBG_RETURN(PASS);
 }
@@ -986,6 +994,7 @@
 	packet->field_count= php_mysqlnd_net_field_length(&p);
 	switch (packet->field_count) {
 		case MYSQLND_NULL_LENGTH:
+			DBG_INF("LOAD LOCAL");
 			/*
 			  First byte in the packet is the field count.
 			  Thus, the name is size - 1. And we add 1 for a trailing \0.
@@ -997,6 +1006,7 @@
 			packet->info_or_local_file_len = len;
 			break;
 		case 0x00:
+			DBG_INF("UPSERT");
 			packet->affected_rows = php_mysqlnd_net_field_length_ll(&p);
 			packet->last_insert_id= php_mysqlnd_net_field_length_ll(&p);
 			packet->server_status = uint2korr(p);
@@ -1010,13 +1020,17 @@
 				packet->info_or_local_file[len] = '\0';
 				packet->info_or_local_file_len = len;
 			}
+			DBG_INF_FMT("affected_rows=%llu last_insert_id=%llu server_status=%d
warning_count=%d",
+						packet->affected_rows, packet->last_insert_id,
+						packet->server_status, packet->warning_count);
 			break;
 		default:
+			DBG_INF("SELECT");
 			/* Result set */
 			break;
 	}
 	if (p - begin > packet->header.size) {
-		DBG_ERR_FMT("GREET packet %d bytes shorter than expected", p - begin -
packet->header.size);
+		DBG_ERR_FMT("RSET_HEADER packet %d bytes shorter than expected", p - begin -
packet->header.size);
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "GREET packet %d bytes shorter than
expected. PID=%d",
 						 p - begin - packet->header.size, getpid());
 	}
@@ -1097,7 +1111,7 @@
 				*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = 0;
 				break;
 			case MYSQLND_NULL_LENGTH:
-				goto faulty_fake;
+				goto faulty_or_fake;
 			default:
 				*(char **)(((char *)meta) + rset_field_offsets[i]) = (char *)p;
 				*(unsigned int *)(((char*)meta) + rset_field_offsets[i+1]) = len;
@@ -1156,7 +1170,7 @@
 	}
 
 	if (p - begin > packet->header.size) {
-		DBG_ERR_FMT("Result set field packet %d bytes shorter than expected", p - begin -
packet->header.size);
+		DBG_ERR_FMT("RSET field packet %d bytes shorter than expected", p - begin -
packet->header.size);
 		php_error_docref(NULL TSRMLS_CC, E_WARNING, "Result set field packet %d bytes "
 						 "shorter than expected. PID=%d", p - begin - packet->header.size, getpid());
 	}
@@ -1210,7 +1224,7 @@
 */
 	DBG_RETURN(PASS);
 
-faulty_fake:
+faulty_or_fake:
 	DBG_ERR_FMT("Protocol error. Server sent NULL_LENGTH. The server is faulty");
 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Protocol error. Server sent NULL_LENGTH."
 					 " The server is faulty");
@@ -1629,6 +1643,8 @@
 			p += 2;
 			packet->server_status = uint2korr(p);
 			/* Seems we have 3 bytes reserved for future use */
+			DBG_INF_FMT("server_status=%d warning_count=%d",
+						packet->server_status, packet->warning_count);
 		}
 	} else {
 		MYSQLND_INC_CONN_STATISTIC(&conn->stats,

Modified: trunk/php5/ext/mysqli/mysqli_api.c
===================================================================
--- trunk/php5/ext/mysqli/mysqli_api.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/php5/ext/mysqli/mysqli_api.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -1471,6 +1471,48 @@
 }
 /* }}} */
 
+
+#ifdef MYSQLI_USE_MYSQLND
+/* {{{ proto bool mysqli_stmt_next_result(object link)
+   check if there any more query results from a multi query */
+PHP_FUNCTION(mysqli_stmt_more_results)
+{
+	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);
+
+	RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
+}
+/* }}} */
+
+
+/* {{{ proto bool mysqli_stmt_next_result(object link)
+   read next result from multi_query */
+PHP_FUNCTION(mysqli_stmt_next_result) {
+	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 (!mysqlnd_stmt_more_results(stmt->stmt)) {
+		php_error_docref(NULL TSRMLS_CC, E_STRICT, "There is no next result set. "
+						"Please, call mysqli_stmt_more_results()/mysqli_stmt::more_results() to check "
+						"whether to call this function/method");
+	}
+
+	RETURN_BOOL(!mysqlnd_stmt_next_result(stmt->stmt));
+}
+/* }}} */
+#endif
+
+
 /* {{{ proto int mysqli_num_fields(object result)
    Get number of fields in result */
 PHP_FUNCTION(mysqli_num_fields)

Modified: trunk/php5/ext/mysqli/mysqli_fe.c
===================================================================
--- trunk/php5/ext/mysqli/mysqli_fe.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/php5/ext/mysqli/mysqli_fe.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -161,6 +161,10 @@
 	PHP_FE(mysqli_stmt_data_seek,						NULL)
 	PHP_FE(mysqli_stmt_errno,							NULL)
 	PHP_FE(mysqli_stmt_error,							NULL)
+#if defined(MYSQLI_USE_MYSQLND)
+	PHP_FE(mysqli_stmt_more_results,					NULL)
+	PHP_FE(mysqli_stmt_next_result,						NULL)
+#endif
 	PHP_FE(mysqli_stmt_num_rows,						NULL)
 	PHP_FE(mysqli_stmt_sqlstate,   						NULL)
 	PHP_FE(mysqli_stmt_store_result,					NULL)
@@ -289,6 +293,10 @@
 	PHP_FALIAS(get_warnings, mysqli_stmt_get_warnings,	NULL)
 	PHP_FALIAS(result_metadata, mysqli_stmt_result_metadata,NULL)
 	PHP_FALIAS(num_rows, mysqli_stmt_num_rows,NULL)
+#if defined(MYSQLI_USE_MYSQLND)
+	PHP_FALIAS(more_results, mysqli_stmt_more_results, NULL)
+	PHP_FALIAS(next_result, mysqli_stmt_next_result, NULL)
+#endif
 	PHP_FALIAS(send_long_data,mysqli_stmt_send_long_data,NULL)
 	PHP_FALIAS(stmt,mysqli_prepare,NULL)
 	PHP_FALIAS(free_result,mysqli_stmt_free_result,NULL)

Modified: trunk/php5/ext/mysqli/php_mysqli_structs.h
===================================================================
--- trunk/php5/ext/mysqli/php_mysqli_structs.h	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/php5/ext/mysqli/php_mysqli_structs.h	2008-04-18 01:57:48 UTC (rev 1497)
@@ -489,6 +489,8 @@
 PHP_FUNCTION(mysqli_stmt_get_warnings);
 PHP_FUNCTION(mysqli_stmt_reset);
 PHP_FUNCTION(mysqli_stmt_insert_id);
+PHP_FUNCTION(mysqli_stmt_more_results);
+PHP_FUNCTION(mysqli_stmt_next_result);
 PHP_FUNCTION(mysqli_stmt_num_rows);
 PHP_FUNCTION(mysqli_stmt_sqlstate);
 PHP_FUNCTION(mysqli_stmt_store_result);

Modified: trunk/php6/ext/mysqli/mysqli_api.c
===================================================================
--- trunk/php6/ext/mysqli/mysqli_api.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/php6/ext/mysqli/mysqli_api.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -1529,6 +1529,48 @@
 }
 /* }}} */
 
+
+#ifdef MYSQLI_USE_MYSQLND
+/* {{{ proto bool mysqli_stmt_next_result(object link)
+   check if there any more query results from a multi query */
+PHP_FUNCTION(mysqli_stmt_more_results)
+{
+	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);
+
+	RETURN_BOOL(mysqlnd_stmt_more_results(stmt->stmt));
+}
+/* }}} */
+
+
+/* {{{ proto bool mysqli_stmt_next_result(object link)
+   read next result from multi_query */
+PHP_FUNCTION(mysqli_stmt_next_result) {
+	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 (!mysqlnd_stmt_more_results(stmt->stmt)) {
+		php_error_docref(NULL TSRMLS_CC, E_STRICT, "There is no next result set. "
+						"Please, call mysqli_stmt_more_results()/mysqli_stmt::more_results() to check "
+						"whether to call this function/method");
+	}
+
+	RETURN_BOOL(!mysqlnd_stmt_next_result(stmt->stmt));
+}
+/* }}} */
+#endif
+
+
 /* {{{ proto int mysqli_num_fields(object result) U
    Get number of fields in result */
 PHP_FUNCTION(mysqli_num_fields)

Modified: trunk/php6/ext/mysqli/mysqli_fe.c
===================================================================
--- trunk/php6/ext/mysqli/mysqli_fe.c	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/php6/ext/mysqli/mysqli_fe.c	2008-04-18 01:57:48 UTC (rev 1497)
@@ -163,6 +163,10 @@
 	PHP_FE(mysqli_stmt_data_seek,						NULL)
 	PHP_FE(mysqli_stmt_errno,							NULL)
 	PHP_FE(mysqli_stmt_error,							NULL)
+#if defined(MYSQLI_USE_MYSQLND)
+	PHP_FE(mysqli_stmt_more_results,					NULL)
+	PHP_FE(mysqli_stmt_next_result,						NULL)
+#endif
 	PHP_FE(mysqli_stmt_num_rows,						NULL)
 	PHP_FE(mysqli_stmt_sqlstate,   						NULL)
 	PHP_FE(mysqli_stmt_store_result,					NULL)
@@ -290,6 +294,10 @@
 	PHP_FALIAS(fetch,mysqli_stmt_fetch,NULL)
 	PHP_FALIAS(get_warnings, mysqli_stmt_get_warnings,	NULL)
 	PHP_FALIAS(result_metadata, mysqli_stmt_result_metadata,NULL)
+#if defined(MYSQLI_USE_MYSQLND)
+	PHP_FALIAS(more_results, mysqli_stmt_more_results,NULL)
+	PHP_FALIAS(next_result, mysqli_stmt_next_result,NULL)
+#endif
 	PHP_FALIAS(num_rows, mysqli_stmt_num_rows,NULL)
 	PHP_FALIAS(send_long_data,mysqli_stmt_send_long_data,NULL)
 	PHP_FALIAS(stmt,mysqli_prepare,NULL)

Modified: trunk/php6/ext/mysqli/php_mysqli_structs.h
===================================================================
--- trunk/php6/ext/mysqli/php_mysqli_structs.h	2008-04-17 19:13:13 UTC (rev 1496)
+++ trunk/php6/ext/mysqli/php_mysqli_structs.h	2008-04-18 01:57:48 UTC (rev 1497)
@@ -486,6 +486,8 @@
 PHP_FUNCTION(mysqli_stmt_get_warnings);
 PHP_FUNCTION(mysqli_stmt_reset);
 PHP_FUNCTION(mysqli_stmt_insert_id);
+PHP_FUNCTION(mysqli_stmt_more_results);
+PHP_FUNCTION(mysqli_stmt_next_result);
 PHP_FUNCTION(mysqli_stmt_num_rows);
 PHP_FUNCTION(mysqli_stmt_sqlstate);
 PHP_FUNCTION(mysqli_stmt_store_result);

Modified: trunk/tests/ext/mysqli/mysqli_class_mysqli_stmt_interface.phpt
===================================================================
--- trunk/tests/ext/mysqli/mysqli_class_mysqli_stmt_interface.phpt	2008-04-17 19:13:13 UTC
(rev 1496)
+++ trunk/tests/ext/mysqli/mysqli_class_mysqli_stmt_interface.phpt	2008-04-18 01:57:48 UTC
(rev 1497)
@@ -41,8 +41,11 @@
 		'store_result'      => true,
 	);
 
-	if ($IS_MYSQLND)
+	if ($IS_MYSQLND) {
 		$expected_methods['get_result'] = true;
+		$expected_methods['more_results'] = true;
+		$expected_methods['next_result'] = true;
+	}
 
 	foreach ($methods as $k => $method) {
 	if (isset($expected_methods[$method])) {

Thread
PHP mysqlnd svn commit: r1497 - in trunk: mysqlnd php5/ext/mysqli php6/ext/mysqli tests/ext/mysqliahristov18 Apr