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