@@ -37,6 +37,36 @@ enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * cons
37
37
38
38
static void mysqlnd_stmt_separate_result_bind (MYSQLND_STMT * const stmt );
39
39
40
+ static enum_func_status mysqlnd_stmt_send_cursor_fetch_command (
41
+ const MYSQLND_STMT_DATA * stmt , unsigned max_rows )
42
+ {
43
+ MYSQLND_CONN_DATA * conn = stmt -> conn ;
44
+ zend_uchar buf [MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */ ];
45
+ const MYSQLND_CSTRING payload = {(const char * ) buf , sizeof (buf )};
46
+
47
+ int4store (buf , stmt -> stmt_id );
48
+ int4store (buf + MYSQLND_STMT_ID_LENGTH , max_rows );
49
+
50
+ if (conn -> command -> stmt_fetch (conn , payload ) == FAIL ) {
51
+ COPY_CLIENT_ERROR (stmt -> error_info , * conn -> error_info );
52
+ return FAIL ;
53
+ }
54
+ return PASS ;
55
+ }
56
+
57
+ static zend_bool mysqlnd_stmt_check_state (const MYSQLND_STMT_DATA * stmt )
58
+ {
59
+ const MYSQLND_CONN_DATA * conn = stmt -> conn ;
60
+ if (stmt -> state != MYSQLND_STMT_WAITING_USE_OR_STORE ) {
61
+ return 0 ;
62
+ }
63
+ if (stmt -> cursor_exists ) {
64
+ return GET_CONNECTION_STATE (& conn -> state ) == CONN_READY ;
65
+ } else {
66
+ return GET_CONNECTION_STATE (& conn -> state ) == CONN_FETCHING_DATA ;
67
+ }
68
+ }
69
+
40
70
/* {{{ mysqlnd_stmt::store_result */
41
71
static MYSQLND_RES *
42
72
MYSQLND_METHOD (mysqlnd_stmt , store_result )(MYSQLND_STMT * const s )
@@ -57,14 +87,8 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
57
87
DBG_RETURN (NULL );
58
88
}
59
89
60
- if (stmt -> cursor_exists ) {
61
- /* Silently convert buffered to unbuffered, for now */
62
- DBG_RETURN (s -> m -> use_result (s ));
63
- }
64
-
65
90
/* Nothing to store for UPSERT/LOAD DATA*/
66
- if (GET_CONNECTION_STATE (& conn -> state ) != CONN_FETCHING_DATA || stmt -> state != MYSQLND_STMT_WAITING_USE_OR_STORE )
67
- {
91
+ if (!mysqlnd_stmt_check_state (stmt )) {
68
92
SET_CLIENT_ERROR (conn -> error_info , CR_COMMANDS_OUT_OF_SYNC , UNKNOWN_SQLSTATE , mysqlnd_out_of_sync );
69
93
DBG_RETURN (NULL );
70
94
}
@@ -75,6 +99,12 @@ MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
75
99
SET_EMPTY_ERROR (conn -> error_info );
76
100
MYSQLND_INC_CONN_STATISTIC (conn -> stats , STAT_PS_BUFFERED_SETS );
77
101
102
+ if (stmt -> cursor_exists ) {
103
+ if (mysqlnd_stmt_send_cursor_fetch_command (stmt , -1 ) == FAIL ) {
104
+ DBG_RETURN (NULL );
105
+ }
106
+ }
107
+
78
108
result = stmt -> result ;
79
109
result -> type = MYSQLND_RES_PS_BUF ;
80
110
/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
@@ -149,19 +179,8 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
149
179
DBG_RETURN (NULL );
150
180
}
151
181
152
- if (stmt -> cursor_exists ) {
153
- /* Prepared statement cursors are not supported as of yet */
154
- char * msg ;
155
- mnd_sprintf (& msg , 0 , "%s() cannot be used with cursors" , get_active_function_name ());
156
- SET_CLIENT_ERROR (stmt -> error_info , CR_NOT_IMPLEMENTED , UNKNOWN_SQLSTATE , msg );
157
- if (msg ) {
158
- mnd_sprintf_free (msg );
159
- }
160
- DBG_RETURN (NULL );
161
- }
162
-
163
182
/* Nothing to store for UPSERT/LOAD DATA*/
164
- if (GET_CONNECTION_STATE ( & conn -> state ) != CONN_FETCHING_DATA || stmt -> state != MYSQLND_STMT_WAITING_USE_OR_STORE ) {
183
+ if (! mysqlnd_stmt_check_state ( stmt ) ) {
165
184
SET_CLIENT_ERROR (stmt -> error_info , CR_COMMANDS_OUT_OF_SYNC , UNKNOWN_SQLSTATE , mysqlnd_out_of_sync );
166
185
DBG_RETURN (NULL );
167
186
}
@@ -170,6 +189,12 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
170
189
SET_EMPTY_ERROR (conn -> error_info );
171
190
MYSQLND_INC_CONN_STATISTIC (conn -> stats , STAT_BUFFERED_SETS );
172
191
192
+ if (stmt -> cursor_exists ) {
193
+ if (mysqlnd_stmt_send_cursor_fetch_command (stmt , -1 ) == FAIL ) {
194
+ DBG_RETURN (NULL );
195
+ }
196
+ }
197
+
173
198
do {
174
199
result = conn -> m -> result_init (stmt -> result -> field_count );
175
200
if (!result ) {
@@ -952,11 +977,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s)
952
977
}
953
978
DBG_INF_FMT ("stmt=%lu" , stmt -> stmt_id );
954
979
955
- if (!stmt -> field_count ||
956
- (!stmt -> cursor_exists && GET_CONNECTION_STATE (& conn -> state ) != CONN_FETCHING_DATA ) ||
957
- (stmt -> cursor_exists && GET_CONNECTION_STATE (& conn -> state ) != CONN_READY ) ||
958
- (stmt -> state != MYSQLND_STMT_WAITING_USE_OR_STORE ))
959
- {
980
+ if (!stmt -> field_count || !mysqlnd_stmt_check_state (stmt )) {
960
981
SET_CLIENT_ERROR (conn -> error_info , CR_COMMANDS_OUT_OF_SYNC , UNKNOWN_SQLSTATE , mysqlnd_out_of_sync );
961
982
DBG_ERR ("command out of sync" );
962
983
DBG_RETURN (NULL );
@@ -986,7 +1007,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
986
1007
MYSQLND_STMT * s = (MYSQLND_STMT * ) param ;
987
1008
MYSQLND_STMT_DATA * stmt = s ? s -> data : NULL ;
988
1009
MYSQLND_CONN_DATA * conn = stmt ? stmt -> conn : NULL ;
989
- zend_uchar buf [MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */ ];
990
1010
MYSQLND_PACKET_ROW * row_packet ;
991
1011
992
1012
DBG_ENTER ("mysqlnd_fetch_stmt_row_cursor" );
@@ -1010,18 +1030,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, const unsigned
1010
1030
SET_EMPTY_ERROR (stmt -> error_info );
1011
1031
SET_EMPTY_ERROR (conn -> error_info );
1012
1032
1013
- int4store (buf , stmt -> stmt_id );
1014
- int4store (buf + MYSQLND_STMT_ID_LENGTH , 1 ); /* for now fetch only one row */
1015
-
1016
- {
1017
- const MYSQLND_CSTRING payload = {(const char * ) buf , sizeof (buf )};
1018
-
1019
- ret = conn -> command -> stmt_fetch (conn , payload );
1020
- if (ret == FAIL ) {
1021
- COPY_CLIENT_ERROR (stmt -> error_info , * conn -> error_info );
1022
- DBG_RETURN (FAIL );
1023
- }
1024
-
1033
+ /* for now fetch only one row */
1034
+ if (mysqlnd_stmt_send_cursor_fetch_command (stmt , 1 ) == FAIL ) {
1035
+ DBG_RETURN (FAIL );
1025
1036
}
1026
1037
1027
1038
UPSERT_STATUS_RESET (stmt -> upsert_status );
0 commit comments