This source file includes following definitions.
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_stmt_skip_metadata
- mysqlnd_stmt_read_prepare_response
- mysqlnd_stmt_prepare_read_eof
- mysqlnd_stmt_execute_parse_response
- MYSQLND_METHOD
- mysqlnd_stmt_fetch_row_buffered
- mysqlnd_stmt_fetch_row_unbuffered
- MYSQLND_METHOD
- mysqlnd_fetch_stmt_row_cursor
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- mysqlnd_stmt_separate_result_bind
- mysqlnd_stmt_separate_one_result_bind
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_METHOD
- MYSQLND_CLASS_METHODS_START
- _mysqlnd_init_ps_subsystem
1
2
3
4
5
6
7
8
9
10
11
12
13
14
15
16
17
18
19
20
21
22 #include "php.h"
23 #include "mysqlnd.h"
24 #include "mysqlnd_wireprotocol.h"
25 #include "mysqlnd_priv.h"
26 #include "mysqlnd_result.h"
27 #include "mysqlnd_result_meta.h"
28 #include "mysqlnd_statistics.h"
29 #include "mysqlnd_debug.h"
30 #include "mysqlnd_block_alloc.h"
31 #include "mysqlnd_ext_plugin.h"
32
33 #define MYSQLND_SILENT
34
35
36 const char * const mysqlnd_not_bound_as_blob = "Can't send long data for non-string/non-binary data types";
37 const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
38
39
40 enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, zend_bool * free_buffer TSRMLS_DC);
41
42 static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt TSRMLS_DC);
43 static void mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const stmt, unsigned int param_no TSRMLS_DC);
44
45
46 static MYSQLND_RES *
47 MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s TSRMLS_DC)
48 {
49 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
50 enum_func_status ret;
51 MYSQLND_CONN_DATA * conn;
52 MYSQLND_RES * result;
53
54 DBG_ENTER("mysqlnd_stmt::store_result");
55 if (!stmt || !stmt->conn || !stmt->result) {
56 DBG_RETURN(NULL);
57 }
58 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
59
60 conn = stmt->conn;
61
62
63 if (!stmt->field_count) {
64 DBG_RETURN(NULL);
65 }
66
67 if (stmt->cursor_exists) {
68
69 DBG_RETURN(s->m->use_result(s TSRMLS_CC));
70 }
71
72
73 if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA ||
74 stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE)
75 {
76 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
77 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
78 DBG_RETURN(NULL);
79 }
80
81 stmt->default_rset_handler = s->m->store_result;
82
83 SET_EMPTY_ERROR(*stmt->error_info);
84 SET_EMPTY_ERROR(*conn->error_info);
85 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_PS_BUFFERED_SETS);
86
87 result = stmt->result;
88 result->type = MYSQLND_RES_PS_BUF;
89
90
91 result->stored_data = (MYSQLND_RES_BUFFERED *) mysqlnd_result_buffered_zval_init(result->field_count, TRUE, result->persistent TSRMLS_CC);
92 if (!result->stored_data) {
93 SET_OOM_ERROR(*conn->error_info);
94 DBG_RETURN(NULL);
95 }
96
97 ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE TSRMLS_CC);
98
99 result->stored_data->m.fetch_row = mysqlnd_stmt_fetch_row_buffered;
100
101 if (PASS == ret) {
102
103 if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
104 MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
105 if (result->stored_data->row_count) {
106
107 if (result->stored_data->row_count * result->meta->field_count * sizeof(zval *) > SIZE_MAX) {
108 SET_OOM_ERROR(*conn->error_info);
109 DBG_RETURN(NULL);
110 }
111
112 set->data = mnd_emalloc((size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
113 if (!set->data) {
114 SET_OOM_ERROR(*conn->error_info);
115 DBG_RETURN(NULL);
116 }
117 memset(set->data, 0, (size_t)(result->stored_data->row_count * result->meta->field_count * sizeof(zval *)));
118 }
119
120 set->data_cursor = set->data;
121 } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
122
123 }
124
125
126 stmt->upsert_status->affected_rows = stmt->result->stored_data->row_count;
127
128 stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
129 } else {
130 COPY_CLIENT_ERROR(*conn->error_info, result->stored_data->error_info);
131 stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
132 mnd_efree(stmt->result);
133 stmt->result = NULL;
134 stmt->state = MYSQLND_STMT_PREPARED;
135 }
136
137 DBG_RETURN(result);
138 }
139
140
141
142
143 static MYSQLND_RES *
144 MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s TSRMLS_DC)
145 {
146 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
147 MYSQLND_CONN_DATA * conn;
148 MYSQLND_RES *result;
149
150 DBG_ENTER("mysqlnd_stmt::get_result");
151 if (!stmt || !stmt->conn || !stmt->result) {
152 DBG_RETURN(NULL);
153 }
154 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
155
156 conn = stmt->conn;
157
158
159 if (!stmt->field_count) {
160 DBG_RETURN(NULL);
161 }
162
163 if (stmt->cursor_exists) {
164
165 DBG_RETURN(s->m->use_result(s TSRMLS_CC));
166 }
167
168
169 if (CONN_GET_STATE(conn) != CONN_FETCHING_DATA || stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE) {
170 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
171 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
172 DBG_RETURN(NULL);
173 }
174
175 SET_EMPTY_ERROR(*stmt->error_info);
176 SET_EMPTY_ERROR(*conn->error_info);
177 MYSQLND_INC_CONN_STATISTIC(conn->stats, STAT_BUFFERED_SETS);
178
179 do {
180 result = conn->m->result_init(stmt->result->field_count, stmt->persistent TSRMLS_CC);
181 if (!result) {
182 SET_OOM_ERROR(*conn->error_info);
183 break;
184 }
185
186 result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
187 if (!result->meta) {
188 SET_OOM_ERROR(*conn->error_info);
189 break;
190 }
191
192 if ((result = result->m.store_result(result, conn, MYSQLND_STORE_PS | MYSQLND_STORE_NO_COPY TSRMLS_CC))) {
193 stmt->upsert_status->affected_rows = result->stored_data->row_count;
194 stmt->state = MYSQLND_STMT_PREPARED;
195 result->type = MYSQLND_RES_PS_BUF;
196 } else {
197 COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
198 stmt->state = MYSQLND_STMT_PREPARED;
199 break;
200 }
201 DBG_RETURN(result);
202 } while (0);
203
204 if (result) {
205 result->m.free_result(result, TRUE TSRMLS_CC);
206 }
207 DBG_RETURN(NULL);
208 }
209
210
211
212
213 static zend_bool
214 MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * s TSRMLS_DC)
215 {
216 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
217 DBG_ENTER("mysqlnd_stmt::more_results");
218
219 DBG_RETURN((stmt && stmt->conn && (stmt->conn->m->get_server_status(stmt->conn TSRMLS_CC) & SERVER_MORE_RESULTS_EXISTS))?
220 TRUE:
221 FALSE);
222 }
223
224
225
226
227 static enum_func_status
228 MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s TSRMLS_DC)
229 {
230 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
231 MYSQLND_CONN_DATA * conn;
232
233 DBG_ENTER("mysqlnd_stmt::next_result");
234 if (!stmt || !stmt->conn || !stmt->result) {
235 DBG_RETURN(FAIL);
236 }
237 conn = stmt->conn;
238 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
239
240 if (CONN_GET_STATE(conn) != CONN_NEXT_RESULT_PENDING || !(conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS)) {
241 DBG_RETURN(FAIL);
242 }
243
244 DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
245
246
247 s->m->free_stmt_result(s TSRMLS_CC);
248 {
249 enum_func_status ret = s->m->parse_execute_response(s TSRMLS_CC);
250 DBG_RETURN(ret);
251 }
252 }
253
254
255
256
257 static enum_func_status
258 mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s TSRMLS_DC)
259 {
260 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
261
262 unsigned int i = 0;
263 enum_func_status ret = FAIL;
264 MYSQLND_PACKET_RES_FIELD * field_packet;
265
266 DBG_ENTER("mysqlnd_stmt_skip_metadata");
267 if (!stmt || !stmt->conn || !stmt->conn->protocol) {
268 DBG_RETURN(FAIL);
269 }
270 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
271
272 field_packet = stmt->conn->protocol->m.get_result_field_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
273 if (!field_packet) {
274 SET_OOM_ERROR(*stmt->error_info);
275 SET_OOM_ERROR(*stmt->conn->error_info);
276 } else {
277 ret = PASS;
278 field_packet->skip_parsing = TRUE;
279 for (;i < stmt->param_count; i++) {
280 if (FAIL == PACKET_READ(field_packet, stmt->conn)) {
281 ret = FAIL;
282 break;
283 }
284 }
285 PACKET_FREE(field_packet);
286 }
287
288 DBG_RETURN(ret);
289 }
290
291
292
293
294 static enum_func_status
295 mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s TSRMLS_DC)
296 {
297 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
298 MYSQLND_PACKET_PREPARE_RESPONSE * prepare_resp;
299 enum_func_status ret = FAIL;
300
301 DBG_ENTER("mysqlnd_stmt_read_prepare_response");
302 if (!stmt || !stmt->conn || !stmt->conn->protocol) {
303 DBG_RETURN(FAIL);
304 }
305 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
306
307 prepare_resp = stmt->conn->protocol->m.get_prepare_response_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
308 if (!prepare_resp) {
309 SET_OOM_ERROR(*stmt->error_info);
310 SET_OOM_ERROR(*stmt->conn->error_info);
311 goto done;
312 }
313
314 if (FAIL == PACKET_READ(prepare_resp, stmt->conn)) {
315 goto done;
316 }
317
318 if (0xFF == prepare_resp->error_code) {
319 COPY_CLIENT_ERROR(*stmt->error_info, prepare_resp->error_info);
320 COPY_CLIENT_ERROR(*stmt->conn->error_info, prepare_resp->error_info);
321 goto done;
322 }
323 ret = PASS;
324 stmt->stmt_id = prepare_resp->stmt_id;
325 stmt->warning_count = stmt->conn->upsert_status->warning_count = prepare_resp->warning_count;
326 stmt->field_count = stmt->conn->field_count = prepare_resp->field_count;
327 stmt->param_count = prepare_resp->param_count;
328 stmt->upsert_status->affected_rows = 0;
329 done:
330 PACKET_FREE(prepare_resp);
331
332 DBG_RETURN(ret);
333 }
334
335
336
337
338 static enum_func_status
339 mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s TSRMLS_DC)
340 {
341 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
342 MYSQLND_PACKET_EOF * fields_eof;
343 enum_func_status ret = FAIL;
344
345 DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
346 if (!stmt || !stmt->conn || !stmt->conn->protocol) {
347 DBG_RETURN(FAIL);
348 }
349 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
350
351 fields_eof = stmt->conn->protocol->m.get_eof_packet(stmt->conn->protocol, FALSE TSRMLS_CC);
352 if (!fields_eof) {
353 SET_OOM_ERROR(*stmt->error_info);
354 SET_OOM_ERROR(*stmt->conn->error_info);
355 } else {
356 if (FAIL == (ret = PACKET_READ(fields_eof, stmt->conn))) {
357 if (stmt->result) {
358 stmt->result->m.free_result_contents(stmt->result TSRMLS_CC);
359 mnd_efree(stmt->result);
360 memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
361 stmt->state = MYSQLND_STMT_INITTED;
362 }
363 } else {
364 stmt->upsert_status->server_status = fields_eof->server_status;
365 stmt->upsert_status->warning_count = fields_eof->warning_count;
366 stmt->state = MYSQLND_STMT_PREPARED;
367 }
368 PACKET_FREE(fields_eof);
369 }
370
371 DBG_RETURN(ret);
372 }
373
374
375
376
377 static enum_func_status
378 MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const query, unsigned int query_len TSRMLS_DC)
379 {
380 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
381 MYSQLND_STMT * s_to_prepare = s;
382 MYSQLND_STMT_DATA * stmt_to_prepare = stmt;
383
384 DBG_ENTER("mysqlnd_stmt::prepare");
385 if (!stmt || !stmt->conn) {
386 DBG_RETURN(FAIL);
387 }
388 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
389 DBG_INF_FMT("query=%s", query);
390
391 SET_ERROR_AFF_ROWS(stmt);
392 SET_ERROR_AFF_ROWS(stmt->conn);
393
394 SET_EMPTY_ERROR(*stmt->error_info);
395 SET_EMPTY_ERROR(*stmt->conn->error_info);
396
397 if (stmt->state > MYSQLND_STMT_INITTED) {
398
399 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
400
401 stmt->default_rset_handler = s->m->use_result;
402 stmt->default_rset_handler(s TSRMLS_CC);
403 }
404
405 if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE && stmt->result) {
406 stmt->result->m.skip_result(stmt->result TSRMLS_CC);
407 }
408
409
410
411
412 s_to_prepare = stmt->conn->m->stmt_init(stmt->conn TSRMLS_CC);
413 if (!s_to_prepare) {
414 goto fail;
415 }
416 stmt_to_prepare = s_to_prepare->data;
417 }
418
419 if (FAIL == stmt_to_prepare->conn->m->simple_command(stmt_to_prepare->conn, COM_STMT_PREPARE, (const zend_uchar *) query, query_len, PROT_LAST, FALSE, TRUE TSRMLS_CC) ||
420 FAIL == mysqlnd_stmt_read_prepare_response(s_to_prepare TSRMLS_CC))
421 {
422 goto fail;
423 }
424
425 if (stmt_to_prepare->param_count) {
426 if (FAIL == mysqlnd_stmt_skip_metadata(s_to_prepare TSRMLS_CC) ||
427 FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
428 {
429 goto fail;
430 }
431 }
432
433
434
435
436
437
438 if (stmt_to_prepare->field_count) {
439 MYSQLND_RES * result = stmt->conn->m->result_init(stmt_to_prepare->field_count, stmt_to_prepare->persistent TSRMLS_CC);
440 if (!result) {
441 SET_OOM_ERROR(*stmt->conn->error_info);
442 goto fail;
443 }
444
445 stmt_to_prepare->result = result;
446
447 result->conn = stmt_to_prepare->conn->m->get_reference(stmt_to_prepare->conn TSRMLS_CC);
448
449 result->type = MYSQLND_RES_PS_BUF;
450
451 if (FAIL == result->m.read_result_metadata(result, stmt_to_prepare->conn TSRMLS_CC) ||
452 FAIL == mysqlnd_stmt_prepare_read_eof(s_to_prepare TSRMLS_CC))
453 {
454 goto fail;
455 }
456 }
457
458 if (stmt_to_prepare != stmt) {
459
460 size_t real_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
461 char * tmp_swap = mnd_malloc(real_size);
462 memcpy(tmp_swap, s, real_size);
463 memcpy(s, s_to_prepare, real_size);
464 memcpy(s_to_prepare, tmp_swap, real_size);
465 mnd_free(tmp_swap);
466 {
467 MYSQLND_STMT_DATA * tmp_swap_data = stmt_to_prepare;
468 stmt_to_prepare = stmt;
469 stmt = tmp_swap_data;
470 }
471 s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
472 }
473 stmt->state = MYSQLND_STMT_PREPARED;
474 DBG_INF("PASS");
475 DBG_RETURN(PASS);
476
477 fail:
478 if (stmt_to_prepare != stmt && s_to_prepare) {
479 s_to_prepare->m->dtor(s_to_prepare, TRUE TSRMLS_CC);
480 }
481 stmt->state = MYSQLND_STMT_INITTED;
482
483 DBG_INF("FAIL");
484 DBG_RETURN(FAIL);
485 }
486
487
488
489
490 static enum_func_status
491 mysqlnd_stmt_execute_parse_response(MYSQLND_STMT * const s TSRMLS_DC)
492 {
493 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
494 enum_func_status ret;
495 MYSQLND_CONN_DATA * conn;
496
497 DBG_ENTER("mysqlnd_stmt_execute_parse_response");
498 if (!stmt || !stmt->conn) {
499 DBG_RETURN(FAIL);
500 }
501 conn = stmt->conn;
502 CONN_SET_STATE(conn, CONN_QUERY_SENT);
503
504 ret = mysqlnd_query_read_result_set_header(stmt->conn, s TSRMLS_CC);
505 if (ret == FAIL) {
506 COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
507 memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status));
508 stmt->upsert_status->affected_rows = conn->upsert_status->affected_rows;
509 if (CONN_GET_STATE(conn) == CONN_QUIT_SENT) {
510
511 }
512 stmt->state = MYSQLND_STMT_PREPARED;
513 stmt->send_types_to_server = 1;
514 } else {
515
516
517
518
519
520
521
522 SET_EMPTY_ERROR(*stmt->error_info);
523 SET_EMPTY_ERROR(*stmt->conn->error_info);
524 *stmt->upsert_status = *conn->upsert_status;
525 stmt->state = MYSQLND_STMT_EXECUTED;
526 if (conn->last_query_type == QUERY_UPSERT || conn->last_query_type == QUERY_LOAD_LOCAL) {
527 DBG_INF("PASS");
528 DBG_RETURN(PASS);
529 }
530
531 stmt->result->type = MYSQLND_RES_PS_BUF;
532 if (!stmt->result->conn) {
533
534
535
536
537 stmt->result->conn = stmt->conn->m->get_reference(stmt->conn TSRMLS_CC);
538 }
539
540
541 stmt->field_count = stmt->result->field_count = conn->field_count;
542 if (stmt->result->stored_data) {
543 stmt->result->stored_data->lengths = NULL;
544 } else if (stmt->result->unbuf) {
545 stmt->result->unbuf->lengths = NULL;
546 }
547 if (stmt->field_count) {
548 stmt->state = MYSQLND_STMT_WAITING_USE_OR_STORE;
549
550
551
552
553
554 DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status,
555 stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
556
557 if (stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS) {
558 DBG_INF("cursor exists");
559 stmt->cursor_exists = TRUE;
560 CONN_SET_STATE(conn, CONN_READY);
561
562 stmt->default_rset_handler = s->m->use_result;
563 DBG_INF("use_result");
564 } else if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
565 DBG_INF("asked for cursor but got none");
566
567
568
569
570
571
572
573
574
575
576
577 stmt->default_rset_handler = s->m->store_result;
578 DBG_INF("store_result");
579 } else {
580 DBG_INF("no cursor");
581
582 stmt->default_rset_handler = s->m->use_result;
583 DBG_INF("use_result");
584 }
585 }
586 }
587 #ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET
588 if (stmt->upsert_status->server_status & SERVER_PS_OUT_PARAMS) {
589 s->m->free_stmt_content(s TSRMLS_CC);
590 DBG_INF("PS OUT Variable RSet, skipping");
591
592 ret = mysqlnd_stmt_execute_parse_response(s TSRMLS_CC);
593 }
594 #endif
595
596 DBG_INF(ret == PASS? "PASS":"FAIL");
597 DBG_RETURN(ret);
598 }
599
600
601
602
603 static enum_func_status
604 MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s TSRMLS_DC)
605 {
606 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
607 enum_func_status ret;
608 MYSQLND_CONN_DATA * conn;
609 zend_uchar *request = NULL;
610 size_t request_len;
611 zend_bool free_request;
612
613 DBG_ENTER("mysqlnd_stmt::execute");
614 if (!stmt || !stmt->conn) {
615 DBG_RETURN(FAIL);
616 }
617 conn = stmt->conn;
618 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
619
620 SET_ERROR_AFF_ROWS(stmt);
621 SET_ERROR_AFF_ROWS(stmt->conn);
622
623 if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) {
624
625
626
627
628
629 #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
630 if (stmt->result_bind &&
631 stmt->result_zvals_separated_once == TRUE &&
632 stmt->state >= MYSQLND_STMT_USER_FETCHING)
633 {
634
635
636
637
638
639
640
641
642
643
644
645
646 unsigned int i;
647 for (i = 0; i < stmt->field_count; i++) {
648 if (stmt->result_bind[i].bound == TRUE) {
649 zval_copy_ctor(stmt->result_bind[i].zv);
650 }
651 }
652 }
653 #endif
654
655 s->m->flush(s TSRMLS_CC);
656
657
658
659
660
661
662 stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
663
664 stmt->state = MYSQLND_STMT_PREPARED;
665 } else if (stmt->state < MYSQLND_STMT_PREPARED) {
666
667 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
668 mysqlnd_out_of_sync);
669 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
670 DBG_INF("FAIL");
671 DBG_RETURN(FAIL);
672 }
673
674 if (stmt->param_count) {
675 unsigned int i, not_bound = 0;
676 if (!stmt->param_bind) {
677 SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE,
678 "No data supplied for parameters in prepared statement");
679 DBG_INF("FAIL");
680 DBG_RETURN(FAIL);
681 }
682 for (i = 0; i < stmt->param_count; i++) {
683 if (stmt->param_bind[i].zv == NULL) {
684 not_bound++;
685 }
686 }
687 if (not_bound) {
688 char * msg;
689 mnd_sprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement",
690 not_bound, not_bound>1 ?"s":"");
691 SET_STMT_ERROR(stmt, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, msg);
692 if (msg) {
693 mnd_sprintf_free(msg);
694 }
695 DBG_INF("FAIL");
696 DBG_RETURN(FAIL);
697 }
698 }
699 ret = s->m->generate_execute_request(s, &request, &request_len, &free_request TSRMLS_CC);
700 if (ret == PASS) {
701
702 ret = stmt->conn->m->simple_command(stmt->conn, COM_STMT_EXECUTE, request, request_len,
703 PROT_LAST ,
704 FALSE, FALSE TSRMLS_CC);
705 } else {
706 SET_STMT_ERROR(stmt, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM.");
707 }
708
709 if (free_request) {
710 mnd_efree(request);
711 }
712
713 if (ret == FAIL) {
714 COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
715 DBG_INF("FAIL");
716 DBG_RETURN(FAIL);
717 }
718 stmt->execute_count++;
719
720 ret = s->m->parse_execute_response(s TSRMLS_CC);
721
722 DBG_INF_FMT("server_status=%u cursor=%u", stmt->upsert_status->server_status, stmt->upsert_status->server_status & SERVER_STATUS_CURSOR_EXISTS);
723
724 if (ret == PASS && conn->last_query_type == QUERY_UPSERT && stmt->upsert_status->affected_rows) {
725 MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn->stats, STAT_ROWS_AFFECTED_PS, stmt->upsert_status->affected_rows);
726 }
727 DBG_RETURN(ret);
728 }
729
730
731
732
733 enum_func_status
734 mysqlnd_stmt_fetch_row_buffered(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
735 {
736 MYSQLND_STMT * s = (MYSQLND_STMT *) param;
737 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
738 const MYSQLND_RES_METADATA * const meta = result->meta;
739 unsigned int field_count = meta->field_count;
740
741 DBG_ENTER("mysqlnd_stmt_fetch_row_buffered");
742 *fetched_anything = FALSE;
743 DBG_INF_FMT("stmt=%lu", stmt != NULL ? stmt->stmt_id : 0L);
744
745
746 if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_ZVAL) {
747 MYSQLND_RES_BUFFERED_ZVAL * set = (MYSQLND_RES_BUFFERED_ZVAL *) result->stored_data;
748 if (set->data_cursor &&
749 (set->data_cursor - set->data) < (result->stored_data->row_count * field_count))
750 {
751
752 if (stmt->result_bind) {
753 unsigned int i;
754 zval **current_row = set->data_cursor;
755
756 if (NULL == current_row[0]) {
757 uint64_t row_num = (set->data_cursor - set->data) / field_count;
758 enum_func_status rc = result->stored_data->m.row_decoder(result->stored_data->row_buffers[row_num],
759 current_row,
760 meta->field_count,
761 meta->fields,
762 result->conn->options->int_and_float_native,
763 result->conn->stats TSRMLS_CC);
764 if (PASS != rc) {
765 DBG_RETURN(FAIL);
766 }
767 result->stored_data->initialized_rows++;
768 if (stmt->update_max_length) {
769 for (i = 0; i < result->field_count; i++) {
770
771
772
773
774
775 if (Z_TYPE_P(current_row[i]) >= IS_STRING) {
776 unsigned long len = Z_STRLEN_P(current_row[i]);
777 if (meta->fields[i].max_length < len) {
778 meta->fields[i].max_length = len;
779 }
780 }
781 }
782 }
783 }
784
785 for (i = 0; i < result->field_count; i++) {
786
787 #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
788 if (stmt->result_bind[i].zv) {
789 zval_dtor(stmt->result_bind[i].zv);
790 }
791 #endif
792
793 if (stmt->result_bind[i].bound == TRUE) {
794 DBG_INF_FMT("i=%u type=%u", i, Z_TYPE_P(current_row[i]));
795 if (Z_TYPE_P(current_row[i]) != IS_NULL) {
796
797
798
799
800
801
802
803
804 Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(current_row[i]);
805 stmt->result_bind[i].zv->value = current_row[i]->value;
806 #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
807 zval_copy_ctor(stmt->result_bind[i].zv);
808 #endif
809 } else {
810 ZVAL_NULL(stmt->result_bind[i].zv);
811 }
812 }
813 }
814 }
815 set->data_cursor += field_count;
816 *fetched_anything = TRUE;
817
818 MYSQLND_INC_GLOBAL_STATISTIC(STAT_ROWS_FETCHED_FROM_CLIENT_PS_BUF);
819 DBG_INF("row fetched");
820 } else {
821 set->data_cursor = NULL;
822 DBG_INF("no more data");
823 }
824 } else if (result->stored_data->type == MYSQLND_BUFFERED_TYPE_C) {
825
826 }
827 DBG_INF("PASS");
828 DBG_RETURN(PASS);
829 }
830
831
832
833
834 enum_func_status
835 mysqlnd_stmt_fetch_row_unbuffered(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
836 {
837 enum_func_status ret;
838 MYSQLND_STMT * s = (MYSQLND_STMT *) param;
839 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
840 MYSQLND_PACKET_ROW * row_packet;
841 const MYSQLND_RES_METADATA * const meta = result->meta;
842
843 DBG_ENTER("mysqlnd_stmt_fetch_row_unbuffered");
844
845 *fetched_anything = FALSE;
846
847 if (result->unbuf->eof_reached) {
848
849 DBG_INF("EOF already reached");
850 DBG_RETURN(PASS);
851 }
852 if (CONN_GET_STATE(result->conn) != CONN_FETCHING_DATA) {
853 SET_CLIENT_ERROR(*result->conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
854 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
855 DBG_ERR("command out of sync");
856 DBG_RETURN(FAIL);
857 }
858 if (!(row_packet = result->unbuf->row_packet)) {
859 DBG_RETURN(FAIL);
860 }
861
862
863 row_packet->skip_extraction = stmt && stmt->result_bind? FALSE:TRUE;
864
865
866
867
868
869 if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
870 unsigned int i, field_count = result->field_count;
871
872 if (!row_packet->skip_extraction) {
873 result->unbuf->m.free_last_data(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC);
874
875 result->unbuf->last_row_data = row_packet->fields;
876 result->unbuf->last_row_buffer = row_packet->row_buffer;
877 row_packet->fields = NULL;
878 row_packet->row_buffer = NULL;
879
880 if (PASS != result->unbuf->m.row_decoder(result->unbuf->last_row_buffer,
881 result->unbuf->last_row_data,
882 row_packet->field_count,
883 row_packet->fields_metadata,
884 result->conn->options->int_and_float_native,
885 result->conn->stats TSRMLS_CC))
886 {
887 DBG_RETURN(FAIL);
888 }
889
890 for (i = 0; i < field_count; i++) {
891 if (stmt->result_bind[i].bound == TRUE) {
892 zval *data = result->unbuf->last_row_data[i];
893
894
895
896
897 #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
898 zval_dtor(stmt->result_bind[i].zv);
899 #endif
900 if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data)) ) {
901 if ((Z_TYPE_P(data) == IS_STRING) && (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) {
902 meta->fields[i].max_length = Z_STRLEN_P(data);
903 }
904 stmt->result_bind[i].zv->value = data->value;
905
906 ZVAL_NULL(data);
907 }
908 }
909 }
910 MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_UNBUF);
911 } else {
912 DBG_INF("skipping extraction");
913
914
915
916
917
918
919 row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
920 row_packet->row_buffer = NULL;
921 }
922
923 result->unbuf->row_count++;
924 *fetched_anything = TRUE;
925 } else if (ret == FAIL) {
926 if (row_packet->error_info.error_no) {
927 COPY_CLIENT_ERROR(*stmt->conn->error_info, row_packet->error_info);
928 COPY_CLIENT_ERROR(*stmt->error_info, row_packet->error_info);
929 }
930 CONN_SET_STATE(result->conn, CONN_READY);
931 result->unbuf->eof_reached = TRUE;
932 } else if (row_packet->eof) {
933 DBG_INF("EOF");
934
935 result->unbuf->eof_reached = TRUE;
936 memset(result->conn->upsert_status, 0, sizeof(*result->conn->upsert_status));
937 result->conn->upsert_status->warning_count = row_packet->warning_count;
938 result->conn->upsert_status->server_status = row_packet->server_status;
939
940
941
942
943 if (result->conn->upsert_status->server_status & SERVER_MORE_RESULTS_EXISTS) {
944 CONN_SET_STATE(result->conn, CONN_NEXT_RESULT_PENDING);
945 } else {
946 CONN_SET_STATE(result->conn, CONN_READY);
947 }
948 }
949
950 DBG_INF_FMT("ret=%s fetched_anything=%u", ret == PASS? "PASS":"FAIL", *fetched_anything);
951 DBG_RETURN(ret);
952 }
953
954
955
956
957 static MYSQLND_RES *
958 MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s TSRMLS_DC)
959 {
960 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
961 MYSQLND_RES * result;
962 MYSQLND_CONN_DATA * conn;
963
964 DBG_ENTER("mysqlnd_stmt::use_result");
965 if (!stmt || !stmt->conn || !stmt->result) {
966 DBG_RETURN(NULL);
967 }
968 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
969
970 conn = stmt->conn;
971
972 if (!stmt->field_count ||
973 (!stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_FETCHING_DATA) ||
974 (stmt->cursor_exists && CONN_GET_STATE(conn) != CONN_READY) ||
975 (stmt->state != MYSQLND_STMT_WAITING_USE_OR_STORE))
976 {
977 SET_CLIENT_ERROR(*conn->error_info, CR_COMMANDS_OUT_OF_SYNC,
978 UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
979 DBG_ERR("command out of sync");
980 DBG_RETURN(NULL);
981 }
982
983 SET_EMPTY_ERROR(*stmt->error_info);
984
985 MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_PS_UNBUFFERED_SETS);
986 result = stmt->result;
987
988 result->m.use_result(stmt->result, TRUE TSRMLS_CC);
989 result->unbuf->m.fetch_row = stmt->cursor_exists? mysqlnd_fetch_stmt_row_cursor:
990 mysqlnd_stmt_fetch_row_unbuffered;
991 stmt->state = MYSQLND_STMT_USE_OR_STORE_CALLED;
992
993 DBG_INF_FMT("%p", result);
994 DBG_RETURN(result);
995 }
996
997
998
999 #define STMT_ID_LENGTH 4
1000
1001
1002 enum_func_status
1003 mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, void * param, unsigned int flags, zend_bool * fetched_anything TSRMLS_DC)
1004 {
1005 enum_func_status ret;
1006 MYSQLND_STMT * s = (MYSQLND_STMT *) param;
1007 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1008 zend_uchar buf[STMT_ID_LENGTH + 4 ];
1009 MYSQLND_PACKET_ROW * row_packet;
1010
1011 DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
1012
1013 if (!stmt || !stmt->conn || !result || !result->conn || !result->unbuf) {
1014 DBG_ERR("no statement");
1015 DBG_RETURN(FAIL);
1016 }
1017
1018 DBG_INF_FMT("stmt=%lu flags=%u", stmt->stmt_id, flags);
1019
1020 if (stmt->state < MYSQLND_STMT_USER_FETCHING) {
1021
1022 SET_CLIENT_ERROR(*stmt->conn->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE,
1023 mysqlnd_out_of_sync);
1024 DBG_ERR("command out of sync");
1025 DBG_RETURN(FAIL);
1026 }
1027 if (!(row_packet = result->unbuf->row_packet)) {
1028 DBG_RETURN(FAIL);
1029 }
1030
1031 SET_EMPTY_ERROR(*stmt->error_info);
1032 SET_EMPTY_ERROR(*stmt->conn->error_info);
1033
1034 int4store(buf, stmt->stmt_id);
1035 int4store(buf + STMT_ID_LENGTH, 1);
1036
1037 if (FAIL == stmt->conn->m->simple_command(stmt->conn, COM_STMT_FETCH, buf, sizeof(buf),
1038 PROT_LAST ,
1039 FALSE, TRUE TSRMLS_CC)) {
1040 COPY_CLIENT_ERROR(*stmt->error_info, *stmt->conn->error_info);
1041 DBG_RETURN(FAIL);
1042 }
1043
1044 row_packet->skip_extraction = stmt->result_bind? FALSE:TRUE;
1045
1046 memset(stmt->upsert_status, 0, sizeof(*stmt->upsert_status));
1047 if (PASS == (ret = PACKET_READ(row_packet, result->conn)) && !row_packet->eof) {
1048 const MYSQLND_RES_METADATA * const meta = result->meta;
1049 unsigned int i, field_count = result->field_count;
1050
1051 if (!row_packet->skip_extraction) {
1052 result->unbuf->m.free_last_data(result->unbuf, result->conn? result->conn->stats : NULL TSRMLS_CC);
1053
1054 result->unbuf->last_row_data = row_packet->fields;
1055 result->unbuf->last_row_buffer = row_packet->row_buffer;
1056 row_packet->fields = NULL;
1057 row_packet->row_buffer = NULL;
1058
1059 if (PASS != result->unbuf->m.row_decoder(result->unbuf->last_row_buffer,
1060 result->unbuf->last_row_data,
1061 row_packet->field_count,
1062 row_packet->fields_metadata,
1063 result->conn->options->int_and_float_native,
1064 result->conn->stats TSRMLS_CC))
1065 {
1066 DBG_RETURN(FAIL);
1067 }
1068
1069
1070 for (i = 0; i < field_count; i++) {
1071 if (stmt->result_bind[i].bound == TRUE) {
1072 zval *data = result->unbuf->last_row_data[i];
1073
1074
1075
1076
1077 #ifndef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
1078 zval_dtor(stmt->result_bind[i].zv);
1079 #endif
1080 DBG_INF_FMT("i=%u bound_var=%p type=%u refc=%u", i, stmt->result_bind[i].zv,
1081 Z_TYPE_P(data), Z_REFCOUNT_P(stmt->result_bind[i].zv));
1082 if (IS_NULL != (Z_TYPE_P(stmt->result_bind[i].zv) = Z_TYPE_P(data))) {
1083 if ((Z_TYPE_P(data) == IS_STRING) && (meta->fields[i].max_length < (unsigned long) Z_STRLEN_P(data))) {
1084 meta->fields[i].max_length = Z_STRLEN_P(data);
1085 }
1086 stmt->result_bind[i].zv->value = data->value;
1087
1088 ZVAL_NULL(data);
1089 }
1090 }
1091 }
1092 } else {
1093 DBG_INF("skipping extraction");
1094
1095
1096
1097
1098
1099
1100 row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
1101 row_packet->row_buffer = NULL;
1102 }
1103
1104 ret = PACKET_READ(row_packet, result->conn);
1105 if (row_packet->row_buffer) {
1106 row_packet->row_buffer->free_chunk(row_packet->row_buffer TSRMLS_CC);
1107 row_packet->row_buffer = NULL;
1108 }
1109 MYSQLND_INC_CONN_STATISTIC(stmt->conn->stats, STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR);
1110
1111 result->unbuf->row_count++;
1112 *fetched_anything = TRUE;
1113 } else {
1114 *fetched_anything = FALSE;
1115
1116 stmt->upsert_status->warning_count =
1117 stmt->conn->upsert_status->warning_count =
1118 row_packet->warning_count;
1119
1120 stmt->upsert_status->server_status =
1121 stmt->conn->upsert_status->server_status =
1122 row_packet->server_status;
1123
1124 result->unbuf->eof_reached = row_packet->eof;
1125 }
1126 stmt->upsert_status->warning_count =
1127 stmt->conn->upsert_status->warning_count =
1128 row_packet->warning_count;
1129 stmt->upsert_status->server_status =
1130 stmt->conn->upsert_status->server_status =
1131 row_packet->server_status;
1132
1133 DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u",
1134 ret == PASS? "PASS":"FAIL", *fetched_anything,
1135 row_packet->server_status, row_packet->warning_count,
1136 result->unbuf->eof_reached);
1137 DBG_RETURN(ret);
1138 }
1139
1140
1141
1142
1143 static enum_func_status
1144 MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, zend_bool * const fetched_anything TSRMLS_DC)
1145 {
1146 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1147 enum_func_status ret;
1148 DBG_ENTER("mysqlnd_stmt::fetch");
1149 if (!stmt || !stmt->conn) {
1150 DBG_RETURN(FAIL);
1151 }
1152 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
1153
1154 if (!stmt->result ||
1155 stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
1156 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
1157
1158 DBG_ERR("command out of sync");
1159 DBG_RETURN(FAIL);
1160 } else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
1161
1162
1163 stmt->default_rset_handler(s TSRMLS_CC);
1164 }
1165 stmt->state = MYSQLND_STMT_USER_FETCHING;
1166
1167 SET_EMPTY_ERROR(*stmt->error_info);
1168 SET_EMPTY_ERROR(*stmt->conn->error_info);
1169
1170 DBG_INF_FMT("result_bind=%p separated_once=%u", stmt->result_bind, stmt->result_zvals_separated_once);
1171
1172
1173
1174
1175 if (stmt->result_bind && !stmt->result_zvals_separated_once) {
1176 unsigned int i;
1177
1178
1179
1180
1181 for (i = 0; i < stmt->result->field_count; i++) {
1182 if (stmt->result_bind[i].bound == TRUE) {
1183 zval_dtor(stmt->result_bind[i].zv);
1184 ZVAL_NULL(stmt->result_bind[i].zv);
1185 }
1186 }
1187 stmt->result_zvals_separated_once = TRUE;
1188 }
1189
1190 ret = stmt->result->m.fetch_row(stmt->result, (void*)s, 0, fetched_anything TSRMLS_CC);
1191 DBG_RETURN(ret);
1192 }
1193
1194
1195
1196
1197 static enum_func_status
1198 MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s TSRMLS_DC)
1199 {
1200 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1201 enum_func_status ret = PASS;
1202 zend_uchar cmd_buf[STMT_ID_LENGTH ];
1203
1204 DBG_ENTER("mysqlnd_stmt::reset");
1205 if (!stmt || !stmt->conn) {
1206 DBG_RETURN(FAIL);
1207 }
1208 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
1209
1210 SET_EMPTY_ERROR(*stmt->error_info);
1211 SET_EMPTY_ERROR(*stmt->conn->error_info);
1212
1213 if (stmt->stmt_id) {
1214 MYSQLND_CONN_DATA * conn = stmt->conn;
1215 if (stmt->param_bind) {
1216 unsigned int i;
1217 DBG_INF("resetting long data");
1218
1219 for (i = 0; i < stmt->param_count; i++) {
1220 if (stmt->param_bind[i].flags & MYSQLND_PARAM_BIND_BLOB_USED) {
1221 stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
1222 }
1223 }
1224 }
1225
1226 s->m->flush(s TSRMLS_CC);
1227
1228
1229
1230
1231
1232
1233
1234 int4store(cmd_buf, stmt->stmt_id);
1235 if (CONN_GET_STATE(conn) == CONN_READY &&
1236 FAIL == (ret = conn->m->simple_command(conn, COM_STMT_RESET, cmd_buf,
1237 sizeof(cmd_buf), PROT_OK_PACKET,
1238 FALSE, TRUE TSRMLS_CC))) {
1239 COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
1240 }
1241 *stmt->upsert_status = *conn->upsert_status;
1242 }
1243 DBG_INF(ret == PASS? "PASS":"FAIL");
1244 DBG_RETURN(ret);
1245 }
1246
1247
1248
1249
1250 static enum_func_status
1251 MYSQLND_METHOD(mysqlnd_stmt, flush)(MYSQLND_STMT * const s TSRMLS_DC)
1252 {
1253 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1254 enum_func_status ret = PASS;
1255
1256 DBG_ENTER("mysqlnd_stmt::flush");
1257 if (!stmt || !stmt->conn) {
1258 DBG_RETURN(FAIL);
1259 }
1260 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
1261
1262 if (stmt->stmt_id) {
1263
1264
1265
1266
1267
1268 do {
1269 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
1270 DBG_INF("fetching result set header");
1271 stmt->default_rset_handler(s TSRMLS_CC);
1272 stmt->state = MYSQLND_STMT_USER_FETCHING;
1273 }
1274
1275 if (stmt->result) {
1276 DBG_INF("skipping result");
1277 stmt->result->m.skip_result(stmt->result TSRMLS_CC);
1278 }
1279 } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
1280 }
1281 DBG_INF(ret == PASS? "PASS":"FAIL");
1282 DBG_RETURN(ret);
1283 }
1284
1285
1286
1287
1288 static enum_func_status
1289 MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
1290 const char * const data, unsigned long length TSRMLS_DC)
1291 {
1292 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1293 enum_func_status ret = FAIL;
1294 MYSQLND_CONN_DATA * conn;
1295 zend_uchar * cmd_buf;
1296 enum php_mysqlnd_server_command cmd = COM_STMT_SEND_LONG_DATA;
1297
1298 DBG_ENTER("mysqlnd_stmt::send_long_data");
1299 if (!stmt || !stmt->conn) {
1300 DBG_RETURN(FAIL);
1301 }
1302 DBG_INF_FMT("stmt=%lu param_no=%u data_len=%lu", stmt->stmt_id, param_no, length);
1303
1304 conn = stmt->conn;
1305
1306 SET_EMPTY_ERROR(*stmt->error_info);
1307 SET_EMPTY_ERROR(*stmt->conn->error_info);
1308
1309 if (stmt->state < MYSQLND_STMT_PREPARED) {
1310 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
1311 DBG_ERR("not prepared");
1312 DBG_RETURN(FAIL);
1313 }
1314 if (!stmt->param_bind) {
1315 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, mysqlnd_out_of_sync);
1316 DBG_ERR("command out of sync");
1317 DBG_RETURN(FAIL);
1318 }
1319 if (param_no >= stmt->param_count) {
1320 SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
1321 DBG_ERR("invalid param_no");
1322 DBG_RETURN(FAIL);
1323 }
1324 if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {
1325 SET_STMT_ERROR(stmt, CR_INVALID_BUFFER_USE, UNKNOWN_SQLSTATE, mysqlnd_not_bound_as_blob);
1326 DBG_ERR("param_no is not of a blob type");
1327 DBG_RETURN(FAIL);
1328 }
1329
1330
1331
1332
1333
1334
1335
1336
1337
1338
1339
1340 if (CONN_GET_STATE(conn) == CONN_READY) {
1341 size_t packet_len;
1342 cmd_buf = mnd_emalloc(packet_len = STMT_ID_LENGTH + 2 + length);
1343 if (cmd_buf) {
1344 stmt->param_bind[param_no].flags |= MYSQLND_PARAM_BIND_BLOB_USED;
1345
1346 int4store(cmd_buf, stmt->stmt_id);
1347 int2store(cmd_buf + STMT_ID_LENGTH, param_no);
1348 memcpy(cmd_buf + STMT_ID_LENGTH + 2, data, length);
1349
1350
1351 ret = conn->m->simple_command(conn, cmd, cmd_buf, packet_len, PROT_LAST , FALSE, TRUE TSRMLS_CC);
1352 mnd_efree(cmd_buf);
1353 if (FAIL == ret) {
1354 COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
1355 }
1356 } else {
1357 ret = FAIL;
1358 SET_OOM_ERROR(*stmt->error_info);
1359 SET_OOM_ERROR(*conn->error_info);
1360 }
1361
1362
1363
1364
1365
1366
1367
1368
1369
1370
1371
1372
1373
1374
1375
1376
1377 #ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
1378 #if HAVE_USLEEP && !defined(PHP_WIN32)
1379 usleep(120000);
1380 #endif
1381 if ((packet_len = conn->net->m.consume_uneaten_data(conn->net, cmd TSRMLS_CC))) {
1382 php_error_docref(NULL TSRMLS_CC, E_WARNING, "There was an error "
1383 "while sending long data. Probably max_allowed_packet_size "
1384 "is smaller than the data. You have to increase it or send "
1385 "smaller chunks of data. Answer was "MYSQLND_SZ_T_SPEC" bytes long.", packet_len);
1386 SET_STMT_ERROR(stmt, CR_CONNECTION_ERROR, UNKNOWN_SQLSTATE,
1387 "Server responded to COM_STMT_SEND_LONG_DATA.");
1388 ret = FAIL;
1389 }
1390 #endif
1391 }
1392
1393 DBG_INF(ret == PASS? "PASS":"FAIL");
1394 DBG_RETURN(ret);
1395 }
1396
1397
1398
1399
1400 static enum_func_status
1401 MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * const param_bind TSRMLS_DC)
1402 {
1403 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1404 DBG_ENTER("mysqlnd_stmt::bind_param");
1405 if (!stmt || !stmt->conn) {
1406 DBG_RETURN(FAIL);
1407 }
1408 DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
1409
1410 if (stmt->state < MYSQLND_STMT_PREPARED) {
1411 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
1412 DBG_ERR("not prepared");
1413 if (param_bind) {
1414 s->m->free_parameter_bind(s, param_bind TSRMLS_CC);
1415 }
1416 DBG_RETURN(FAIL);
1417 }
1418
1419 SET_EMPTY_ERROR(*stmt->error_info);
1420 SET_EMPTY_ERROR(*stmt->conn->error_info);
1421
1422 if (stmt->param_count) {
1423 unsigned int i = 0;
1424
1425 if (!param_bind) {
1426 SET_STMT_ERROR(stmt, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported");
1427 DBG_ERR("Re-binding (still) not supported");
1428 DBG_RETURN(FAIL);
1429 } else if (stmt->param_bind) {
1430 DBG_INF("Binding");
1431
1432
1433
1434
1435 for (i = 0; i < stmt->param_count; i++) {
1436
1437
1438
1439
1440 if (stmt->param_bind[i].zv) {
1441 zval_ptr_dtor(&stmt->param_bind[i].zv);
1442 }
1443 }
1444 if (stmt->param_bind != param_bind) {
1445 s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
1446 }
1447 }
1448
1449 stmt->param_bind = param_bind;
1450 for (i = 0; i < stmt->param_count; i++) {
1451
1452 DBG_INF_FMT("%u is of type %u", i, stmt->param_bind[i].type);
1453
1454
1455 Z_ADDREF_P(stmt->param_bind[i].zv);
1456 stmt->param_bind[i].flags = 0;
1457 if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
1458 stmt->param_bind[i].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
1459 }
1460 }
1461 stmt->send_types_to_server = 1;
1462 }
1463 DBG_INF("PASS");
1464 DBG_RETURN(PASS);
1465 }
1466
1467
1468
1469
1470 static enum_func_status
1471 MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigned int param_no,
1472 zval * const zv, zend_uchar type TSRMLS_DC)
1473 {
1474 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1475 DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
1476 if (!stmt || !stmt->conn) {
1477 DBG_RETURN(FAIL);
1478 }
1479 DBG_INF_FMT("stmt=%lu param_no=%u param_count=%u type=%u", stmt->stmt_id, param_no, stmt->param_count, type);
1480
1481 if (stmt->state < MYSQLND_STMT_PREPARED) {
1482 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
1483 DBG_ERR("not prepared");
1484 DBG_RETURN(FAIL);
1485 }
1486
1487 if (param_no >= stmt->param_count) {
1488 SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
1489 DBG_ERR("invalid param_no");
1490 DBG_RETURN(FAIL);
1491 }
1492 SET_EMPTY_ERROR(*stmt->error_info);
1493 SET_EMPTY_ERROR(*stmt->conn->error_info);
1494
1495 if (stmt->param_count) {
1496 if (!stmt->param_bind) {
1497 stmt->param_bind = mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent);
1498 if (!stmt->param_bind) {
1499 DBG_RETURN(FAIL);
1500 }
1501 }
1502
1503
1504
1505 Z_ADDREF_P(zv);
1506 DBG_INF("Binding");
1507
1508 if (stmt->param_bind[param_no].zv) {
1509 zval_ptr_dtor(&stmt->param_bind[param_no].zv);
1510 }
1511 if (type == MYSQL_TYPE_LONG_BLOB) {
1512
1513 stmt->param_bind[param_no].flags &= ~MYSQLND_PARAM_BIND_BLOB_USED;
1514 }
1515 stmt->param_bind[param_no].zv = zv;
1516 stmt->param_bind[param_no].type = type;
1517
1518 stmt->send_types_to_server = 1;
1519 }
1520 DBG_INF("PASS");
1521 DBG_RETURN(PASS);
1522 }
1523
1524
1525
1526
1527 static enum_func_status
1528 MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const s TSRMLS_DC)
1529 {
1530 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1531 DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
1532 if (!stmt || !stmt->conn) {
1533 DBG_RETURN(FAIL);
1534 }
1535 DBG_INF_FMT("stmt=%lu param_count=%u", stmt->stmt_id, stmt->param_count);
1536
1537 if (stmt->state < MYSQLND_STMT_PREPARED) {
1538 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
1539 DBG_ERR("not prepared");
1540 DBG_RETURN(FAIL);
1541 }
1542
1543 SET_EMPTY_ERROR(*stmt->error_info);
1544 SET_EMPTY_ERROR(*stmt->conn->error_info);
1545
1546 if (stmt->param_count) {
1547 stmt->send_types_to_server = 1;
1548 }
1549 DBG_RETURN(PASS);
1550 }
1551
1552
1553
1554
1555 static enum_func_status
1556 MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
1557 MYSQLND_RESULT_BIND * const result_bind TSRMLS_DC)
1558 {
1559 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1560 DBG_ENTER("mysqlnd_stmt::bind_result");
1561 if (!stmt || !stmt->conn) {
1562 DBG_RETURN(FAIL);
1563 }
1564 DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
1565
1566 if (stmt->state < MYSQLND_STMT_PREPARED) {
1567 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
1568 if (result_bind) {
1569 s->m->free_result_bind(s, result_bind TSRMLS_CC);
1570 }
1571 DBG_ERR("not prepared");
1572 DBG_RETURN(FAIL);
1573 }
1574
1575 SET_EMPTY_ERROR(*stmt->error_info);
1576 SET_EMPTY_ERROR(*stmt->conn->error_info);
1577
1578 if (stmt->field_count) {
1579 unsigned int i = 0;
1580
1581 if (!result_bind) {
1582 DBG_ERR("no result bind passed");
1583 DBG_RETURN(FAIL);
1584 }
1585
1586 mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
1587 stmt->result_zvals_separated_once = FALSE;
1588 stmt->result_bind = result_bind;
1589 for (i = 0; i < stmt->field_count; i++) {
1590
1591 Z_ADDREF_P(stmt->result_bind[i].zv);
1592 DBG_INF_FMT("ref of %p = %u", stmt->result_bind[i].zv, Z_REFCOUNT_P(stmt->result_bind[i].zv));
1593
1594
1595
1596
1597
1598 stmt->result_bind[i].bound = TRUE;
1599 }
1600 } else if (result_bind) {
1601 s->m->free_result_bind(s, result_bind TSRMLS_CC);
1602 }
1603 DBG_INF("PASS");
1604 DBG_RETURN(PASS);
1605 }
1606
1607
1608
1609
1610 static enum_func_status
1611 MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
1612 {
1613 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1614 DBG_ENTER("mysqlnd_stmt::bind_result");
1615 if (!stmt || !stmt->conn) {
1616 DBG_RETURN(FAIL);
1617 }
1618 DBG_INF_FMT("stmt=%lu field_count=%u", stmt->stmt_id, stmt->field_count);
1619
1620 if (stmt->state < MYSQLND_STMT_PREPARED) {
1621 SET_STMT_ERROR(stmt, CR_NO_PREPARE_STMT, UNKNOWN_SQLSTATE, mysqlnd_stmt_not_prepared);
1622 DBG_ERR("not prepared");
1623 DBG_RETURN(FAIL);
1624 }
1625
1626 if (param_no >= stmt->field_count) {
1627 SET_STMT_ERROR(stmt, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
1628 DBG_ERR("invalid param_no");
1629 DBG_RETURN(FAIL);
1630 }
1631
1632 SET_EMPTY_ERROR(*stmt->error_info);
1633 SET_EMPTY_ERROR(*stmt->conn->error_info);
1634
1635 if (stmt->field_count) {
1636 mysqlnd_stmt_separate_one_result_bind(s, param_no TSRMLS_CC);
1637
1638 if (!stmt->result_bind) {
1639 stmt->result_bind = mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent);
1640 } else {
1641 stmt->result_bind = mnd_perealloc(stmt->result_bind, stmt->field_count * sizeof(MYSQLND_RESULT_BIND), stmt->persistent);
1642 }
1643 if (!stmt->result_bind) {
1644 DBG_RETURN(FAIL);
1645 }
1646 ALLOC_INIT_ZVAL(stmt->result_bind[param_no].zv);
1647
1648
1649
1650
1651
1652 stmt->result_bind[param_no].bound = TRUE;
1653 }
1654 DBG_INF("PASS");
1655 DBG_RETURN(PASS);
1656 }
1657
1658
1659
1660
1661 static uint64_t
1662 MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s TSRMLS_DC)
1663 {
1664 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1665 return stmt? stmt->upsert_status->last_insert_id : 0;
1666 }
1667
1668
1669
1670
1671 static uint64_t
1672 MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
1673 {
1674 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1675 return stmt? stmt->upsert_status->affected_rows : 0;
1676 }
1677
1678
1679
1680
1681 static uint64_t
1682 MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const s TSRMLS_DC)
1683 {
1684 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1685 return stmt && stmt->result? mysqlnd_num_rows(stmt->result):0;
1686 }
1687
1688
1689
1690
1691 static unsigned int
1692 MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s TSRMLS_DC)
1693 {
1694 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1695 return stmt? stmt->upsert_status->warning_count : 0;
1696 }
1697
1698
1699
1700
1701 static unsigned int
1702 MYSQLND_METHOD(mysqlnd_stmt, server_status)(const MYSQLND_STMT * const s TSRMLS_DC)
1703 {
1704 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1705 return stmt? stmt->upsert_status->server_status : 0;
1706 }
1707
1708
1709
1710
1711 static unsigned int
1712 MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const s TSRMLS_DC)
1713 {
1714 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1715 return stmt? stmt->field_count : 0;
1716 }
1717
1718
1719
1720
1721 static unsigned int
1722 MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const s TSRMLS_DC)
1723 {
1724 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1725 return stmt? stmt->param_count : 0;
1726 }
1727
1728
1729
1730
1731 static unsigned int
1732 MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s TSRMLS_DC)
1733 {
1734 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1735 return stmt? stmt->error_info->error_no : 0;
1736 }
1737
1738
1739
1740
1741 static const char *
1742 MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s TSRMLS_DC)
1743 {
1744 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1745 return stmt? stmt->error_info->error : 0;
1746 }
1747
1748
1749
1750
1751 static const char *
1752 MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s TSRMLS_DC)
1753 {
1754 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1755 return stmt && stmt->error_info->sqlstate[0] ? stmt->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
1756 }
1757
1758
1759
1760
1761 static enum_func_status
1762 MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const s, uint64_t row TSRMLS_DC)
1763 {
1764 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1765 return stmt && stmt->result? stmt->result->m.seek_data(stmt->result, row TSRMLS_CC) : FAIL;
1766 }
1767
1768
1769
1770
1771 static MYSQLND_RES *
1772 MYSQLND_METHOD(mysqlnd_stmt, param_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
1773 {
1774 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1775 if (!stmt || !stmt->param_count) {
1776 return NULL;
1777 }
1778 return NULL;
1779 }
1780
1781
1782
1783
1784 static MYSQLND_RES *
1785 MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s TSRMLS_DC)
1786 {
1787 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1788 MYSQLND_RES *result;
1789
1790 DBG_ENTER("mysqlnd_stmt::result_metadata");
1791 if (!stmt) {
1792 DBG_RETURN(NULL);
1793 }
1794 DBG_INF_FMT("stmt=%u field_count=%u", stmt->stmt_id, stmt->field_count);
1795
1796 if (!stmt->field_count || !stmt->conn || !stmt->result || !stmt->result->meta) {
1797 DBG_INF("NULL");
1798 DBG_RETURN(NULL);
1799 }
1800
1801 if (stmt->update_max_length && stmt->result->stored_data) {
1802
1803 stmt->result->stored_data->m.initialize_result_set_rest(stmt->result->stored_data, stmt->result->meta, stmt->conn->stats,
1804 stmt->conn->options->int_and_float_native TSRMLS_CC);
1805 }
1806
1807
1808
1809
1810
1811
1812
1813
1814
1815 do {
1816 result = stmt->conn->m->result_init(stmt->field_count, stmt->persistent TSRMLS_CC);
1817 if (!result) {
1818 break;
1819 }
1820 result->type = MYSQLND_RES_NORMAL;
1821 result->unbuf = mysqlnd_result_unbuffered_init(stmt->field_count, TRUE, result->persistent TSRMLS_CC);
1822 if (!result->unbuf) {
1823 break;
1824 }
1825 result->unbuf->eof_reached = TRUE;
1826 result->meta = stmt->result->meta->m->clone_metadata(stmt->result->meta, FALSE TSRMLS_CC);
1827 if (!result->meta) {
1828 break;
1829 }
1830
1831 DBG_INF_FMT("result=%p", result);
1832 DBG_RETURN(result);
1833 } while (0);
1834
1835 SET_OOM_ERROR(*stmt->conn->error_info);
1836 if (result) {
1837 result->m.free_result(result, TRUE TSRMLS_CC);
1838 }
1839 DBG_RETURN(NULL);
1840 }
1841
1842
1843
1844
1845 static enum_func_status
1846 MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
1847 enum mysqlnd_stmt_attr attr_type,
1848 const void * const value TSRMLS_DC)
1849 {
1850 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1851 DBG_ENTER("mysqlnd_stmt::attr_set");
1852 if (!stmt) {
1853 DBG_RETURN(FAIL);
1854 }
1855 DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
1856
1857 switch (attr_type) {
1858 case STMT_ATTR_UPDATE_MAX_LENGTH:{
1859 zend_uchar bval = *(zend_uchar *) value;
1860
1861
1862
1863
1864 stmt->update_max_length = bval? TRUE:FALSE;
1865 break;
1866 }
1867 case STMT_ATTR_CURSOR_TYPE: {
1868 unsigned int ival = *(unsigned int *) value;
1869 if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) {
1870 SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
1871 DBG_INF("FAIL");
1872 DBG_RETURN(FAIL);
1873 }
1874 stmt->flags = ival;
1875 break;
1876 }
1877 case STMT_ATTR_PREFETCH_ROWS: {
1878 unsigned int ival = *(unsigned int *) value;
1879 if (ival == 0) {
1880 ival = MYSQLND_DEFAULT_PREFETCH_ROWS;
1881 } else if (ival > 1) {
1882 SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
1883 DBG_INF("FAIL");
1884 DBG_RETURN(FAIL);
1885 }
1886 stmt->prefetch_rows = ival;
1887 break;
1888 }
1889 default:
1890 SET_STMT_ERROR(stmt, CR_NOT_IMPLEMENTED, UNKNOWN_SQLSTATE, "Not implemented");
1891 DBG_RETURN(FAIL);
1892 }
1893 DBG_INF("PASS");
1894 DBG_RETURN(PASS);
1895 }
1896
1897
1898
1899
1900 static enum_func_status
1901 MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
1902 enum mysqlnd_stmt_attr attr_type,
1903 void * const value TSRMLS_DC)
1904 {
1905 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1906 DBG_ENTER("mysqlnd_stmt::attr_set");
1907 if (!stmt) {
1908 DBG_RETURN(FAIL);
1909 }
1910 DBG_INF_FMT("stmt=%lu attr_type=%u", stmt->stmt_id, attr_type);
1911
1912 switch (attr_type) {
1913 case STMT_ATTR_UPDATE_MAX_LENGTH:
1914 *(zend_bool *) value= stmt->update_max_length;
1915 break;
1916 case STMT_ATTR_CURSOR_TYPE:
1917 *(unsigned long *) value= stmt->flags;
1918 break;
1919 case STMT_ATTR_PREFETCH_ROWS:
1920 *(unsigned long *) value= stmt->prefetch_rows;
1921 break;
1922 default:
1923 DBG_RETURN(FAIL);
1924 }
1925 DBG_INF_FMT("value=%lu", value);
1926 DBG_RETURN(PASS);
1927 }
1928
1929
1930
1931
1932
1933 static enum_func_status
1934 MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s TSRMLS_DC)
1935 {
1936 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1937 DBG_ENTER("mysqlnd_stmt::free_result");
1938 if (!stmt || !stmt->conn) {
1939 DBG_RETURN(FAIL);
1940 }
1941 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
1942
1943 if (!stmt->result) {
1944 DBG_INF("no result");
1945 DBG_RETURN(PASS);
1946 }
1947
1948
1949
1950
1951
1952 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
1953 DBG_INF("fetching result set header");
1954
1955 stmt->default_rset_handler = s->m->use_result;
1956 stmt->default_rset_handler(s TSRMLS_CC);
1957 }
1958
1959 if (stmt->state > MYSQLND_STMT_WAITING_USE_OR_STORE) {
1960 DBG_INF("skipping result");
1961
1962 stmt->result->m.skip_result(stmt->result TSRMLS_CC);
1963
1964
1965
1966
1967 mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
1968
1969
1970 stmt->result->m.free_result_buffers(stmt->result TSRMLS_CC);
1971 }
1972
1973 if (stmt->state > MYSQLND_STMT_PREPARED) {
1974
1975 stmt->state = MYSQLND_STMT_PREPARED;
1976 }
1977
1978
1979 CONN_SET_STATE(stmt->conn, CONN_READY);
1980
1981 DBG_RETURN(PASS);
1982 }
1983
1984
1985
1986
1987 static void
1988 mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s TSRMLS_DC)
1989 {
1990 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
1991 unsigned int i;
1992
1993 DBG_ENTER("mysqlnd_stmt_separate_result_bind");
1994 if (!stmt) {
1995 DBG_VOID_RETURN;
1996 }
1997 DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count);
1998
1999 if (!stmt->result_bind) {
2000 DBG_VOID_RETURN;
2001 }
2002
2003
2004
2005
2006
2007
2008 for (i = 0; i < stmt->field_count; i++) {
2009
2010 if (stmt->result_bind[i].bound == TRUE) {
2011 DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNT_P(stmt->result_bind[i].zv));
2012
2013
2014
2015
2016 if (Z_REFCOUNT_P(stmt->result_bind[i].zv) > 1) {
2017 #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
2018 zval_copy_ctor(stmt->result_bind[i].zv);
2019 #endif
2020 zval_ptr_dtor(&stmt->result_bind[i].zv);
2021 } else {
2022
2023
2024
2025
2026
2027 #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
2028 ZVAL_NULL(stmt->result_bind[i].zv);
2029 #endif
2030 zval_ptr_dtor(&stmt->result_bind[i].zv);
2031 }
2032 }
2033 }
2034 s->m->free_result_bind(s, stmt->result_bind TSRMLS_CC);
2035 stmt->result_bind = NULL;
2036
2037 DBG_VOID_RETURN;
2038 }
2039
2040
2041
2042
2043 static void
2044 mysqlnd_stmt_separate_one_result_bind(MYSQLND_STMT * const s, unsigned int param_no TSRMLS_DC)
2045 {
2046 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2047 DBG_ENTER("mysqlnd_stmt_separate_one_result_bind");
2048 if (!stmt) {
2049 DBG_VOID_RETURN;
2050 }
2051 DBG_INF_FMT("stmt=%lu result_bind=%p field_count=%u param_no=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count, param_no);
2052
2053 if (!stmt->result_bind) {
2054 DBG_VOID_RETURN;
2055 }
2056
2057
2058
2059
2060
2061
2062
2063 if (stmt->result_bind[param_no].bound == TRUE) {
2064 DBG_INF_FMT("%u has refcount=%u", param_no, Z_REFCOUNT_P(stmt->result_bind[param_no].zv));
2065
2066
2067
2068
2069 if (Z_REFCOUNT_P(stmt->result_bind[param_no].zv) > 1) {
2070 #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
2071 zval_copy_ctor(stmt->result_bind[param_no].zv);
2072 #endif
2073 zval_ptr_dtor(&stmt->result_bind[param_no].zv);
2074 } else {
2075
2076
2077
2078
2079
2080 #ifdef WE_DONT_COPY_IN_BUFFERED_AND_UNBUFFERED_BECAUSEOF_IS_REF
2081 ZVAL_NULL(stmt->result_bind[param_no].zv);
2082 #endif
2083 zval_ptr_dtor(&stmt->result_bind[param_no].zv);
2084 }
2085 }
2086
2087 DBG_VOID_RETURN;
2088 }
2089
2090
2091
2092
2093 static void
2094 MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(MYSQLND_STMT * const s TSRMLS_DC)
2095 {
2096 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2097 DBG_ENTER("mysqlnd_stmt::free_stmt_result");
2098 if (!stmt) {
2099 DBG_VOID_RETURN;
2100 }
2101
2102
2103
2104
2105
2106 mysqlnd_stmt_separate_result_bind(s TSRMLS_CC);
2107
2108 if (stmt->result) {
2109 stmt->result->m.free_result_internal(stmt->result TSRMLS_CC);
2110 stmt->result = NULL;
2111 }
2112 if (stmt->error_info->error_list) {
2113 zend_llist_clean(stmt->error_info->error_list);
2114 mnd_pefree(stmt->error_info->error_list, s->persistent);
2115 stmt->error_info->error_list = NULL;
2116 }
2117
2118 DBG_VOID_RETURN;
2119 }
2120
2121
2122
2123
2124 static void
2125 MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s TSRMLS_DC)
2126 {
2127 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2128 DBG_ENTER("mysqlnd_stmt::free_stmt_content");
2129 if (!stmt) {
2130 DBG_VOID_RETURN;
2131 }
2132 DBG_INF_FMT("stmt=%lu param_bind=%p param_count=%u", stmt->stmt_id, stmt->param_bind, stmt->param_count);
2133
2134
2135 if (stmt->param_bind) {
2136 unsigned int i;
2137
2138
2139
2140
2141
2142 for (i = 0; i < stmt->param_count; i++) {
2143
2144
2145
2146
2147 if (stmt->param_bind[i].zv) {
2148 zval_ptr_dtor(&stmt->param_bind[i].zv);
2149 }
2150 }
2151 s->m->free_parameter_bind(s, stmt->param_bind TSRMLS_CC);
2152 stmt->param_bind = NULL;
2153 }
2154
2155 s->m->free_stmt_result(s TSRMLS_CC);
2156 DBG_VOID_RETURN;
2157 }
2158
2159
2160
2161
2162 static enum_func_status
2163 MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
2164 {
2165 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2166 MYSQLND_CONN_DATA * conn;
2167 zend_uchar cmd_buf[STMT_ID_LENGTH ];
2168 enum_mysqlnd_collected_stats statistic = STAT_LAST;
2169
2170 DBG_ENTER("mysqlnd_stmt::net_close");
2171 if (!stmt || !stmt->conn) {
2172 DBG_RETURN(FAIL);
2173 }
2174 DBG_INF_FMT("stmt=%lu", stmt->stmt_id);
2175
2176 conn = stmt->conn;
2177
2178 SET_EMPTY_ERROR(*stmt->error_info);
2179 SET_EMPTY_ERROR(*stmt->conn->error_info);
2180
2181
2182
2183
2184
2185
2186 do {
2187 if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
2188 DBG_INF("fetching result set header");
2189 stmt->default_rset_handler(s TSRMLS_CC);
2190 stmt->state = MYSQLND_STMT_USER_FETCHING;
2191 }
2192
2193
2194 if (stmt->result) {
2195 DBG_INF("skipping result");
2196 stmt->result->m.skip_result(stmt->result TSRMLS_CC);
2197 }
2198 } while (mysqlnd_stmt_more_results(s) && mysqlnd_stmt_next_result(s) == PASS);
2199
2200
2201
2202
2203 if (stmt->stmt_id) {
2204 MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_FREE_RESULT_IMPLICIT:
2205 STAT_FREE_RESULT_EXPLICIT);
2206
2207 int4store(cmd_buf, stmt->stmt_id);
2208 if (CONN_GET_STATE(conn) == CONN_READY &&
2209 FAIL == conn->m->simple_command(conn, COM_STMT_CLOSE, cmd_buf, sizeof(cmd_buf),
2210 PROT_LAST ,
2211 FALSE, TRUE TSRMLS_CC)) {
2212 COPY_CLIENT_ERROR(*stmt->error_info, *conn->error_info);
2213 DBG_RETURN(FAIL);
2214 }
2215 }
2216 switch (stmt->execute_count) {
2217 case 0:
2218 statistic = STAT_PS_PREPARED_NEVER_EXECUTED;
2219 break;
2220 case 1:
2221 statistic = STAT_PS_PREPARED_ONCE_USED;
2222 break;
2223 default:
2224 break;
2225 }
2226 if (statistic != STAT_LAST) {
2227 MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
2228 }
2229
2230 if (stmt->execute_cmd_buffer.buffer) {
2231 mnd_pefree(stmt->execute_cmd_buffer.buffer, stmt->persistent);
2232 stmt->execute_cmd_buffer.buffer = NULL;
2233 }
2234
2235 s->m->free_stmt_content(s TSRMLS_CC);
2236
2237 if (stmt->conn) {
2238 stmt->conn->m->free_reference(stmt->conn TSRMLS_CC);
2239 stmt->conn = NULL;
2240 }
2241
2242 DBG_RETURN(PASS);
2243 }
2244
2245
2246
2247 static enum_func_status
2248 MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, zend_bool implicit TSRMLS_DC)
2249 {
2250 MYSQLND_STMT_DATA * stmt = (s != NULL) ? s->data:NULL;
2251 enum_func_status ret = FAIL;
2252 zend_bool persistent = (s != NULL) ? s->persistent : 0;
2253
2254 DBG_ENTER("mysqlnd_stmt::dtor");
2255 if (stmt) {
2256 DBG_INF_FMT("stmt=%p", stmt);
2257
2258 MYSQLND_INC_GLOBAL_STATISTIC(implicit == TRUE? STAT_STMT_CLOSE_IMPLICIT:
2259 STAT_STMT_CLOSE_EXPLICIT);
2260
2261 ret = s->m->net_close(s, implicit TSRMLS_CC);
2262 mnd_pefree(stmt, persistent);
2263 }
2264 mnd_pefree(s, persistent);
2265
2266 DBG_INF(ret == PASS? "PASS":"FAIL");
2267 DBG_RETURN(ret);
2268 }
2269
2270
2271
2272
2273 static MYSQLND_PARAM_BIND *
2274 MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind)(MYSQLND_STMT * const s TSRMLS_DC)
2275 {
2276 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2277 DBG_ENTER("mysqlnd_stmt::alloc_param_bind");
2278 if (!stmt) {
2279 DBG_RETURN(NULL);
2280 }
2281 DBG_RETURN(mnd_pecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND), stmt->persistent));
2282 }
2283
2284
2285
2286
2287 static MYSQLND_RESULT_BIND *
2288 MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind)(MYSQLND_STMT * const s TSRMLS_DC)
2289 {
2290 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2291 DBG_ENTER("mysqlnd_stmt::alloc_result_bind");
2292 if (!stmt) {
2293 DBG_RETURN(NULL);
2294 }
2295 DBG_RETURN(mnd_pecalloc(stmt->field_count, sizeof(MYSQLND_RESULT_BIND), stmt->persistent));
2296 }
2297
2298
2299
2300
2301 PHPAPI void
2302 MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * param_bind TSRMLS_DC)
2303 {
2304 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2305 if (stmt) {
2306 mnd_pefree(param_bind, stmt->persistent);
2307 }
2308 }
2309
2310
2311
2312
2313 PHPAPI void
2314 MYSQLND_METHOD(mysqlnd_stmt, free_result_bind)(MYSQLND_STMT * const s, MYSQLND_RESULT_BIND * result_bind TSRMLS_DC)
2315 {
2316 MYSQLND_STMT_DATA * stmt = s? s->data:NULL;
2317 if (stmt) {
2318 mnd_pefree(result_bind, stmt->persistent);
2319 }
2320 }
2321
2322
2323
2324
2325 MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
2326 MYSQLND_METHOD(mysqlnd_stmt, prepare),
2327 MYSQLND_METHOD(mysqlnd_stmt, execute),
2328 MYSQLND_METHOD(mysqlnd_stmt, use_result),
2329 MYSQLND_METHOD(mysqlnd_stmt, store_result),
2330 MYSQLND_METHOD(mysqlnd_stmt, get_result),
2331 MYSQLND_METHOD(mysqlnd_stmt, more_results),
2332 MYSQLND_METHOD(mysqlnd_stmt, next_result),
2333 MYSQLND_METHOD(mysqlnd_stmt, free_result),
2334 MYSQLND_METHOD(mysqlnd_stmt, data_seek),
2335 MYSQLND_METHOD(mysqlnd_stmt, reset),
2336 MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, net_close),
2337 MYSQLND_METHOD(mysqlnd_stmt, dtor),
2338
2339 MYSQLND_METHOD(mysqlnd_stmt, fetch),
2340
2341 MYSQLND_METHOD(mysqlnd_stmt, bind_parameters),
2342 MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter),
2343 MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
2344 MYSQLND_METHOD(mysqlnd_stmt, bind_result),
2345 MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
2346 MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
2347 MYSQLND_METHOD(mysqlnd_stmt, param_metadata),
2348 MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
2349
2350 MYSQLND_METHOD(mysqlnd_stmt, insert_id),
2351 MYSQLND_METHOD(mysqlnd_stmt, affected_rows),
2352 MYSQLND_METHOD(mysqlnd_stmt, num_rows),
2353
2354 MYSQLND_METHOD(mysqlnd_stmt, param_count),
2355 MYSQLND_METHOD(mysqlnd_stmt, field_count),
2356 MYSQLND_METHOD(mysqlnd_stmt, warning_count),
2357
2358 MYSQLND_METHOD(mysqlnd_stmt, errno),
2359 MYSQLND_METHOD(mysqlnd_stmt, error),
2360 MYSQLND_METHOD(mysqlnd_stmt, sqlstate),
2361
2362 MYSQLND_METHOD(mysqlnd_stmt, attr_get),
2363 MYSQLND_METHOD(mysqlnd_stmt, attr_set),
2364
2365
2366 MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind),
2367 MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind),
2368 MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind),
2369 MYSQLND_METHOD(mysqlnd_stmt, free_result_bind),
2370 MYSQLND_METHOD(mysqlnd_stmt, server_status),
2371 mysqlnd_stmt_execute_generate_request,
2372 mysqlnd_stmt_execute_parse_response,
2373 MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content),
2374 MYSQLND_METHOD(mysqlnd_stmt, flush),
2375 MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)
2376 MYSQLND_CLASS_METHODS_END;
2377
2378
2379
2380 MYSQLND_STMT *
2381 _mysqlnd_stmt_init(MYSQLND_CONN_DATA * const conn TSRMLS_DC)
2382 {
2383 MYSQLND_STMT * ret;
2384 DBG_ENTER("_mysqlnd_stmt_init");
2385 ret = MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_object_factory).get_prepared_statement(conn TSRMLS_CC);
2386 DBG_RETURN(ret);
2387 }
2388
2389
2390
2391
2392 void _mysqlnd_init_ps_subsystem()
2393 {
2394 mysqlnd_stmt_set_methods(&MYSQLND_CLASS_METHOD_TABLE_NAME(mysqlnd_stmt));
2395 _mysqlnd_init_ps_fetch_subsystem();
2396 }
2397
2398
2399
2400
2401
2402
2403
2404
2405
2406
2407