@@ -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; */
@@ -127,19 +157,8 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
127
157
DBG_RETURN (NULL );
128
158
}
129
159
130
- if (stmt -> cursor_exists ) {
131
- /* Prepared statement cursors are not supported as of yet */
132
- char * msg ;
133
- mnd_sprintf (& msg , 0 , "%s() cannot be used with cursors" , get_active_function_name ());
134
- SET_CLIENT_ERROR (stmt -> error_info , CR_NOT_IMPLEMENTED , UNKNOWN_SQLSTATE , msg );
135
- if (msg ) {
136
- mnd_sprintf_free (msg );
137
- }
138
- DBG_RETURN (NULL );
139
- }
140
-
141
160
/* Nothing to store for UPSERT/LOAD DATA*/
142
- if (GET_CONNECTION_STATE ( & conn -> state ) != CONN_FETCHING_DATA || stmt -> state != MYSQLND_STMT_WAITING_USE_OR_STORE ) {
161
+ if (! mysqlnd_stmt_check_state ( stmt ) ) {
143
162
SET_CLIENT_ERROR (stmt -> error_info , CR_COMMANDS_OUT_OF_SYNC , UNKNOWN_SQLSTATE , mysqlnd_out_of_sync );
144
163
DBG_RETURN (NULL );
145
164
}
@@ -148,6 +167,12 @@ MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
148
167
SET_EMPTY_ERROR (conn -> error_info );
149
168
MYSQLND_INC_CONN_STATISTIC (conn -> stats , STAT_BUFFERED_SETS );
150
169
170
+ if (stmt -> cursor_exists ) {
171
+ if (mysqlnd_stmt_send_cursor_fetch_command (stmt , -1 ) == FAIL ) {
172
+ DBG_RETURN (NULL );
173
+ }
174
+ }
175
+
151
176
do {
152
177
result = conn -> m -> result_init (stmt -> result -> field_count );
153
178
if (!result ) {
@@ -718,11 +743,7 @@ MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s)
718
743
}
719
744
DBG_INF_FMT ("stmt=%lu" , stmt -> stmt_id );
720
745
721
- if (!stmt -> field_count ||
722
- (!stmt -> cursor_exists && GET_CONNECTION_STATE (& conn -> state ) != CONN_FETCHING_DATA ) ||
723
- (stmt -> cursor_exists && GET_CONNECTION_STATE (& conn -> state ) != CONN_READY ) ||
724
- (stmt -> state != MYSQLND_STMT_WAITING_USE_OR_STORE ))
725
- {
746
+ if (!stmt -> field_count || !mysqlnd_stmt_check_state (stmt )) {
726
747
SET_CLIENT_ERROR (conn -> error_info , CR_COMMANDS_OUT_OF_SYNC , UNKNOWN_SQLSTATE , mysqlnd_out_of_sync );
727
748
DBG_ERR ("command out of sync" );
728
749
DBG_RETURN (NULL );
@@ -752,7 +773,6 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, zval **row_ptr, const unsign
752
773
enum_func_status ret ;
753
774
MYSQLND_STMT_DATA * stmt = result -> unbuf -> stmt ;
754
775
MYSQLND_CONN_DATA * conn = stmt -> conn ;
755
- zend_uchar buf [MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */ ];
756
776
MYSQLND_PACKET_ROW * row_packet ;
757
777
758
778
DBG_ENTER ("mysqlnd_fetch_stmt_row_cursor" );
@@ -776,18 +796,9 @@ mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, zval **row_ptr, const unsign
776
796
SET_EMPTY_ERROR (stmt -> error_info );
777
797
SET_EMPTY_ERROR (conn -> error_info );
778
798
779
- int4store (buf , stmt -> stmt_id );
780
- int4store (buf + MYSQLND_STMT_ID_LENGTH , 1 ); /* for now fetch only one row */
781
-
782
- {
783
- const MYSQLND_CSTRING payload = {(const char * ) buf , sizeof (buf )};
784
-
785
- ret = conn -> command -> stmt_fetch (conn , payload );
786
- if (ret == FAIL ) {
787
- COPY_CLIENT_ERROR (stmt -> error_info , * conn -> error_info );
788
- DBG_RETURN (FAIL );
789
- }
790
-
799
+ /* for now fetch only one row */
800
+ if (mysqlnd_stmt_send_cursor_fetch_command (stmt , 1 ) == FAIL ) {
801
+ DBG_RETURN (FAIL );
791
802
}
792
803
793
804
UPSERT_STATUS_RESET (stmt -> upsert_status );
0 commit comments