php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
mysqlnd_ps.c
Go to the documentation of this file.
1/*
2 +----------------------------------------------------------------------+
3 | Copyright (c) The PHP Group |
4 +----------------------------------------------------------------------+
5 | This source file is subject to version 3.01 of the PHP license, |
6 | that is bundled with this package in the file LICENSE, and is |
7 | available through the world-wide-web at the following url: |
8 | https://www.php.net/license/3_01.txt |
9 | If you did not receive a copy of the PHP license and are unable to |
10 | obtain it through the world-wide-web, please send a note to |
11 | license@php.net so we can mail you a copy immediately. |
12 +----------------------------------------------------------------------+
13 | Authors: Andrey Hristov <andrey@php.net> |
14 | Ulf Wendel <uw@php.net> |
15 +----------------------------------------------------------------------+
16*/
17
18#include "php.h"
19#include "mysqlnd.h"
21#include "mysqlnd_connection.h"
22#include "mysqlnd_priv.h"
23#include "mysqlnd_ps.h"
24#include "mysqlnd_result.h"
25#include "mysqlnd_result_meta.h"
26#include "mysqlnd_statistics.h"
27#include "mysqlnd_debug.h"
28#include "mysqlnd_block_alloc.h"
29#include "mysqlnd_ext_plugin.h"
30
31const char * const mysqlnd_not_bound_as_blob = "Can't send long data for non-string/non-binary data types";
32const char * const mysqlnd_stmt_not_prepared = "Statement not prepared";
33
34/* Exported by mysqlnd_ps_codec.c */
35enum_func_status mysqlnd_stmt_execute_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, bool * free_buffer);
36enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT * const s, zend_uchar ** request, size_t *request_len, bool * free_buffer);
37
38static void mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const stmt);
39
40static enum_func_status mysqlnd_stmt_send_cursor_fetch_command(
41 const MYSQLND_STMT_DATA *stmt, unsigned max_rows)
42{
43 MYSQLND_CONN_DATA *conn = stmt->conn;
44 zend_uchar buf[MYSQLND_STMT_ID_LENGTH /* statement id */ + 4 /* number of rows to fetch */];
45 const MYSQLND_CSTRING payload = {(const char*) buf, sizeof(buf)};
46
47 int4store(buf, stmt->stmt_id);
49
50 if (conn->command->stmt_fetch(conn, payload) == FAIL) {
52 return FAIL;
53 }
54 return PASS;
55}
56
57static bool mysqlnd_stmt_check_state(const MYSQLND_STMT_DATA *stmt)
58{
59 const MYSQLND_CONN_DATA *conn = stmt->conn;
61 return 0;
62 }
63 if (stmt->cursor_exists) {
64 return GET_CONNECTION_STATE(&conn->state) == CONN_READY;
65 } else {
67 }
68}
69
70/* {{{ mysqlnd_stmt::store_result */
71static MYSQLND_RES *
72MYSQLND_METHOD(mysqlnd_stmt, store_result)(MYSQLND_STMT * const s)
73{
75 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
76 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
78
79 DBG_ENTER("mysqlnd_stmt::store_result");
80 if (!stmt || !conn || !stmt->result) {
82 }
83 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
84
85 /* be compliant with libmysql - NULL will turn */
86 if (!stmt->field_count) {
88 }
89
90 /* Nothing to store for UPSERT/LOAD DATA*/
91 if (!mysqlnd_stmt_check_state(stmt)) {
94 }
95
96 stmt->default_rset_handler = s->m->store_result;
97
101
102 if (stmt->cursor_exists) {
103 if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
105 }
106 }
107
108 result = stmt->result;
110/* result->m.row_decoder = php_mysqlnd_rowp_read_binary_protocol; */
111
112 result->stored_data = mysqlnd_result_buffered_init(result, result->field_count, stmt);
113 if (!result->stored_data) {
116 }
117
118 ret = result->m.store_result_fetch_data(conn, result, result->meta, &result->stored_data->row_buffers, TRUE);
119
120 if (PASS == ret) {
121 result->stored_data->current_row = 0;
122
123 /* libmysql API docs say it should be so for SELECT statements */
125
127 } else {
128 COPY_CLIENT_ERROR(conn->error_info, result->stored_data->error_info);
129 COPY_CLIENT_ERROR(stmt->error_info, result->stored_data->error_info);
130 stmt->result->m.free_result_contents(stmt->result);
131 stmt->result = NULL;
134 }
135
137}
138/* }}} */
139
140
141/* {{{ mysqlnd_stmt::get_result */
142static MYSQLND_RES *
143MYSQLND_METHOD(mysqlnd_stmt, get_result)(MYSQLND_STMT * const s)
144{
145 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
146 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
148
149 DBG_ENTER("mysqlnd_stmt::get_result");
150 if (!stmt || !conn || !stmt->result) {
152 }
153 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
154
155 /* be compliant with libmysql - NULL will turn */
156 if (!stmt->field_count) {
158 }
159
160 /* Nothing to store for UPSERT/LOAD DATA*/
161 if (!mysqlnd_stmt_check_state(stmt)) {
164 }
165
169
170 if (stmt->cursor_exists) {
171 if (mysqlnd_stmt_send_cursor_fetch_command(stmt, -1) == FAIL) {
173 }
174 }
175
176 do {
177 result = conn->m->result_init(stmt->result->field_count);
178 if (!result) {
180 break;
181 }
182
183 result->meta = stmt->result->meta->m->clone_metadata(result, stmt->result->meta);
184 if (!result->meta) {
186 break;
187 }
188
189 if (result->m.store_result(result, conn, stmt)) {
190 UPSERT_STATUS_SET_AFFECTED_ROWS(stmt->upsert_status, result->stored_data->row_count);
193 } else {
196 break;
197 }
199 } while (0);
200
201 if (result) {
202 result->m.free_result(result, TRUE);
203 }
205}
206/* }}} */
207
208
209/* {{{ mysqlnd_stmt::more_results */
210static bool
211MYSQLND_METHOD(mysqlnd_stmt, more_results)(const MYSQLND_STMT * s)
212{
213 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
214 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
215 DBG_ENTER("mysqlnd_stmt::more_results");
216 /* (conn->state == CONN_NEXT_RESULT_PENDING) too */
217 DBG_RETURN((stmt && conn && (conn->m->get_server_status(conn) & SERVER_MORE_RESULTS_EXISTS))? TRUE: FALSE);
218}
219/* }}} */
220
221
222/* {{{ mysqlnd_stmt::next_result */
223static enum_func_status
224MYSQLND_METHOD(mysqlnd_stmt, next_result)(MYSQLND_STMT * s)
225{
226 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
227 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
228
229 DBG_ENTER("mysqlnd_stmt::next_result");
230 if (!stmt || !conn || !stmt->result) {
232 }
233 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
234
237 }
238
240
241 /* Free space for next result */
242 s->m->free_stmt_result(s);
243 {
246 }
247}
248/* }}} */
249
250
251/* {{{ mysqlnd_stmt_skip_metadata */
252static enum_func_status
253mysqlnd_stmt_skip_metadata(MYSQLND_STMT * s)
254{
255 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
256 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
257 /* Follows parameter metadata, we have just to skip it, as libmysql does */
258 unsigned int i = 0;
260 MYSQLND_PACKET_RES_FIELD field_packet;
261 MYSQLND_MEMORY_POOL * pool;
262
263 DBG_ENTER("mysqlnd_stmt_skip_metadata");
264 if (!stmt || !conn) {
266 }
268 if (!pool) {
270 }
271 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
272
273 conn->payload_decoder_factory->m.init_result_field_packet(&field_packet);
274 field_packet.memory_pool = pool;
275
276 ret = PASS;
277 field_packet.skip_parsing = TRUE;
278 for (;i < stmt->param_count; i++) {
279 if (FAIL == PACKET_READ(conn, &field_packet)) {
280 ret = FAIL;
281 break;
282 }
283 }
284 PACKET_FREE(&field_packet);
286
288}
289/* }}} */
290
291
292/* {{{ mysqlnd_stmt_read_prepare_response */
293static enum_func_status
294mysqlnd_stmt_read_prepare_response(MYSQLND_STMT * s)
295{
296 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
297 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
300
301 DBG_ENTER("mysqlnd_stmt_read_prepare_response");
302 if (!stmt || !conn) {
304 }
305 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
306
307 conn->payload_decoder_factory->m.init_prepare_response_packet(&prepare_resp);
308
309 if (FAIL == PACKET_READ(conn, &prepare_resp)) {
310 goto done;
311 }
312
313 if (0xFF == prepare_resp.error_code) {
314 COPY_CLIENT_ERROR(stmt->error_info, prepare_resp.error_info);
315 COPY_CLIENT_ERROR(conn->error_info, prepare_resp.error_info);
316 goto done;
317 }
318 ret = PASS;
319 stmt->stmt_id = prepare_resp.stmt_id;
321 UPSERT_STATUS_SET_AFFECTED_ROWS(stmt->upsert_status, 0); /* be like libmysql */
322 stmt->field_count = conn->field_count = prepare_resp.field_count;
323 stmt->param_count = prepare_resp.param_count;
324done:
325 PACKET_FREE(&prepare_resp);
326
328}
329/* }}} */
330
331
332/* {{{ mysqlnd_stmt_prepare_read_eof */
333static enum_func_status
334mysqlnd_stmt_prepare_read_eof(MYSQLND_STMT * s)
335{
336 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
337 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
338 MYSQLND_PACKET_EOF fields_eof;
340
341 DBG_ENTER("mysqlnd_stmt_prepare_read_eof");
342 if (!stmt || !conn) {
344 }
345 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
346
347 conn->payload_decoder_factory->m.init_eof_packet(&fields_eof);
348 if (FAIL == (ret = PACKET_READ(conn, &fields_eof))) {
349 if (stmt->result) {
350 stmt->result->m.free_result_contents(stmt->result);
351 /* XXX: This will crash, because we will null also the methods.
352 But seems it happens in extreme cases or doesn't. Should be fixed by exporting a function
353 (from mysqlnd_driver.c?) to do the reset.
354 This bad handling is also in mysqlnd_result.c
355 */
356 memset(stmt, 0, sizeof(MYSQLND_STMT_DATA));
358 }
359 } else {
363 }
364
366}
367/* }}} */
368
369
370/* {{{ mysqlnd_stmt::prepare */
371static enum_func_status
372MYSQLND_METHOD(mysqlnd_stmt, prepare)(MYSQLND_STMT * const s, const char * const query, const size_t query_len)
373{
374 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
375 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
376
377 DBG_ENTER("mysqlnd_stmt::prepare");
378 if (!stmt || !conn) {
380 }
381 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
382 DBG_INF_FMT("query=%s", query);
383
386
389
390 if (stmt->state > MYSQLND_STMT_INITTED) {
391 /*
392 Create a new prepared statement and destroy the previous one.
393 */
394 MYSQLND_STMT * s_to_prepare = conn->m->stmt_init(conn);
395 if (!s_to_prepare) {
396 goto fail;
397 }
398 MYSQLND_STMT_DATA * stmt_to_prepare = s_to_prepare->data;
399
400 /* swap */
401 size_t real_size = sizeof(MYSQLND_STMT) + mysqlnd_plugin_count() * sizeof(void *);
402 char * tmp_swap = mnd_emalloc(real_size);
403 memcpy(tmp_swap, s, real_size);
404 memcpy(s, s_to_prepare, real_size);
405 memcpy(s_to_prepare, tmp_swap, real_size);
406 mnd_efree(tmp_swap);
407 {
408 MYSQLND_STMT_DATA * tmp_swap_data = stmt_to_prepare;
409 stmt_to_prepare = stmt;
410 stmt = tmp_swap_data;
411 }
412 s_to_prepare->m->dtor(s_to_prepare, TRUE);
413 }
414
415 {
417 const MYSQLND_CSTRING query_string = {query, query_len};
418
419 ret = conn->command->stmt_prepare(conn, query_string);
420 if (FAIL == ret) {
422 goto fail;
423 }
424 }
425
426 if (FAIL == mysqlnd_stmt_read_prepare_response(s)) {
427 goto fail;
428 }
429
430 if (stmt->param_count) {
431 if (FAIL == mysqlnd_stmt_skip_metadata(s) ||
432 FAIL == mysqlnd_stmt_prepare_read_eof(s))
433 {
434 goto fail;
435 }
436 }
437
438 /*
439 Read metadata only if there is actual result set.
440 Beware that SHOW statements bypass the PS framework and thus they send
441 no metadata at prepare.
442 */
443 if (stmt->field_count) {
444 MYSQLND_RES * result = conn->m->result_init(stmt->field_count);
445 if (!result) {
447 goto fail;
448 }
449 /* Allocate the result now as it is needed for the reading of metadata */
450 stmt->result = result;
451
452 result->conn = conn->m->get_reference(conn);
453
455
456 if (FAIL == result->m.read_result_metadata(result, conn) ||
457 FAIL == mysqlnd_stmt_prepare_read_eof(s))
458 {
459 goto fail;
460 }
461 }
462
464 DBG_INF("PASS");
466
467fail:
468 DBG_INF("FAIL");
470}
471/* }}} */
472
473
474/* {{{ mysqlnd_stmt_execute_parse_response */
475static enum_func_status
477{
478 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
479 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
481
482 DBG_ENTER("mysqlnd_stmt_execute_parse_response");
483 if (!stmt || !conn) {
485 }
487
488 ret = conn->m->query_read_result_set_header(conn, s);
489 if (ret == FAIL) {
494 /* close the statement here, the connection has been closed */
495 }
497 stmt->send_types_to_server = 1;
498 } else {
499 /*
500 stmt->send_types_to_server has already been set to 0 in
501 mysqlnd_stmt_execute_generate_request / mysqlnd_stmt_execute_store_params
502 In case there is a situation in which binding was done for integer and the
503 value is > LONG_MAX or < LONG_MIN, there is string conversion and we have
504 to resend the types. Next execution will also need to resend the type.
505 */
512
515 DBG_INF("PASS");
517 }
518
520 if (!stmt->result->conn) {
521 /*
522 For SHOW we don't create (bypasses PS in server)
523 a result set at prepare and thus a connection was missing
524 */
525 stmt->result->conn = conn->m->get_reference(conn);
526 }
527
528 /* If the field count changed, update the result_bind structure. Ideally result_bind
529 * would only ever be created after execute, in which case the size cannot change anymore,
530 * but at least in mysqli this does not seem enforceable. */
531 if (stmt->result_bind && conn->field_count != stmt->field_count) {
532 if (conn->field_count < stmt->field_count) {
533 /* Number of columns decreased, free bindings. */
534 for (unsigned i = conn->field_count; i < stmt->field_count; i++) {
535 zval_ptr_dtor(&stmt->result_bind[i].zv);
536 }
537 }
538 stmt->result_bind =
540 if (conn->field_count > stmt->field_count) {
541 /* Number of columns increase, initialize new ones. */
542 for (unsigned i = stmt->field_count; i < conn->field_count; i++) {
543 ZVAL_UNDEF(&stmt->result_bind[i].zv);
544 stmt->result_bind[i].bound = false;
545 }
546 }
547 }
548
549 stmt->field_count = stmt->result->field_count = conn->field_count;
550 if (stmt->field_count) {
552 /*
553 We need to set this because the user might not call
554 use_result() or store_result() and we should be able to scrap the
555 data on the line, if he just decides to close the statement.
556 */
557 DBG_INF_FMT("server_status=%u cursor=%u", UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status),
559
560 if (stmt->flags & CURSOR_TYPE_READ_ONLY) {
562 DBG_INF("cursor exists");
563 stmt->cursor_exists = TRUE;
565 /* Only cursor read */
566 stmt->default_rset_handler = s->m->use_result;
567 DBG_INF("use_result");
568 } else {
569 DBG_INF("asked for cursor but got none");
570 /*
571 We have asked for CURSOR but got no cursor, because the condition
572 above is not fulfilled. Then...
573
574 This is a single-row result set, a result set with no rows, EXPLAIN,
575 SHOW VARIABLES, or some other command which either a) bypasses the
576 cursors framework in the server and writes rows directly to the
577 network or b) is more efficient if all (few) result set rows are
578 precached on client and server's resources are freed.
579 */
580 /* preferred is buffered read */
581 stmt->default_rset_handler = s->m->store_result;
582 DBG_INF("store_result");
583 }
584 } else {
585 DBG_INF("no cursor");
586 /* preferred is unbuffered read */
587 stmt->default_rset_handler = s->m->use_result;
588 DBG_INF("use_result");
589 }
590 }
591 }
592#ifndef MYSQLND_DONT_SKIP_OUT_PARAMS_RESULTSET
594 s->m->free_stmt_content(s);
595 DBG_INF("PS OUT Variable RSet, skipping");
596 /* OUT params result set. Skip for now to retain compatibility */
598 }
599#endif
600
602
605 }
606
607 DBG_INF(ret == PASS? "PASS":"FAIL");
609}
610/* }}} */
611
612
613/* {{{ mysqlnd_stmt::execute */
614static enum_func_status
615MYSQLND_METHOD(mysqlnd_stmt, execute)(MYSQLND_STMT * const s)
616{
617 DBG_ENTER("mysqlnd_stmt::execute");
618 if (FAIL == s->m->send_execute(s, MYSQLND_SEND_EXECUTE_IMPLICIT, NULL, NULL) ||
619 FAIL == s->m->parse_execute_response(s, MYSQLND_PARSE_EXEC_RESPONSE_IMPLICIT))
620 {
622 }
624}
625/* }}} */
626
627
628/* {{{ mysqlnd_stmt::send_execute */
629static enum_func_status
630MYSQLND_METHOD(mysqlnd_stmt, send_execute)(MYSQLND_STMT * const s, const enum_mysqlnd_send_execute_type type, zval * read_cb, zval * err_cb)
631{
632 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
633 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
635 zend_uchar *request = NULL;
636 size_t request_len;
637 bool free_request;
638
639 DBG_ENTER("mysqlnd_stmt::send_execute");
640 if (!stmt || !conn) {
642 }
643 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
644
647
648 if (stmt->result && stmt->state >= MYSQLND_STMT_PREPARED && stmt->field_count) {
649 s->m->flush(s);
650
651 /*
652 Executed, but the user hasn't started to fetch
653 This will clean also the metadata, but after the EXECUTE call we will
654 have it again.
655 stmt->result may be freed and nullified by free_stmt_result, transitively called from flush.
656 */
657 if (stmt->result) {
658 stmt->result->m.free_result_buffers(stmt->result);
659 }
660
662 } else if (stmt->state < MYSQLND_STMT_PREPARED) {
663 /* Only initted - error */
665 DBG_INF("FAIL");
667 }
668
669 if (stmt->param_count) {
670 unsigned int i, not_bound = 0;
671 if (!stmt->param_bind) {
672 SET_CLIENT_ERROR(stmt->error_info, CR_PARAMS_NOT_BOUND, UNKNOWN_SQLSTATE, "No data supplied for parameters in prepared statement");
673 DBG_INF("FAIL");
675 }
676 for (i = 0; i < stmt->param_count; i++) {
677 if (Z_ISUNDEF(stmt->param_bind[i].zv)) {
678 not_bound++;
679 }
680 }
681 if (not_bound) {
682 char * msg;
683 mnd_sprintf(&msg, 0, "No data supplied for %u parameter%s in prepared statement",
684 not_bound, not_bound>1 ?"s":"");
686 if (msg) {
688 }
689 DBG_INF("FAIL");
691 }
692 }
693 ret = s->m->generate_execute_request(s, &request, &request_len, &free_request);
694 if (ret == PASS) {
695 const MYSQLND_CSTRING payload = {(const char*) request, request_len};
696
697 ret = conn->command->stmt_execute(conn, payload);
698 } else {
699 SET_CLIENT_ERROR(stmt->error_info, CR_UNKNOWN_ERROR, UNKNOWN_SQLSTATE, "Couldn't generate the request. Possibly OOM.");
700 }
701
702 if (free_request) {
703 mnd_efree(request);
704 }
705
706 if (ret == FAIL) {
708 DBG_INF("FAIL");
710 }
711 stmt->execute_count++;
712
714}
715/* }}} */
716
717
718/* {{{ mysqlnd_stmt::use_result */
719static MYSQLND_RES *
720MYSQLND_METHOD(mysqlnd_stmt, use_result)(MYSQLND_STMT * s)
721{
722 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
723 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
725
726 DBG_ENTER("mysqlnd_stmt::use_result");
727 if (!stmt || !conn || !stmt->result) {
729 }
730 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
731
732 if (!stmt->field_count || !mysqlnd_stmt_check_state(stmt)) {
734 DBG_ERR("command out of sync");
736 }
737
739
741 result = stmt->result;
742
743 result->m.use_result(stmt->result, stmt);
744 if (stmt->cursor_exists) {
745 result->unbuf->m.fetch_row = mysqlnd_fetch_stmt_row_cursor;
746 }
748
749 DBG_INF_FMT("%p", result);
751}
752/* }}} */
753
754
755/* {{{ mysqlnd_fetch_row_cursor */
757mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES * result, zval **row_ptr, const unsigned int flags, bool * fetched_anything)
758{
760 MYSQLND_STMT_DATA * stmt = result->unbuf->stmt;
761 MYSQLND_CONN_DATA * conn = stmt->conn;
762 MYSQLND_PACKET_ROW * row_packet;
763 void *checkpoint;
764
765 DBG_ENTER("mysqlnd_fetch_stmt_row_cursor");
766
767 if (!stmt->conn || !result->conn) {
768 DBG_ERR("no statement");
770 }
771 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " flags=%u", stmt->stmt_id, flags);
772
773 if (stmt->state < MYSQLND_STMT_USER_FETCHING) {
774 /* Only initted - error */
776 DBG_ERR("command out of sync");
778 }
779 if (!(row_packet = result->unbuf->row_packet)) {
781 }
782
785
786 /* for now fetch only one row */
787 if (mysqlnd_stmt_send_cursor_fetch_command(stmt, 1) == FAIL) {
789 }
790
791 checkpoint = result->memory_pool->checkpoint;
793
795 if (PASS == (ret = PACKET_READ(conn, row_packet)) && !row_packet->eof) {
796 if (row_ptr) {
797 result->unbuf->last_row_buffer = row_packet->row_buffer;
798 row_packet->row_buffer.ptr = NULL;
799 *row_ptr = result->row_data;
800
801 if (PASS != result->unbuf->m.row_decoder(&result->unbuf->last_row_buffer,
802 result->row_data,
803 row_packet->field_count,
804 row_packet->fields_metadata,
806 conn->stats))
807 {
809 result->memory_pool->checkpoint = checkpoint;
811 }
812 } else {
813 DBG_INF("skipping extraction");
814 row_packet->row_buffer.ptr = NULL;
815 }
816 /* We asked for one row, the next one should be EOF, eat it */
817 ret = PACKET_READ(conn, row_packet);
819
820 result->unbuf->row_count++;
821 *fetched_anything = TRUE;
822 } else {
823 *fetched_anything = FALSE;
826
829
830 result->unbuf->eof_reached = row_packet->eof;
831 }
834
837
839 result->memory_pool->checkpoint = checkpoint;
840
841 DBG_INF_FMT("ret=%s fetched=%u server_status=%u warnings=%u eof=%u",
842 ret == PASS? "PASS":"FAIL", *fetched_anything,
843 row_packet->server_status, row_packet->warning_count,
844 result->unbuf->eof_reached);
846}
847/* }}} */
848
849
850/* {{{ mysqlnd_stmt::fetch */
851static enum_func_status
852MYSQLND_METHOD(mysqlnd_stmt, fetch)(MYSQLND_STMT * const s, bool * const fetched_anything)
853{
854 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
855 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
857 DBG_ENTER("mysqlnd_stmt::fetch");
858 if (!stmt || !stmt->conn) {
860 }
861 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
862
863 if (!stmt->result || stmt->state < MYSQLND_STMT_WAITING_USE_OR_STORE) {
865 DBG_ERR("command out of sync");
867 } else if (stmt->state == MYSQLND_STMT_WAITING_USE_OR_STORE) {
868 /* Execute only once. We have to free the previous contents of user's bound vars */
869
870 stmt->default_rset_handler(s);
871 }
873
876
877 if (stmt->result_bind) {
878 zval *row_data;
879 ret = stmt->result->m.fetch_row(stmt->result, &row_data, 0, fetched_anything);
880 if (ret == PASS && *fetched_anything) {
881 unsigned field_count = stmt->result->field_count;
882 for (unsigned i = 0; i < field_count; i++) {
883 zval *resultzv = &stmt->result_bind[i].zv;
884 if (stmt->result_bind[i].bound == TRUE) {
885 DBG_INF_FMT("i=%u type=%u", i, Z_TYPE(row_data[i]));
886 ZEND_TRY_ASSIGN_VALUE_EX(resultzv, &row_data[i], 0);
887 } else {
888 zval_ptr_dtor_nogc(&row_data[i]);
889 }
890 }
891 }
892 } else {
893 ret = stmt->result->m.fetch_row(stmt->result, NULL, 0, fetched_anything);
894 }
896}
897/* }}} */
898
899
900/* {{{ mysqlnd_stmt::reset */
901static enum_func_status
902MYSQLND_METHOD(mysqlnd_stmt, reset)(MYSQLND_STMT * const s)
903{
905 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
906 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
907
908 DBG_ENTER("mysqlnd_stmt::reset");
909 if (!stmt || !conn) {
911 }
912 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
913
916
917 if (stmt->stmt_id) {
918 MYSQLND_CONN_DATA * conn = stmt->conn;
919 if (stmt->param_bind) {
920 unsigned int i;
921 DBG_INF("resetting long data");
922 /* Reset Long Data */
923 for (i = 0; i < stmt->param_count; i++) {
926 }
927 }
928 }
929
930 s->m->flush(s);
931
932 /*
933 Don't free now, let the result be usable. When the stmt will again be
934 executed then the result set will be cleaned, the bound variables will
935 be separated before that.
936 */
937
938 if (GET_CONNECTION_STATE(&conn->state) == CONN_READY) {
939 size_t stmt_id = stmt->stmt_id;
940
941 ret = stmt->conn->command->stmt_reset(stmt->conn, stmt_id);
942 if (ret == FAIL) {
944 }
945 }
946 *stmt->upsert_status = *conn->upsert_status;
947 }
948 DBG_INF(ret == PASS? "PASS":"FAIL");
950}
951/* }}} */
952
953
954/* {{{ mysqlnd_stmt::flush */
955static enum_func_status
956MYSQLND_METHOD(mysqlnd_stmt, flush)(MYSQLND_STMT * const s)
957{
959 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
960 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
961
962 DBG_ENTER("mysqlnd_stmt::flush");
963 if (!stmt || !conn) {
965 }
966 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
967
968 if (stmt->stmt_id) {
969 /*
970 If the user decided to close the statement right after execute()
971 We have to call the appropriate use_result() or store_result() and
972 clean.
973 */
974 do {
976 DBG_INF("fetching result set header");
977 stmt->default_rset_handler(s);
979 }
980
981 if (stmt->result) {
982 DBG_INF("skipping result");
983 stmt->result->m.skip_result(stmt->result);
984 }
986 }
987 DBG_INF(ret == PASS? "PASS":"FAIL");
989}
990/* }}} */
991
992
993/* {{{ mysqlnd_stmt::send_long_data */
994static enum_func_status
995MYSQLND_METHOD(mysqlnd_stmt, send_long_data)(MYSQLND_STMT * const s, unsigned int param_no,
996 const char * const data, zend_ulong data_length)
997{
999 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1000 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1001 zend_uchar * cmd_buf;
1002
1003 DBG_ENTER("mysqlnd_stmt::send_long_data");
1004 if (!stmt || !conn) {
1006 }
1007 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " param_no=%u data_len=" ZEND_ULONG_FMT, stmt->stmt_id, param_no, data_length);
1008
1011
1012 if (stmt->state < MYSQLND_STMT_PREPARED) {
1014 DBG_ERR("not prepared");
1016 }
1017 if (!stmt->param_bind) {
1019 DBG_ERR("command out of sync");
1021 }
1022 if (param_no >= stmt->param_count) {
1023 SET_CLIENT_ERROR(stmt->error_info, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
1024 DBG_ERR("invalid param_no");
1026 }
1027 if (stmt->param_bind[param_no].type != MYSQL_TYPE_LONG_BLOB) {
1029 DBG_ERR("param_no is not of a blob type");
1031 }
1032
1033 if (GET_CONNECTION_STATE(&conn->state) == CONN_READY) {
1034 const size_t packet_len = MYSQLND_STMT_ID_LENGTH + 2 + data_length;
1035 cmd_buf = mnd_emalloc(packet_len);
1036 if (cmd_buf) {
1038
1039 int4store(cmd_buf, stmt->stmt_id);
1040 int2store(cmd_buf + MYSQLND_STMT_ID_LENGTH, param_no);
1041 memcpy(cmd_buf + MYSQLND_STMT_ID_LENGTH + 2, data, data_length);
1042
1043 /* COM_STMT_SEND_LONG_DATA doesn't acknowledge with an OK packet */
1044 {
1045 const MYSQLND_CSTRING payload = {(const char *) cmd_buf, packet_len};
1046
1047 ret = conn->command->stmt_send_long_data(conn, payload);
1048 if (ret == FAIL) {
1050 }
1051 }
1052
1053 mnd_efree(cmd_buf);
1054 } else {
1055 ret = FAIL;
1058 }
1059 /*
1060 Cover protocol error: COM_STMT_SEND_LONG_DATA was designed to be quick and not
1061 sent response packets. According to documentation the only way to get an error
1062 is to have out-of-memory on the server-side. However, that's not true, as if
1063 max_allowed_packet_size is smaller than the chunk being sent to the server, the
1064 latter will complain with an error message. However, normally we don't expect
1065 an error message, thus we continue. When sending the next command, which expects
1066 response we will read the unexpected data and error message will look weird.
1067 Therefore we do non-blocking read to clean the line, if there is a need.
1068 Nevertheless, there is a built-in protection when sending a command packet, that
1069 checks if the line is clear - useful for debug purposes and to be switched off
1070 in release builds.
1071
1072 Maybe we can make it automatic by checking what's the value of
1073 max_allowed_packet_size on the server and resending the data.
1074 */
1075#ifdef MYSQLND_DO_WIRE_CHECK_BEFORE_COMMAND
1076#if defined(HAVE_USLEEP) && !defined(PHP_WIN32)
1077 usleep(120000);
1078#endif
1079 if ((packet_len = conn->protocol_frame_codec->m.consume_uneaten_data(conn->protocol_frame_codec, COM_STMT_SEND_LONG_DATA))) {
1080 php_error_docref(NULL, E_WARNING, "There was an error "
1081 "while sending long data. Probably max_allowed_packet_size "
1082 "is smaller than the data. You have to increase it or send "
1083 "smaller chunks of data. Answer was %zu bytes long.", packet_len);
1085 "Server responded to COM_STMT_SEND_LONG_DATA.");
1086 ret = FAIL;
1087 }
1088#endif
1089 }
1090
1091 DBG_INF(ret == PASS? "PASS":"FAIL");
1092 DBG_RETURN(ret);
1093}
1094/* }}} */
1095
1096
1097/* {{{ mysqlnd_stmt::bind_parameters */
1098static enum_func_status
1099MYSQLND_METHOD(mysqlnd_stmt, bind_parameters)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * const param_bind)
1100{
1101 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1102 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1103
1104 DBG_ENTER("mysqlnd_stmt::bind_param");
1105 if (!stmt || !conn) {
1107 }
1108 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " param_count=%u", stmt->stmt_id, stmt->param_count);
1109
1110 if (stmt->state < MYSQLND_STMT_PREPARED) {
1112 DBG_ERR("not prepared");
1113 if (param_bind) {
1114 s->m->free_parameter_bind(s, param_bind);
1115 }
1117 }
1118
1121
1122 if (stmt->param_count) {
1123 unsigned int i = 0;
1124
1125 if (!param_bind) {
1126 SET_CLIENT_ERROR(stmt->error_info, CR_COMMANDS_OUT_OF_SYNC, UNKNOWN_SQLSTATE, "Re-binding (still) not supported");
1127 DBG_ERR("Re-binding (still) not supported");
1129 } else if (stmt->param_bind) {
1130 DBG_INF("Binding");
1131 /*
1132 There is already result bound.
1133 Forbid for now re-binding!!
1134 */
1135 for (i = 0; i < stmt->param_count; i++) {
1136 /*
1137 We may have the last reference, then call zval_ptr_dtor() or we may leak memory.
1138 Switching from bind_one_parameter to bind_parameters may result in zv being NULL
1139 */
1140 zval_ptr_dtor(&stmt->param_bind[i].zv);
1141 }
1142 if (stmt->param_bind != param_bind) {
1143 s->m->free_parameter_bind(s, stmt->param_bind);
1144 }
1145 }
1146
1147 stmt->param_bind = param_bind;
1148 for (i = 0; i < stmt->param_count; i++) {
1149 /* The client will use stmt_send_long_data */
1150 DBG_INF_FMT("%u is of type %u", i, stmt->param_bind[i].type);
1151 /* Prevent from freeing */
1152 /* Don't update is_ref, or we will leak during conversion */
1153 Z_TRY_ADDREF(stmt->param_bind[i].zv);
1154 stmt->param_bind[i].flags = 0;
1155 if (stmt->param_bind[i].type == MYSQL_TYPE_LONG_BLOB) {
1157 }
1158 }
1159 stmt->send_types_to_server = 1;
1160 } else if (param_bind && param_bind != stmt->param_bind) {
1161 s->m->free_parameter_bind(s, param_bind);
1162 }
1163 DBG_INF("PASS");
1165}
1166/* }}} */
1167
1168
1169/* {{{ mysqlnd_stmt::bind_one_parameter */
1170static enum_func_status
1171MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter)(MYSQLND_STMT * const s, unsigned int param_no,
1172 zval * const zv, zend_uchar type)
1173{
1174 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1175 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1176
1177 DBG_ENTER("mysqlnd_stmt::bind_one_parameter");
1178 if (!stmt || !conn) {
1180 }
1181 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " param_no=%u param_count=%u type=%u", stmt->stmt_id, param_no, stmt->param_count, type);
1182
1183 if (stmt->state < MYSQLND_STMT_PREPARED) {
1185 DBG_ERR("not prepared");
1187 }
1188
1189 if (param_no >= stmt->param_count) {
1190 SET_CLIENT_ERROR(stmt->error_info, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
1191 DBG_ERR("invalid param_no");
1193 }
1196
1197 if (stmt->param_count) {
1198 if (!stmt->param_bind) {
1199 stmt->param_bind = mnd_ecalloc(stmt->param_count, sizeof(MYSQLND_PARAM_BIND));
1200 if (!stmt->param_bind) {
1202 }
1203 }
1204
1205 /* Prevent from freeing */
1206 /* Don't update is_ref, or we will leak during conversion */
1208 DBG_INF("Binding");
1209 /* Release what we had, if we had */
1210 zval_ptr_dtor(&stmt->param_bind[param_no].zv);
1211 if (type == MYSQL_TYPE_LONG_BLOB) {
1212 /* The client will use stmt_send_long_data */
1214 }
1215 ZVAL_COPY_VALUE(&stmt->param_bind[param_no].zv, zv);
1216 stmt->param_bind[param_no].type = type;
1217
1218 stmt->send_types_to_server = 1;
1219 }
1220 DBG_INF("PASS");
1222}
1223/* }}} */
1224
1225
1226/* {{{ mysqlnd_stmt::refresh_bind_param */
1227static enum_func_status
1228MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param)(MYSQLND_STMT * const s)
1229{
1230 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1231 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1232
1233 DBG_ENTER("mysqlnd_stmt::refresh_bind_param");
1234 if (!stmt || !conn) {
1236 }
1237 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " param_count=%u", stmt->stmt_id, stmt->param_count);
1238
1239 if (stmt->state < MYSQLND_STMT_PREPARED) {
1241 DBG_ERR("not prepared");
1243 }
1244
1247
1248 if (stmt->param_count) {
1249 stmt->send_types_to_server = 1;
1250 }
1252}
1253/* }}} */
1254
1255
1256/* {{{ mysqlnd_stmt::bind_result */
1257static enum_func_status
1258MYSQLND_METHOD(mysqlnd_stmt, bind_result)(MYSQLND_STMT * const s,
1259 MYSQLND_RESULT_BIND * const result_bind)
1260{
1261 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1262 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1263
1264 DBG_ENTER("mysqlnd_stmt::bind_result");
1265 if (!stmt || !conn) {
1267 }
1268 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " field_count=%u", stmt->stmt_id, stmt->field_count);
1269
1270 if (stmt->state < MYSQLND_STMT_PREPARED) {
1272 if (result_bind) {
1273 s->m->free_result_bind(s, result_bind);
1274 }
1275 DBG_ERR("not prepared");
1277 }
1278
1281
1282 if (stmt->field_count) {
1283 unsigned int i = 0;
1284
1285 if (!result_bind) {
1286 DBG_ERR("no result bind passed");
1288 }
1289
1290 mysqlnd_stmt_separate_result_bind(s);
1291 stmt->result_bind = result_bind;
1292 for (i = 0; i < stmt->field_count; i++) {
1293 /* Prevent from freeing */
1294 Z_TRY_ADDREF(stmt->result_bind[i].zv);
1295
1296 DBG_INF_FMT("ref of %p = %u", &stmt->result_bind[i].zv,
1297 Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0);
1298 /*
1299 Don't update is_ref !!! it's not our job
1300 Otherwise either 009.phpt or mysqli_stmt_bind_result.phpt
1301 will fail.
1302 */
1303 stmt->result_bind[i].bound = TRUE;
1304 }
1305 } else if (result_bind) {
1306 s->m->free_result_bind(s, result_bind);
1307 }
1308 DBG_INF("PASS");
1310}
1311/* }}} */
1312
1313
1314/* {{{ mysqlnd_stmt::bind_result */
1315static enum_func_status
1316MYSQLND_METHOD(mysqlnd_stmt, bind_one_result)(MYSQLND_STMT * const s, unsigned int param_no)
1317{
1318 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1319 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1320
1321 DBG_ENTER("mysqlnd_stmt::bind_one_result");
1322 if (!stmt || !conn) {
1324 }
1325 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " field_count=%u", stmt->stmt_id, stmt->field_count);
1326
1327 if (stmt->state < MYSQLND_STMT_PREPARED) {
1329 DBG_ERR("not prepared");
1331 }
1332
1333 if (param_no >= stmt->field_count) {
1334 SET_CLIENT_ERROR(stmt->error_info, CR_INVALID_PARAMETER_NO, UNKNOWN_SQLSTATE, "Invalid parameter number");
1335 DBG_ERR("invalid param_no");
1337 }
1338
1341
1342 if (stmt->field_count) {
1343 if (!stmt->result_bind) {
1345 }
1346 if (stmt->result_bind[param_no].bound) {
1347 zval_ptr_dtor(&stmt->result_bind[param_no].zv);
1348 }
1349 ZVAL_NULL(&stmt->result_bind[param_no].zv);
1350 stmt->result_bind[param_no].bound = TRUE;
1351 }
1352 DBG_INF("PASS");
1354}
1355/* }}} */
1356
1357
1358/* {{{ mysqlnd_stmt::insert_id */
1359static uint64_t
1360MYSQLND_METHOD(mysqlnd_stmt, insert_id)(const MYSQLND_STMT * const s)
1361{
1362 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1363 return stmt? UPSERT_STATUS_GET_LAST_INSERT_ID(stmt->upsert_status) : 0;
1364}
1365/* }}} */
1366
1367
1368/* {{{ mysqlnd_stmt::affected_rows */
1369static uint64_t
1370MYSQLND_METHOD(mysqlnd_stmt, affected_rows)(const MYSQLND_STMT * const s)
1371{
1372 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1373 return stmt? UPSERT_STATUS_GET_AFFECTED_ROWS(stmt->upsert_status) : 0;
1374}
1375/* }}} */
1376
1377
1378/* {{{ mysqlnd_stmt::num_rows */
1379static uint64_t
1380MYSQLND_METHOD(mysqlnd_stmt, num_rows)(const MYSQLND_STMT * const s)
1381{
1382 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1383 return stmt && stmt->result? mysqlnd_num_rows(stmt->result):0;
1384}
1385/* }}} */
1386
1387
1388/* {{{ mysqlnd_stmt::warning_count */
1389static unsigned int
1390MYSQLND_METHOD(mysqlnd_stmt, warning_count)(const MYSQLND_STMT * const s)
1391{
1392 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1393 return stmt? UPSERT_STATUS_GET_WARNINGS(stmt->upsert_status) : 0;
1394}
1395/* }}} */
1396
1397
1398/* {{{ mysqlnd_stmt::server_status */
1399static unsigned int
1400MYSQLND_METHOD(mysqlnd_stmt, server_status)(const MYSQLND_STMT * const s)
1401{
1402 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1403 return stmt? UPSERT_STATUS_GET_SERVER_STATUS(stmt->upsert_status) : 0;
1404}
1405/* }}} */
1406
1407
1408/* {{{ mysqlnd_stmt::field_count */
1409static unsigned int
1410MYSQLND_METHOD(mysqlnd_stmt, field_count)(const MYSQLND_STMT * const s)
1411{
1412 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1413 return stmt? stmt->field_count : 0;
1414}
1415/* }}} */
1416
1417
1418/* {{{ mysqlnd_stmt::param_count */
1419static unsigned int
1420MYSQLND_METHOD(mysqlnd_stmt, param_count)(const MYSQLND_STMT * const s)
1421{
1422 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1423 return stmt? stmt->param_count : 0;
1424}
1425/* }}} */
1426
1427
1428/* {{{ mysqlnd_stmt::errno */
1429static unsigned int
1430MYSQLND_METHOD(mysqlnd_stmt, errno)(const MYSQLND_STMT * const s)
1431{
1432 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1433 return stmt? stmt->error_info->error_no : 0;
1434}
1435/* }}} */
1436
1437
1438/* {{{ mysqlnd_stmt::error */
1439static const char *
1440MYSQLND_METHOD(mysqlnd_stmt, error)(const MYSQLND_STMT * const s)
1441{
1442 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1443 return stmt? stmt->error_info->error : 0;
1444}
1445/* }}} */
1446
1447
1448/* {{{ mysqlnd_stmt::sqlstate */
1449static const char *
1450MYSQLND_METHOD(mysqlnd_stmt, sqlstate)(const MYSQLND_STMT * const s)
1451{
1452 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1453 return stmt && stmt->error_info->sqlstate[0] ? stmt->error_info->sqlstate:MYSQLND_SQLSTATE_NULL;
1454}
1455/* }}} */
1456
1457
1458/* {{{ mysqlnd_stmt::data_seek */
1459static enum_func_status
1460MYSQLND_METHOD(mysqlnd_stmt, data_seek)(const MYSQLND_STMT * const s, uint64_t row)
1461{
1462 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1463 return stmt && stmt->result? stmt->result->m.seek_data(stmt->result, row) : FAIL;
1464}
1465/* }}} */
1466
1467
1468/* {{{ mysqlnd_stmt::result_metadata */
1469static MYSQLND_RES *
1470MYSQLND_METHOD(mysqlnd_stmt, result_metadata)(MYSQLND_STMT * const s)
1471{
1472 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1473 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1474 MYSQLND_RES * result_meta = NULL;
1475
1476 DBG_ENTER("mysqlnd_stmt::result_metadata");
1477 if (!stmt || ! conn) {
1479 }
1480 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " field_count=%u", stmt->stmt_id, stmt->field_count);
1481
1482 if (!stmt->field_count || !stmt->result || !stmt->result->meta) {
1483 DBG_INF("NULL");
1485 }
1486
1487 /*
1488 TODO: This implementation is kind of a hack,
1489 find a better way to do it. In different functions I have put
1490 fuses to check for result->m.fetch_row() being NULL. This should
1491 be handled in a better way.
1492 */
1493 do {
1494 result_meta = conn->m->result_init(stmt->field_count);
1495 if (!result_meta) {
1496 break;
1497 }
1498 result_meta->type = MYSQLND_RES_NORMAL;
1499 result_meta->unbuf = mysqlnd_result_unbuffered_init(result_meta, stmt->field_count, stmt);
1500 if (!result_meta->unbuf) {
1501 break;
1502 }
1503 result_meta->unbuf->eof_reached = TRUE;
1504 result_meta->meta = stmt->result->meta->m->clone_metadata(result_meta, stmt->result->meta);
1505 if (!result_meta->meta) {
1506 break;
1507 }
1508
1509 DBG_INF_FMT("result_meta=%p", result_meta);
1510 DBG_RETURN(result_meta);
1511 } while (0);
1512
1514 if (result_meta) {
1515 result_meta->m.free_result(result_meta, TRUE);
1516 }
1518}
1519/* }}} */
1520
1521
1522/* {{{ mysqlnd_stmt::attr_set */
1523static enum_func_status
1524MYSQLND_METHOD(mysqlnd_stmt, attr_set)(MYSQLND_STMT * const s,
1525 enum mysqlnd_stmt_attr attr_type,
1526 const void * const value)
1527{
1528 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1529 DBG_ENTER("mysqlnd_stmt::attr_set");
1530 if (!stmt) {
1532 }
1533 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " attr_type=%u", stmt->stmt_id, attr_type);
1534
1535 switch (attr_type) {
1537 zend_uchar bval = *(zend_uchar *) value;
1538 /*
1539 XXX : libmysql uses my_bool, but mysqli uses ulong as storage on the stack
1540 and mysqlnd won't be used out of the scope of PHP -> use ulong.
1541 */
1542 stmt->update_max_length = bval? TRUE:FALSE;
1543 break;
1544 }
1545 case STMT_ATTR_CURSOR_TYPE: {
1546 unsigned long ival = *(unsigned long *) value;
1547 if (ival > (unsigned long) CURSOR_TYPE_READ_ONLY) {
1549 DBG_INF("FAIL");
1551 }
1552 stmt->flags = ival;
1553 break;
1554 }
1555 default:
1558 }
1559 DBG_INF("PASS");
1561}
1562/* }}} */
1563
1564
1565/* {{{ mysqlnd_stmt::attr_get */
1566static enum_func_status
1567MYSQLND_METHOD(mysqlnd_stmt, attr_get)(const MYSQLND_STMT * const s,
1568 enum mysqlnd_stmt_attr attr_type,
1569 void * const value)
1570{
1571 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1572 DBG_ENTER("mysqlnd_stmt::attr_get");
1573 if (!stmt) {
1575 }
1576 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " attr_type=%u", stmt->stmt_id, attr_type);
1577
1578 switch (attr_type) {
1580 *(bool *) value = stmt->update_max_length;
1581 DBG_INF_FMT("value=%d", *(bool *) value);
1582 break;
1584 *(unsigned long *) value = stmt->flags;
1585 DBG_INF_FMT("value=%lu", *(unsigned long *) value);
1586 break;
1587 default:
1589 }
1591}
1592/* }}} */
1593
1594
1595/* free_result() doesn't actually free stmt->result but only the buffers */
1596/* {{{ mysqlnd_stmt::free_result */
1597static enum_func_status
1598MYSQLND_METHOD(mysqlnd_stmt, free_result)(MYSQLND_STMT * const s)
1599{
1600 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1601 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1602
1603 DBG_ENTER("mysqlnd_stmt::free_result");
1604 if (!stmt || !conn) {
1606 }
1607 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
1608
1609 if (!stmt->result) {
1610 DBG_INF("no result");
1612 }
1613
1614 /*
1615 If right after execute() we have to call the appropriate
1616 use_result() or store_result() and clean.
1617 */
1619 DBG_INF("fetching result set header");
1620 /* Do implicit use_result and then flush the result */
1621 stmt->default_rset_handler = s->m->use_result;
1622 stmt->default_rset_handler(s);
1623 }
1624
1626 DBG_INF("skipping result");
1627 /* Flush if anything is left and unbuffered set */
1628 stmt->result->m.skip_result(stmt->result);
1629 /*
1630 Separate the bound variables, which point to the result set, then
1631 destroy the set.
1632 */
1633 mysqlnd_stmt_separate_result_bind(s);
1634
1635 /* Now we can destroy the result set */
1636 stmt->result->m.free_result_buffers(stmt->result);
1637 }
1638
1639 if (stmt->state > MYSQLND_STMT_PREPARED) {
1640 /* As the buffers have been freed, we should go back to PREPARED */
1642 }
1643
1645}
1646/* }}} */
1647
1648
1649/* {{{ mysqlnd_stmt_separate_result_bind */
1650static void
1651mysqlnd_stmt_separate_result_bind(MYSQLND_STMT * const s)
1652{
1653 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1654 unsigned int i;
1655
1656 DBG_ENTER("mysqlnd_stmt_separate_result_bind");
1657 if (!stmt) {
1659 }
1660 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " result_bind=%p field_count=%u", stmt->stmt_id, stmt->result_bind, stmt->field_count);
1661
1662 if (!stmt->result_bind) {
1664 }
1665
1666 /*
1667 Because only the bound variables can point to our internal buffers, then
1668 separate or free only them. Free is possible because the user could have
1669 lost reference.
1670 */
1671 for (i = 0; i < stmt->field_count; i++) {
1672 /* Let's try with no cache */
1673 if (stmt->result_bind[i].bound == TRUE) {
1674 DBG_INF_FMT("%u has refcount=%u", i, Z_REFCOUNTED(stmt->result_bind[i].zv)? Z_REFCOUNT(stmt->result_bind[i].zv) : 0);
1675 zval_ptr_dtor(&stmt->result_bind[i].zv);
1676 }
1677 }
1678
1679 s->m->free_result_bind(s, stmt->result_bind);
1680 stmt->result_bind = NULL;
1681
1683}
1684/* }}} */
1685
1686
1687/* {{{ mysqlnd_stmt::free_stmt_result */
1688static void
1689MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)(MYSQLND_STMT * const s)
1690{
1691 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1692 DBG_ENTER("mysqlnd_stmt::free_stmt_result");
1693 if (!stmt) {
1695 }
1696
1697 /*
1698 First separate the bound variables, which point to the result set, then
1699 destroy the set.
1700 */
1701 mysqlnd_stmt_separate_result_bind(s);
1702 /* Not every statement has a result set attached */
1703 if (stmt->result) {
1704 stmt->result->m.free_result(stmt->result, /* implicit */ TRUE);
1705 stmt->result = NULL;
1706 }
1708
1710}
1711/* }}} */
1712
1713
1714/* {{{ mysqlnd_stmt::free_stmt_content */
1715static void
1716MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content)(MYSQLND_STMT * const s)
1717{
1718 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1719 DBG_ENTER("mysqlnd_stmt::free_stmt_content");
1720 if (!stmt) {
1722 }
1723 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT " param_bind=%p param_count=%u", stmt->stmt_id, stmt->param_bind, stmt->param_count);
1724
1725 /* Destroy the input bind */
1726 if (stmt->param_bind) {
1727 unsigned int i;
1728 /*
1729 Because only the bound variables can point to our internal buffers, then
1730 separate or free only them. Free is possible because the user could have
1731 lost reference.
1732 */
1733 for (i = 0; i < stmt->param_count; i++) {
1734 /*
1735 If bind_one_parameter was used, but not everything was
1736 bound and nothing was fetched, then some `zv` could be NULL
1737 */
1738 zval_ptr_dtor(&stmt->param_bind[i].zv);
1739 }
1740 s->m->free_parameter_bind(s, stmt->param_bind);
1741 stmt->param_bind = NULL;
1742 }
1743
1744 s->m->free_stmt_result(s);
1746}
1747/* }}} */
1748
1749
1750/* {{{ mysqlnd_stmt::close_on_server */
1751static enum_func_status
1752MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, close_on_server)(MYSQLND_STMT * const s, bool implicit)
1753{
1754 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1755 MYSQLND_CONN_DATA * conn = stmt? stmt->conn : NULL;
1757
1758 DBG_ENTER("mysqlnd_stmt::close_on_server");
1759 if (!stmt || !conn) {
1761 }
1762 DBG_INF_FMT("stmt=" ZEND_ULONG_FMT, stmt->stmt_id);
1763
1766
1767 /*
1768 If the user decided to close the statement right after execute()
1769 We have to call the appropriate use_result() or store_result() and
1770 clean.
1771 */
1772 do {
1774 DBG_INF("fetching result set header");
1775 stmt->default_rset_handler(s);
1777 }
1778
1779 /* unbuffered set not fetched to the end ? Clean the line */
1780 if (stmt->result) {
1781 DBG_INF("skipping result");
1782 stmt->result->m.skip_result(stmt->result);
1783 }
1785 /*
1786 After this point we are allowed to free the result set,
1787 as we have cleaned the line
1788 */
1789 if (stmt->stmt_id) {
1792
1793 if (GET_CONNECTION_STATE(&conn->state) == CONN_READY) {
1795 const size_t stmt_id = stmt->stmt_id;
1796
1797 ret = conn->command->stmt_close(conn, stmt_id);
1798 if (ret == FAIL) {
1801 }
1802 }
1803 }
1804 switch (stmt->execute_count) {
1805 case 0:
1807 break;
1808 case 1:
1809 statistic = STAT_PS_PREPARED_ONCE_USED;
1810 break;
1811 default:
1812 break;
1813 }
1814 if (statistic != STAT_LAST) {
1815 MYSQLND_INC_CONN_STATISTIC(conn->stats, statistic);
1816 }
1817
1818 if (stmt->execute_cmd_buffer.buffer) {
1821 }
1822
1823 s->m->free_stmt_content(s);
1824
1825 if (conn) {
1826 conn->m->free_reference(conn);
1827 stmt->conn = NULL;
1828 }
1829
1831}
1832/* }}} */
1833
1834/* {{{ mysqlnd_stmt::dtor */
1835static enum_func_status
1836MYSQLND_METHOD(mysqlnd_stmt, dtor)(MYSQLND_STMT * const s, bool implicit)
1837{
1838 MYSQLND_STMT_DATA * stmt = (s != NULL) ? s->data:NULL;
1840
1841 DBG_ENTER("mysqlnd_stmt::dtor");
1842 if (stmt) {
1843 DBG_INF_FMT("stmt=%p", stmt);
1844
1847
1848 ret = s->m->close_on_server(s, implicit);
1849 mnd_efree(stmt);
1850 }
1851 mnd_efree(s);
1852
1853 DBG_INF(ret == PASS? "PASS":"FAIL");
1854 DBG_RETURN(ret);
1855}
1856/* }}} */
1857
1858
1859/* {{{ mysqlnd_stmt::alloc_param_bind */
1860static MYSQLND_PARAM_BIND *
1861MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind)(MYSQLND_STMT * const s)
1862{
1863 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1864 DBG_ENTER("mysqlnd_stmt::alloc_param_bind");
1865 if (!stmt) {
1867 }
1869}
1870/* }}} */
1871
1872
1873/* {{{ mysqlnd_stmt::alloc_result_bind */
1874static MYSQLND_RESULT_BIND *
1875MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind)(MYSQLND_STMT * const s)
1876{
1877 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1878 DBG_ENTER("mysqlnd_stmt::alloc_result_bind");
1879 if (!stmt) {
1881 }
1883}
1884/* }}} */
1885
1886
1887/* {{{ param_bind::free_parameter_bind */
1888PHPAPI void
1889MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind)(MYSQLND_STMT * const s, MYSQLND_PARAM_BIND * param_bind)
1890{
1891 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1892 if (stmt) {
1893 mnd_efree(param_bind);
1894 }
1895}
1896/* }}} */
1897
1898
1899/* {{{ mysqlnd_stmt::free_result_bind */
1900PHPAPI void
1901MYSQLND_METHOD(mysqlnd_stmt, free_result_bind)(MYSQLND_STMT * const s, MYSQLND_RESULT_BIND * result_bind)
1902{
1903 MYSQLND_STMT_DATA * stmt = s? s->data : NULL;
1904 if (stmt) {
1905 mnd_efree(result_bind);
1906 }
1907}
1908/* }}} */
1909
1910
1911
1912MYSQLND_CLASS_METHODS_START(mysqlnd_stmt)
1913 MYSQLND_METHOD(mysqlnd_stmt, prepare),
1914 MYSQLND_METHOD(mysqlnd_stmt, send_execute),
1915 MYSQLND_METHOD(mysqlnd_stmt, execute),
1916 MYSQLND_METHOD(mysqlnd_stmt, use_result),
1917 MYSQLND_METHOD(mysqlnd_stmt, store_result),
1918 MYSQLND_METHOD(mysqlnd_stmt, get_result),
1919 MYSQLND_METHOD(mysqlnd_stmt, more_results),
1920 MYSQLND_METHOD(mysqlnd_stmt, next_result),
1921 MYSQLND_METHOD(mysqlnd_stmt, free_result),
1922 MYSQLND_METHOD(mysqlnd_stmt, data_seek),
1923 MYSQLND_METHOD(mysqlnd_stmt, reset),
1924 MYSQLND_METHOD_PRIVATE(mysqlnd_stmt, close_on_server),
1925 MYSQLND_METHOD(mysqlnd_stmt, dtor),
1926
1927 MYSQLND_METHOD(mysqlnd_stmt, fetch),
1928
1929 MYSQLND_METHOD(mysqlnd_stmt, bind_parameters),
1930 MYSQLND_METHOD(mysqlnd_stmt, bind_one_parameter),
1931 MYSQLND_METHOD(mysqlnd_stmt, refresh_bind_param),
1932 MYSQLND_METHOD(mysqlnd_stmt, bind_result),
1933 MYSQLND_METHOD(mysqlnd_stmt, bind_one_result),
1934 MYSQLND_METHOD(mysqlnd_stmt, send_long_data),
1935
1936 MYSQLND_METHOD(mysqlnd_stmt, result_metadata),
1937
1938 MYSQLND_METHOD(mysqlnd_stmt, insert_id),
1939 MYSQLND_METHOD(mysqlnd_stmt, affected_rows),
1940 MYSQLND_METHOD(mysqlnd_stmt, num_rows),
1941
1942 MYSQLND_METHOD(mysqlnd_stmt, param_count),
1943 MYSQLND_METHOD(mysqlnd_stmt, field_count),
1944 MYSQLND_METHOD(mysqlnd_stmt, warning_count),
1945
1946 MYSQLND_METHOD(mysqlnd_stmt, errno),
1947 MYSQLND_METHOD(mysqlnd_stmt, error),
1948 MYSQLND_METHOD(mysqlnd_stmt, sqlstate),
1949
1950 MYSQLND_METHOD(mysqlnd_stmt, attr_get),
1951 MYSQLND_METHOD(mysqlnd_stmt, attr_set),
1952
1953
1954 MYSQLND_METHOD(mysqlnd_stmt, alloc_param_bind),
1955 MYSQLND_METHOD(mysqlnd_stmt, alloc_result_bind),
1956 MYSQLND_METHOD(mysqlnd_stmt, free_parameter_bind),
1957 MYSQLND_METHOD(mysqlnd_stmt, free_result_bind),
1958 MYSQLND_METHOD(mysqlnd_stmt, server_status),
1961 MYSQLND_METHOD(mysqlnd_stmt, free_stmt_content),
1962 MYSQLND_METHOD(mysqlnd_stmt, flush),
1963 MYSQLND_METHOD(mysqlnd_stmt, free_stmt_result)
1965
1966
1967/* {{{ _mysqlnd_init_ps_subsystem */
1973/* }}} */
usleep(int $microseconds)
reset(array|object &$array)
char s[4]
Definition cdf.c:77
#define int4store(T, A)
Definition config-win.h:63
#define int2store(T, A)
Definition config-win.h:59
error($message)
Definition ext_skel.php:22
zend_ffi_type * type
Definition ffi.c:3812
zval * zv
Definition ffi.c:3975
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
zend_ffi_ctype_name_buf buf
Definition ffi.c:4685
#define TRUE
Definition gd_gd.c:7
#define FALSE
Definition gd_gd.c:8
#define NULL
Definition gdcache.h:45
#define PASS(tables)
Definition hash_gost.c:193
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define MYSQLND_INC_GLOBAL_STATISTIC(statistic)
Definition mysqlnd.h:255
#define mysqlnd_stmt_next_result(stmt)
Definition mysqlnd.h:219
PHPAPI unsigned int mysqlnd_plugin_count(void)
#define mysqlnd_num_rows(result)
Definition mysqlnd.h:145
#define MYSQLND_METHOD_PRIVATE(class, method)
Definition mysqlnd.h:295
#define MYSQLND_INC_CONN_STATISTIC(conn_stats, statistic)
Definition mysqlnd.h:264
#define mysqlnd_stmt_more_results(stmt)
Definition mysqlnd.h:218
zend_long mempool_default_size
Definition mysqlnd.h:306
#define MYSQLND_G(v)
#define MYSQLND_INC_CONN_STATISTIC_W_VALUE(conn_stats, statistic, value)
Definition mysqlnd.h:268
#define MYSQLND_METHOD(class, method)
Definition mysqlnd.h:294
#define mnd_sprintf_free(p)
#define mnd_efree(ptr)
#define mnd_sprintf(p, mx_len, fmt,...)
#define mnd_erealloc(ptr, new_size)
#define mnd_ecalloc(nmemb, size)
#define mnd_emalloc(size)
PHPAPI void mysqlnd_mempool_destroy(MYSQLND_MEMORY_POOL *pool)
PHPAPI void mysqlnd_mempool_restore_state(MYSQLND_MEMORY_POOL *pool)
PHPAPI void mysqlnd_mempool_save_state(MYSQLND_MEMORY_POOL *pool)
PHPAPI MYSQLND_MEMORY_POOL * mysqlnd_mempool_create(size_t arena_size)
PHPAPI const char *const mysqlnd_out_of_sync
#define SET_CONNECTION_STATE(state_struct, s)
#define UPSERT_STATUS_GET_AFFECTED_ROWS(status)
#define UPSERT_STATUS_GET_SERVER_STATUS(status)
#define UPSERT_STATUS_GET_WARNINGS(status)
#define UPSERT_STATUS_GET_LAST_INSERT_ID(status)
#define UPSERT_STATUS_SET_WARNINGS(status, warnings)
#define UPSERT_STATUS_SET_AFFECTED_ROWS_TO_ERROR(status)
#define GET_CONNECTION_STATE(state_struct)
#define UPSERT_STATUS_SET_LAST_INSERT_ID(status, id)
#define UPSERT_STATUS_RESET(status)
#define UPSERT_STATUS_SET_AFFECTED_ROWS(status, rows)
#define UPSERT_STATUS_SET_SERVER_STATUS(status, server_st)
#define DBG_VOID_RETURN
#define DBG_RETURN(value)
@ CONN_READY
@ CONN_QUIT_SENT
@ CONN_QUERY_SENT
@ CONN_NEXT_RESULT_PENDING
@ CONN_FETCHING_DATA
@ QUERY_LOAD_LOCAL
@ QUERY_UPSERT
enum mysqlnd_send_execute_type enum_mysqlnd_send_execute_type
#define SERVER_STATUS_CURSOR_EXISTS
#define CR_NOT_IMPLEMENTED
#define MYSQLND_SQLSTATE_NULL
@ STAT_FREE_RESULT_EXPLICIT
@ STAT_PS_BUFFERED_SETS
@ STAT_PS_PREPARED_NEVER_EXECUTED
@ STAT_STMT_CLOSE_EXPLICIT
@ STAT_FREE_RESULT_IMPLICIT
@ STAT_BUFFERED_SETS
@ STAT_ROWS_AFFECTED_PS
@ STAT_PS_PREPARED_ONCE_USED
@ STAT_STMT_CLOSE_IMPLICIT
@ STAT_LAST
@ STAT_PS_UNBUFFERED_SETS
@ STAT_ROWS_FETCHED_FROM_CLIENT_PS_CURSOR
@ CURSOR_TYPE_READ_ONLY
@ MYSQLND_PARSE_EXEC_RESPONSE_IMPLICIT
@ MYSQLND_PARSE_EXEC_RESPONSE_IMPLICIT_OUT_VARIABLES
@ MYSQLND_PARSE_EXEC_RESPONSE_IMPLICIT_NEXT_RESULT
#define CR_NO_PREPARE_STMT
#define SERVER_PS_OUT_PARAMS
#define CR_UNKNOWN_ERROR
#define CR_PARAMS_NOT_BOUND
enum mysqlnd_collected_stats enum_mysqlnd_collected_stats
@ MYSQLND_RES_NORMAL
@ MYSQLND_RES_PS_BUF
#define CR_INVALID_PARAMETER_NO
#define MYSQLND_STMT_ID_LENGTH
@ MYSQLND_STMT_WAITING_USE_OR_STORE
@ MYSQLND_STMT_INITTED
@ MYSQLND_STMT_USER_FETCHING
@ MYSQLND_STMT_EXECUTED
@ MYSQLND_STMT_USE_OR_STORE_CALLED
@ MYSQLND_STMT_PREPARED
#define CR_CONNECTION_ERROR
mysqlnd_stmt_attr
@ STMT_ATTR_UPDATE_MAX_LENGTH
@ STMT_ATTR_CURSOR_TYPE
#define CR_COMMANDS_OUT_OF_SYNC
@ COM_STMT_SEND_LONG_DATA
@ MYSQL_TYPE_LONG_BLOB
enum mysqlnd_parse_exec_response_type enum_mysqlnd_parse_exec_response_type
#define CR_INVALID_BUFFER_USE
#define SERVER_MORE_RESULTS_EXISTS
@ MYSQLND_PARAM_BIND_BLOB_USED
enum func_status enum_func_status
#define UNKNOWN_SQLSTATE
@ MYSQLND_SEND_EXECUTE_IMPLICIT
#define mysqlnd_stmt_set_methods(m)
void _mysqlnd_init_ps_subsystem(void)
const char *const mysqlnd_not_bound_as_blob
Definition mysqlnd_ps.c:31
mysqlnd_stmt_execute_generate_request
enum_func_status mysqlnd_stmt_execute_batch_generate_request(MYSQLND_STMT *const s, zend_uchar **request, size_t *request_len, bool *free_buffer)
enum_func_status mysqlnd_fetch_stmt_row_cursor(MYSQLND_RES *result, zval **row_ptr, const unsigned int flags, bool *fetched_anything)
Definition mysqlnd_ps.c:757
const char *const mysqlnd_stmt_not_prepared
Definition mysqlnd_ps.c:32
mysqlnd_stmt_execute_parse_response
void _mysqlnd_init_ps_fetch_subsystem(void)
PHPAPI MYSQLND_RES_BUFFERED * mysqlnd_result_buffered_init(MYSQLND_RES *result, const unsigned int field_count, MYSQLND_STMT_DATA *stmt)
PHPAPI MYSQLND_RES_UNBUFFERED * mysqlnd_result_unbuffered_init(MYSQLND_RES *result, const unsigned int field_count, MYSQLND_STMT_DATA *stmt)
#define MYSQLND_CLASS_METHODS_END
struct st_mysqlnd_connection_data MYSQLND_CONN_DATA
struct st_mysqlnd_const_string MYSQLND_CSTRING
struct st_mysqlnd_memory_pool MYSQLND_MEMORY_POOL
struct st_mysqlnd_param_bind MYSQLND_PARAM_BIND
#define SET_EMPTY_ERROR(info)
struct st_mysqlnd_stmt_data MYSQLND_STMT_DATA
#define COPY_CLIENT_ERROR(dest, source)
struct st_mysqlnd_stmt MYSQLND_STMT
#define SET_OOM_ERROR(info)
struct st_mysqlnd_result_bind MYSQLND_RESULT_BIND
#define SET_CLIENT_ERROR(info, err_no, sqlstate, error)
#define MYSQLND_CLASS_METHODS_START(class)
struct st_mysqlnd_res MYSQLND_RES
#define MYSQLND_CLASS_METHOD_TABLE_NAME(class)
struct st_mysqlnd_packet_prepare_response MYSQLND_PACKET_PREPARE_RESPONSE
struct st_mysqlnd_packet_eof MYSQLND_PACKET_EOF
#define PACKET_FREE(packet)
struct st_mysqlnd_packet_res_field MYSQLND_PACKET_RES_FIELD
#define PACKET_READ(conn, packet)
struct st_mysqlnd_packet_row MYSQLND_PACKET_ROW
#define PHPAPI
Definition php.h:71
char sqlstate[6]
char * msg
Definition phpdbg.h:289
zend_constant * data
bool fail
Definition session.c:1065
#define FAIL(...)
MYSQLND_SESSION_OPTIONS * options
MYSQLND_UPSERT_STATUS * upsert_status
enum_mysqlnd_query_type last_query_type
MYSQLND_PROTOCOL_PAYLOAD_DECODER_FACTORY * payload_decoder_factory
MYSQLND_ERROR_INFO * error_info
MYSQLND_CONNECTION_STATE state
char sqlstate[MYSQLND_SQLSTATE_LENGTH+1]
char error[MYSQLND_ERRMSG_SIZE+1]
MYSQLND_MEMORY_POOL * memory_pool
MYSQLND_ROW_BUFFER row_buffer
enum_param_bind_flags flags
MYSQLND_RES_METADATA * meta
MYSQLND_RES_UNBUFFERED * unbuf
MYSQLND_RES_BUFFERED * stored_data
MYSQLND_CONN_DATA * conn
unsigned int field_count
enum_mysqlnd_res_type type
enum_mysqlnd_stmt_state state
mysqlnd_stmt_use_or_store_func default_rset_handler
MYSQLND_CMD_BUFFER execute_cmd_buffer
unsigned char send_types_to_server
MYSQLND_ERROR_INFO * error_info
MYSQLND_UPSERT_STATUS * upsert_status
MYSQLND_PARAM_BIND * param_bind
MYSQLND_RESULT_BIND * result_bind
MYSQLND_CONN_DATA * conn
MYSQLND_STMT_DATA * data
#define errno
#define ZEND_TRY_ASSIGN_VALUE_EX(zv, other_zv, strict)
Definition zend_API.h:1454
struct _zval_struct zval
#define E_WARNING
Definition zend_errors.h:24
ZEND_API void zend_llist_clean(zend_llist *l)
Definition zend_llist.c:121
#define ZEND_ULONG_FMT
Definition zend_long.h:88
uint32_t zend_ulong
Definition zend_long.h:43
#define Z_TRY_ADDREF_P(pz)
#define ZVAL_UNDEF(z)
#define ZVAL_NULL(z)
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_REFCOUNTED(zval)
Definition zend_types.h:917
#define Z_TRY_ADDREF(z)
unsigned char zend_uchar
Definition zend_types.h:57
#define Z_REFCOUNT(z)
#define Z_TYPE(zval)
Definition zend_types.h:659
#define ZVAL_COPY_VALUE(z, v)
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
bool result
zval * ret
value