php-internal-docs 8.4.8
Unofficial docs for php/php-src
Loading...
Searching...
No Matches
pdo_stmt.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 | Author: Wez Furlong <wez@php.net> |
14 | Marcus Boerger <helly@php.net> |
15 | Sterling Hughes <sterling@php.net> |
16 +----------------------------------------------------------------------+
17*/
18
19/* The PDO Statement Handle Class */
20
21#ifdef HAVE_CONFIG_H
22#include <config.h>
23#endif
24
25#include "php.h"
26#include "php_ini.h"
27#include "ext/standard/info.h"
29#include "php_pdo.h"
30#include "php_pdo_driver.h"
31#include "php_pdo_int.h"
32#include "zend_exceptions.h"
33#include "zend_interfaces.h"
34#include "php_memory_streams.h"
35#include "pdo_stmt_arginfo.h"
36
37#define PHP_STMT_GET_OBJ \
38 pdo_stmt_t *stmt = Z_PDO_STMT_P(ZEND_THIS); \
39 if (!stmt->dbh) { \
40 zend_throw_error(NULL, "%s object is uninitialized", ZSTR_VAL(Z_OBJ(EX(This))->ce->name)); \
41 RETURN_THROWS(); \
42 } \
43
44static inline bool rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param) /* {{{ */
45{
46 if (stmt->bound_param_map) {
47 /* rewriting :name to ? style.
48 * We need to fixup the parameter numbers on the parameters.
49 * If we find that a given named parameter has been used twice,
50 * we will raise an error, as we can't be sure that it is safe
51 * to bind multiple parameters onto the same zval in the underlying
52 * driver */
54 int position = 0;
55
56 if (stmt->named_rewrite_template) {
57 /* this is not an error here */
58 return 1;
59 }
60 if (!param->name) {
61 /* do the reverse; map the parameter number to the name */
62 if ((name = zend_hash_index_find_ptr(stmt->bound_param_map, param->paramno)) != NULL) {
63 param->name = zend_string_copy(name);
64 return 1;
65 }
66 /* TODO Error? */
67 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
68 return 0;
69 }
70
72 if (!zend_string_equals(name, param->name)) {
73 position++;
74 continue;
75 }
76 if (param->paramno >= 0) {
77 /* TODO Error? */
78 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO refuses to handle repeating the same :named parameter for multiple positions with this driver, as it might be unsafe to do so. Consider using a separate name for each parameter instead");
79 return -1;
80 }
81 param->paramno = position;
82 return 1;
84 /* TODO Error? */
85 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
86 return 0;
87 }
88 return 1;
89}
90/* }}} */
91
92/* trigger callback hook for parameters */
93static bool dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type) /* {{{ */
94{
95 bool ret = 1, is_param = 1;
96 struct pdo_bound_param_data *param;
98
99 if (stmt->dbh->skip_param_evt & (1 << event_type)) {
100 return 1;
101 }
102
103 if (!stmt->methods->param_hook) {
104 return 1;
105 }
106
108
109iterate:
110 if (ht) {
111 ZEND_HASH_FOREACH_PTR(ht, param) {
112 if (!stmt->methods->param_hook(stmt, param, event_type)) {
113 ret = 0;
114 break;
115 }
117 }
118 if (ret && is_param) {
120 is_param = 0;
121 goto iterate;
122 }
123
124 return ret;
125}
126/* }}} */
127
129{
130 int col;
131
133
134 for (col = 0; col < stmt->column_count; col++) {
135 if (!stmt->methods->describer(stmt, col)) {
136 return false;
137 }
138
139 /* if we are applying case conversions on column names, do so now */
140 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
141 zend_string *orig_name = stmt->columns[col].name;
142 switch (stmt->dbh->desired_case) {
143 case PDO_CASE_LOWER:
144 stmt->columns[col].name = zend_string_tolower(orig_name);
145 zend_string_release(orig_name);
146 break;
147 case PDO_CASE_UPPER: {
148 stmt->columns[col].name = zend_string_separate(orig_name, 0);
149 char *s = ZSTR_VAL(stmt->columns[col].name);
150 while (*s != '\0') {
151 *s = toupper(*s);
152 s++;
153 }
154 break;
155 }
157 }
158 }
159
160 /* update the column index on named bound parameters */
161 if (stmt->bound_columns) {
162 struct pdo_bound_param_data *param;
163
164 if ((param = zend_hash_find_ptr(stmt->bound_columns,
165 stmt->columns[col].name)) != NULL) {
166 param->paramno = col;
167 }
168 }
169
170 }
171 return true;
172}
173/* }}} */
174
175static void pdo_stmt_reset_columns(pdo_stmt_t *stmt) {
176 if (stmt->columns) {
177 int i;
178 struct pdo_column_data *cols = stmt->columns;
179
180 for (i = 0; i < stmt->column_count; i++) {
181 if (cols[i].name) {
182 zend_string_release_ex(cols[i].name, 0);
183 }
184 }
185 efree(stmt->columns);
186 }
187 stmt->columns = NULL;
188 stmt->column_count = 0;
189}
190
196{
197 /* Columns not yet "described". */
198 if (!stmt->columns) {
199 stmt->column_count = new_count;
200 return;
201 }
202
203 /* The column count has not changed: No need to reload columns description.
204 * Note: Do not handle attribute name change, without column count change. */
205 if (new_count == stmt->column_count) {
206 return;
207 }
208
209 /* Free previous columns to force reload description. */
210 pdo_stmt_reset_columns(stmt);
211 stmt->column_count = new_count;
212}
213
214static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
215{
216 if (Z_ISUNDEF(stmt->lazy_object_ref)) {
217 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
218 row->stmt = stmt;
220 ZVAL_OBJ(&stmt->lazy_object_ref, &row->std);
221 GC_ADDREF(&stmt->std);
222 GC_DELREF(&row->std);
223 }
225}
226/* }}} */
227
228static void param_dtor(zval *el) /* {{{ */
229{
230 struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)Z_PTR_P(el);
231
232 /* tell the driver that it is going away */
233 if (param->stmt->methods->param_hook) {
234 param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE);
235 }
236
237 if (param->name) {
238 zend_string_release_ex(param->name, 0);
239 }
240
241 if (!Z_ISUNDEF(param->parameter)) {
242 zval_ptr_dtor(&param->parameter);
243 ZVAL_UNDEF(&param->parameter);
244 }
245 if (!Z_ISUNDEF(param->driver_params)) {
247 }
248 efree(param);
249}
250/* }}} */
251
252static bool really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, bool is_param) /* {{{ */
253{
256 struct pdo_bound_param_data *pparam = NULL;
257
259
260 if (!hash) {
262 zend_hash_init(hash, 13, NULL, param_dtor, 0);
263
264 if (is_param) {
266 } else {
268 }
269 }
270
271 if (!Z_ISREF(param->parameter)) {
272 parameter = &param->parameter;
273 } else {
274 parameter = Z_REFVAL(param->parameter);
275 }
276
277 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
278 if (!try_convert_to_string(parameter)) {
279 return 0;
280 }
283 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(parameter) == IS_LONG) {
285 }
286
287 param->stmt = stmt;
288 param->is_param = is_param;
289
290 if (Z_REFCOUNTED(param->driver_params)) {
291 Z_ADDREF(param->driver_params);
292 }
293
294 if (!is_param && param->name && stmt->columns) {
295 /* try to map the name to the column */
296 int i;
297
298 for (i = 0; i < stmt->column_count; i++) {
299 if (zend_string_equals(stmt->columns[i].name, param->name)) {
300 param->paramno = i;
301 break;
302 }
303 }
304
305 /* if you prepare and then execute passing an array of params keyed by names,
306 * then this will trigger, and we don't want that */
307 if (param->paramno == -1) {
308 /* Should this always be an Error? */
309 char *tmp;
310 /* TODO Error? */
311 spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
312 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
313 efree(tmp);
314 }
315 }
316
317 if (param->name) {
318 if (is_param && ZSTR_VAL(param->name)[0] != ':') {
319 zend_string *temp = zend_string_alloc(ZSTR_LEN(param->name) + 1, 0);
320 ZSTR_VAL(temp)[0] = ':';
321 memmove(ZSTR_VAL(temp) + 1, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1);
322 param->name = temp;
323 } else {
324 param->name = zend_string_init(ZSTR_VAL(param->name), ZSTR_LEN(param->name), 0);
325 }
326 }
327
328 if (is_param && !rewrite_name_to_position(stmt, param)) {
329 if (param->name) {
330 zend_string_release_ex(param->name, 0);
331 param->name = NULL;
332 }
333 return 0;
334 }
335
336 /* ask the driver to perform any normalization it needs on the
337 * parameter name. Note that it is illegal for the driver to take
338 * a reference to param, as it resides in transient storage only
339 * at this time. */
340 if (stmt->methods->param_hook) {
343 if (param->name) {
344 zend_string_release_ex(param->name, 0);
345 param->name = NULL;
346 }
347 return 0;
348 }
349 }
350
351 /* delete any other parameter registered with this number.
352 * If the parameter is named, it will be removed and correctly
353 * disposed of by the hash_update call that follows */
354 if (param->paramno >= 0) {
356 }
357
358 /* allocate storage for the parameter, keyed by its "canonical" name */
359 if (param->name) {
360 pparam = zend_hash_update_mem(hash, param->name, param, sizeof(struct pdo_bound_param_data));
361 } else {
362 pparam = zend_hash_index_update_mem(hash, param->paramno, param, sizeof(struct pdo_bound_param_data));
363 }
364
365 /* tell the driver we just created a parameter */
366 if (stmt->methods->param_hook) {
369 /* undo storage allocation; the hash will free the parameter
370 * name if required */
371 if (pparam->name) {
372 zend_hash_del(hash, pparam->name);
373 } else {
375 }
376 /* param->parameter is freed by hash dtor */
377 ZVAL_UNDEF(&param->parameter);
378 return 0;
379 }
380 }
381 return 1;
382}
383/* }}} */
384
385/* {{{ Execute a prepared statement, optionally binding parameters */
387{
388 zval *input_params = NULL;
389 int ret = 1;
390
393 Z_PARAM_ARRAY_OR_NULL(input_params)
395
398
399 if (input_params) {
400 struct pdo_bound_param_data param;
401 zval *tmp;
403 zend_ulong num_index;
404
405 if (stmt->bound_params) {
409 }
410
411 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) {
412 memset(&param, 0, sizeof(param));
413
414 if (key) {
415 /* yes this is correct. we don't want to count the null byte. ask wez */
416 param.name = key;
417 param.paramno = -1;
418 } else {
419 /* we're okay to be zero based here */
420 /* num_index is unsignend */
421 param.paramno = num_index;
422 }
423
425 ZVAL_COPY(&param.parameter, tmp);
426
427 if (!really_register_bound_param(&param, stmt, 1)) {
428 if (!Z_ISUNDEF(param.parameter)) {
429 zval_ptr_dtor(&param.parameter);
430 }
432 }
434 }
435
437 /* handle the emulated parameter binding,
438 * stmt->active_query_string holds the query with binds expanded and
439 * quoted.
440 */
441
442 /* string is leftover from previous calls so PDOStatement::debugDumpParams() can access */
444 zend_string_release(stmt->active_query_string);
446 }
447
449
450 if (ret == 0) {
451 /* no changes were made */
452 stmt->active_query_string = zend_string_copy(stmt->query_string);
453 ret = 1;
454 } else if (ret == -1) {
455 /* something broke */
457 }
458 } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE)) {
461 }
462 if (stmt->methods->executer(stmt)) {
463 if (!stmt->executed) {
464 /* this is the first execute */
465
467 /* for "big boy" drivers, we need to allocate memory to fetch
468 * the results into, so lets do that now */
470 }
471
472 stmt->executed = 1;
473 }
474
475 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST)) {
478 }
479
481 }
484}
485/* }}} */
486
487static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, enum pdo_param_type *type_override) /* {{{ */
488{
489 if (colno < 0) {
490 zend_value_error("Column index must be greater than or equal to 0");
491 ZVAL_NULL(dest);
492 return;
493 }
494
495 if (colno >= stmt->column_count) {
496 zend_value_error("Invalid column index");
497 ZVAL_NULL(dest);
498 return;
499 }
500
501 ZVAL_NULL(dest);
502 stmt->methods->get_col(stmt, colno, dest, type_override);
503
504 if (Z_TYPE_P(dest) == IS_STRING && Z_STRLEN_P(dest) == 0
506 zval_ptr_dtor_str(dest);
507 ZVAL_NULL(dest);
508 }
509
510 /* If stringification is requested, override with PDO_PARAM_STR. */
511 enum pdo_param_type pdo_param_str = PDO_PARAM_STR;
512 if (stmt->dbh->stringify) {
513 type_override = &pdo_param_str;
514 }
515
516 if (type_override && Z_TYPE_P(dest) != IS_NULL) {
517 switch (*type_override) {
518 case PDO_PARAM_INT:
519 convert_to_long(dest);
520 break;
521 case PDO_PARAM_BOOL:
522 convert_to_boolean(dest);
523 break;
524 case PDO_PARAM_STR:
525 if (Z_TYPE_P(dest) == IS_FALSE) {
526 /* Return "0" rather than "", because this is what database drivers that
527 * don't have a dedicated boolean type would return. */
528 zval_ptr_dtor_nogc(dest);
529 ZVAL_INTERNED_STR(dest, ZSTR_CHAR('0'));
530 } else if (Z_TYPE_P(dest) == IS_RESOURCE) {
531 /* Convert LOB stream to string */
532 php_stream *stream;
533 php_stream_from_zval_no_verify(stream, dest);
535 zval_ptr_dtor_nogc(dest);
536 if (str == NULL) {
537 ZVAL_EMPTY_STRING(dest);
538 } else {
539 ZVAL_STR(dest, str);
540 }
541 } else {
542 convert_to_string(dest);
543 }
544 break;
545 case PDO_PARAM_NULL:
546 convert_to_null(dest);
547 break;
548 case PDO_PARAM_LOB:
549 if (Z_TYPE_P(dest) == IS_STRING) {
550 php_stream *stream =
552 zval_ptr_dtor_str(dest);
553 php_stream_to_zval(stream, dest);
554 }
555 break;
556 default:
557 break;
558 }
559 }
560
562 ZVAL_EMPTY_STRING(dest);
563 }
564}
565/* }}} */
566
567static bool do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset) /* {{{ */
568{
569 if (!stmt->executed) {
570 return 0;
571 }
572
573 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE)) {
574 return 0;
575 }
576
577 if (!stmt->methods->fetcher(stmt, ori, offset)) {
578 return 0;
579 }
580
581 /* some drivers might need to describe the columns now */
583 return 0;
584 }
585
586 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST)) {
587 return 0;
588 }
589
590 if (stmt->bound_columns) {
591 /* update those bound column variables now */
592 struct pdo_bound_param_data *param;
593
595 if (param->paramno >= 0) {
596 if (!Z_ISREF(param->parameter)) {
597 continue;
598 }
599
600 /* delete old value */
602
603 /* set new value */
604 fetch_value(stmt, Z_REFVAL(param->parameter), param->paramno, &param->param_type);
605
606 /* TODO: some smart thing that avoids duplicating the value in the
607 * general loop below. For now, if you're binding output columns,
608 * it's better to use LAZY or BOUND fetches if you want to shave
609 * off those cycles */
610 }
612 }
613
614 return 1;
615}
616/* }}} */
617
618static bool do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
619{
623
624 fci->size = sizeof(zend_fcall_info);
625
626 if (!ce) {
629 }
630
631 if (ce->constructor) {
633 fci->retval = &stmt->fetch.cls.retval;
634 fci->param_count = 0;
635 fci->params = NULL;
636
638
639 fcc->function_handler = ce->constructor;
640 fcc->called_scope = ce;
641 return 1;
642 } else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
643 zend_throw_error(NULL, "User-supplied statement does not accept constructor arguments");
644 return 0;
645 } else {
646 return 1; /* no ctor no args is also ok */
647 }
648}
649/* }}} */
650
651static bool make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args) /* {{{ */
652{
653 char *is_callable_error = NULL;
654
655 if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error) == FAILURE) {
656 if (is_callable_error) {
657 zend_type_error("%s", is_callable_error);
658 efree(is_callable_error);
659 } else {
660 zend_type_error("User-supplied function must be a valid callback");
661 }
662 return false;
663 }
664 if (is_callable_error) {
665 /* Possible error message */
666 efree(is_callable_error);
667 }
668
669 fci->param_count = num_args; /* probably less */
670 fci->params = safe_emalloc(sizeof(zval), num_args, 0);
671
672 return true;
673}
674/* }}} */
675
676static bool do_fetch_func_prepare(pdo_stmt_t *stmt) /* {{{ */
677{
680
681 if (!make_callable_ex(stmt, &stmt->fetch.func.function, fci, fcc, stmt->column_count)) {
682 return false;
683 } else {
685 return true;
686 }
687}
688/* }}} */
689
690static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
691{
692 /* fci.size is used to check if it is valid */
695 /* Added to free constructor arguments */
697 } else {
699 }
701 }
702
703 stmt->fetch.cls.fci.size = 0;
704 if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args) && free_ctor_agrs) {
708 }
709 if (stmt->fetch.func.values) {
712 }
713}
714/* }}} */
715
716/* perform a fetch.
717 * Stores values into return_value according to HOW. */
718static bool do_fetch(pdo_stmt_t *stmt, zval *return_value, enum pdo_fetch_type how, enum pdo_fetch_orientation ori, zend_long offset, zval *return_all) /* {{{ */
719{
720 int flags, idx, old_arg_count = 0;
721 zend_class_entry *ce = NULL, *old_ce = NULL;
722 zval grp_val, *pgrp, retval, old_ctor_args = {{0}, {0}, {0}};
723 int colno;
724 int i = 0;
725
726 if (how == PDO_FETCH_USE_DEFAULT) {
728 }
729 flags = how & PDO_FETCH_FLAGS;
730 how = how & ~PDO_FETCH_FLAGS;
731
732 if (!do_fetch_common(stmt, ori, offset)) {
733 return 0;
734 }
735
736 if (how == PDO_FETCH_BOUND) {
738 return 1;
739 }
740
741 if ((flags & PDO_FETCH_GROUP) && stmt->fetch.column == -1) {
742 colno = 1;
743 } else {
744 colno = stmt->fetch.column;
745 }
746
747 if (how == PDO_FETCH_LAZY) {
748 get_lazy_object(stmt, return_value);
749 return 1;
750 }
751
753
754 switch (how) {
756 case PDO_FETCH_ASSOC:
757 case PDO_FETCH_BOTH:
758 case PDO_FETCH_NUM:
759 case PDO_FETCH_NAMED:
760 if (!return_all) {
762 } else {
764 }
765 break;
766
768 if (stmt->column_count != 2) {
769 /* TODO: Error? */
770 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain exactly 2 columns.");
771 return 0;
772 }
773 if (!return_all) {
775 }
776 break;
777
778 case PDO_FETCH_COLUMN:
779 if (colno < 0 ) {
780 zend_value_error("Column index must be greater than or equal to 0");
781 return false;
782 }
783
784 if (colno >= stmt->column_count) {
785 zend_value_error("Invalid column index");
786 return false;
787 }
788
789 if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
790 fetch_value(stmt, return_value, 1, NULL);
791 } else if (flags == PDO_FETCH_GROUP && colno) {
792 fetch_value(stmt, return_value, 0, NULL);
793 } else {
794 fetch_value(stmt, return_value, colno, NULL);
795 }
796 if (!return_all) {
797 return 1;
798 }
799 break;
800
801 case PDO_FETCH_OBJ:
803 break;
804
805 case PDO_FETCH_CLASS:
807 zval val;
808 zend_class_entry *cep;
809
810 old_ce = stmt->fetch.cls.ce;
811 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
812 old_arg_count = stmt->fetch.cls.fci.param_count;
813 do_fetch_opt_finish(stmt, 0);
814
815 fetch_value(stmt, &val, i++, NULL);
816 if (Z_TYPE(val) != IS_NULL) {
817 if (!try_convert_to_string(&val)) {
818 return 0;
819 }
820 if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
822 } else {
823 stmt->fetch.cls.ce = cep;
824 }
825 }
826
827 do_fetch_class_prepare(stmt);
828 zval_ptr_dtor_str(&val);
829 }
830 ce = stmt->fetch.cls.ce;
831 /* TODO: Make this an assertion and ensure this is true higher up? */
832 if (!ce) {
833 /* TODO Error? */
834 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
835 return 0;
836 }
837 if ((flags & PDO_FETCH_SERIALIZE) == 0) {
839 return 0;
840 }
841 if (!stmt->fetch.cls.fci.size) {
842 if (!do_fetch_class_prepare(stmt)) {
844 return 0;
845 }
846 }
847 if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
851 /* TODO Error? */
852 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
853 return 0;
854 } else {
855 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
858 }
859 }
860 }
861 }
862 break;
863
864 case PDO_FETCH_INTO:
865 /* TODO: Make this an assertion and ensure this is true higher up? */
866 if (Z_ISUNDEF(stmt->fetch.into)) {
867 /* TODO ArgumentCountError? */
868 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
869 return 0;
870 break;
871 }
872
874
876 how = PDO_FETCH_OBJ;
877 }
878 break;
879
880 case PDO_FETCH_FUNC:
881 /* TODO: Make this an assertion and ensure this is true higher up? */
883 /* TODO ArgumentCountError? */
884 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
885 return 0;
886 }
887 if (!stmt->fetch.func.fci.size) {
888 if (!do_fetch_func_prepare(stmt))
889 {
890 return 0;
891 }
892 }
893 break;
895 }
896
897 if (return_all && how != PDO_FETCH_KEY_PAIR) {
898 if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
899 fetch_value(stmt, &grp_val, colno, NULL);
900 } else {
901 fetch_value(stmt, &grp_val, i, NULL);
902 }
903 convert_to_string(&grp_val);
904 if (how == PDO_FETCH_COLUMN) {
905 i = stmt->column_count; /* no more data to fetch */
906 } else {
907 i++;
908 }
909 }
910
911 for (idx = 0; i < stmt->column_count; i++, idx++) {
912 zval val;
913 fetch_value(stmt, &val, i, NULL);
914
915 switch (how) {
916 case PDO_FETCH_ASSOC:
917 zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
918 break;
919
921 {
922 zval tmp;
923 fetch_value(stmt, &tmp, ++i, NULL);
924
925 if (Z_TYPE(val) == IS_LONG) {
926 zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL(val), &tmp);
927 } else {
929 zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STR(val), &tmp);
930 }
932 return 1;
933 }
934 break;
935
937 case PDO_FETCH_BOTH:
938 zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
941 }
942 break;
943
944 case PDO_FETCH_NAMED:
945 /* already have an item with this name? */
946 {
947 zval *curr_val;
948 if ((curr_val = zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name))) {
949 zval arr;
950 if (Z_TYPE_P(curr_val) != IS_ARRAY) {
951 /* a little bit of black magic here:
952 * we're creating a new array and swapping it for the
953 * zval that's already stored in the hash under the name
954 * we want. We then add that zval to the array.
955 * This is effectively the same thing as:
956 * if (!is_array($hash[$name])) {
957 * $hash[$name] = array($hash[$name]);
958 * }
959 * */
960 zval cur;
961
962 array_init(&arr);
963
964 ZVAL_COPY_VALUE(&cur, curr_val);
965 ZVAL_COPY_VALUE(curr_val, &arr);
966
968 } else {
969 ZVAL_COPY_VALUE(&arr, curr_val);
970 }
972 } else {
974 }
975 }
976 break;
977
978 case PDO_FETCH_NUM:
980 break;
981
982 case PDO_FETCH_OBJ:
983 case PDO_FETCH_INTO:
985 stmt->columns[i].name,
986 &val);
988 break;
989
990 case PDO_FETCH_CLASS:
991 if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
993 stmt->columns[i].name,
994 &val);
996 } else {
997 if (!ce->unserialize) {
999 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
1000 return 0;
1001 } else if (ce->unserialize(return_value, ce, (unsigned char *)(Z_TYPE(val) == IS_STRING ? Z_STRVAL(val) : ""), Z_TYPE(val) == IS_STRING ? Z_STRLEN(val) : 0, NULL) == FAILURE) {
1003 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
1006 return 0;
1007 } else {
1009 }
1010 }
1011 break;
1012
1013 case PDO_FETCH_FUNC:
1016 break;
1017
1018 default:
1020 zend_value_error("Fetch mode must be a bitmask of PDO::FETCH_* constants");
1021 return 0;
1022 }
1023 }
1024
1025 switch (how) {
1026 case PDO_FETCH_CLASS:
1031 /* TODO Error? */
1032 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
1033 return 0;
1034 } else {
1035 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
1037 }
1038 }
1039 }
1040 if (flags & PDO_FETCH_CLASSTYPE) {
1041 do_fetch_opt_finish(stmt, 0);
1042 stmt->fetch.cls.ce = old_ce;
1043 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1044 stmt->fetch.cls.fci.param_count = old_arg_count;
1045 }
1046 break;
1047
1048 case PDO_FETCH_FUNC:
1049 stmt->fetch.func.fci.param_count = idx;
1052 /* TODO Error? */
1053 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
1054 return 0;
1055 } else {
1056 if (return_all) {
1057 zval_ptr_dtor(return_value); /* we don't need that */
1059 } else if (!Z_ISUNDEF(retval)) {
1061 }
1062 }
1063 while (idx--) {
1065 }
1066 break;
1067
1068 default:
1069 break;
1070 }
1071
1072 if (return_all) {
1074 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), return_value);
1075 } else {
1076 zval grp;
1077 if ((pgrp = zend_symtable_find(Z_ARRVAL_P(return_all), Z_STR(grp_val))) == NULL) {
1078 array_init(&grp);
1079 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), &grp);
1080 } else {
1081 ZVAL_COPY_VALUE(&grp, pgrp);
1082 }
1084 }
1085 zval_ptr_dtor_str(&grp_val);
1086 }
1087
1088 return 1;
1089}
1090/* }}} */
1091
1092static bool pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num, bool fetch_all) /* {{{ */
1093{
1094 int flags = mode & PDO_FETCH_FLAGS;
1095
1097
1099 zend_argument_value_error(mode_arg_num, "must be a bitmask of PDO::FETCH_* constants");
1100 return 0;
1101 }
1102
1103 if (mode == PDO_FETCH_USE_DEFAULT) {
1106 }
1107
1108 switch(mode) {
1109 case PDO_FETCH_FUNC:
1110 if (!fetch_all) {
1111 zend_value_error("Can only use PDO::FETCH_FUNC in PDOStatement::fetchAll()");
1112 return 0;
1113 }
1114 return 1;
1115
1116 case PDO_FETCH_LAZY:
1117 if (fetch_all) {
1118 zend_argument_value_error(mode_arg_num, "cannot be PDO::FETCH_LAZY in PDOStatement::fetchAll()");
1119 return 0;
1120 }
1122 default:
1124 zend_argument_value_error(mode_arg_num, "must use PDO::FETCH_SERIALIZE with PDO::FETCH_CLASS");
1125 return 0;
1126 }
1128 zend_argument_value_error(mode_arg_num, "must use PDO::FETCH_CLASSTYPE with PDO::FETCH_CLASS");
1129 return 0;
1130 }
1131 if (mode >= PDO_FETCH__MAX) {
1132 zend_argument_value_error(mode_arg_num, "must be a bitmask of PDO::FETCH_* constants");
1133 return 0;
1134 }
1136
1137 case PDO_FETCH_CLASS:
1138 if (flags & PDO_FETCH_SERIALIZE) {
1139 php_error_docref(NULL, E_DEPRECATED, "The PDO::FETCH_SERIALIZE mode is deprecated");
1140 }
1141 return 1;
1142 }
1143}
1144/* }}} */
1145
1146/* {{{ Fetches the next row and returns it, or false if there are no more rows */
1148{
1151 zend_long off = 0;
1152
1155 Z_PARAM_LONG(how)
1156 Z_PARAM_LONG(ori)
1157 Z_PARAM_LONG(off)
1159
1162
1163 if (!pdo_stmt_verify_mode(stmt, how, 1, false)) {
1164 RETURN_THROWS();
1165 }
1166
1167 if (!do_fetch(stmt, return_value, how, ori, off, NULL)) {
1170 }
1171}
1172/* }}} */
1173
1174/* {{{ Fetches the next row and returns it as an object. */
1176{
1177 zend_class_entry *ce = NULL;
1178 zend_class_entry *old_ce;
1179 zval old_ctor_args, *ctor_args = NULL;
1180 int old_arg_count;
1181
1185 Z_PARAM_ARRAY(ctor_args)
1187
1190
1191 old_ce = stmt->fetch.cls.ce;
1192 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
1193 old_arg_count = stmt->fetch.cls.fci.param_count;
1194
1195 do_fetch_opt_finish(stmt, 0);
1196
1197 if (ctor_args && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1199 } else {
1201 }
1202 if (ce) {
1203 stmt->fetch.cls.ce = ce;
1204 } else {
1206 }
1207
1208 if (!do_fetch(stmt, return_value, PDO_FETCH_CLASS, PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL)) {
1211 }
1212 do_fetch_opt_finish(stmt, 1);
1213
1214 stmt->fetch.cls.ce = old_ce;
1215 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1216 stmt->fetch.cls.fci.param_count = old_arg_count;
1217}
1218/* }}} */
1219
1220/* {{{ Returns a data of the specified column in the result set. */
1222{
1223 zend_long col_n = 0;
1224
1227 Z_PARAM_LONG(col_n)
1229
1232
1233 if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0)) {
1236 }
1237
1238 fetch_value(stmt, return_value, col_n, NULL);
1239}
1240/* }}} */
1241
1242/* {{{ Returns an array of all of the results. */
1244{
1246 zval data, *return_all = NULL;
1247 zval *arg2 = NULL;
1248 zend_class_entry *old_ce;
1249 zval old_ctor_args, *ctor_args = NULL;
1250 HashTable *current_ctor = NULL;
1251 bool error = false;
1252 int flags, old_arg_count;
1253
1256 Z_PARAM_LONG(how)
1258 Z_PARAM_ARRAY_OR_NULL(ctor_args)
1260
1262 if (!pdo_stmt_verify_mode(stmt, how, 1, true)) {
1263 RETURN_THROWS();
1264 }
1265
1266 old_ce = stmt->fetch.cls.ce;
1267 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
1268 if (Z_TYPE(old_ctor_args) == IS_ARRAY) {
1269 /* Protect against destruction by marking this as immutable: we consider this non-owned temporarily */
1271 }
1272 old_arg_count = stmt->fetch.cls.fci.param_count;
1273
1274 do_fetch_opt_finish(stmt, 0);
1275
1276 /* TODO Would be good to reuse part of pdo_stmt_setup_fetch_mode() in some way */
1277
1278 switch (how & ~PDO_FETCH_FLAGS) {
1279 case PDO_FETCH_CLASS:
1280 /* Figure out correct class */
1281 if (arg2) {
1282 if (Z_TYPE_P(arg2) != IS_STRING) {
1283 zend_argument_type_error(2, "must be of type string, %s given", zend_zval_value_name(arg2));
1284 RETURN_THROWS();
1285 }
1287 if (!stmt->fetch.cls.ce) {
1288 zend_argument_type_error(2, "must be a valid class");
1289 RETURN_THROWS();
1290 }
1291 } else {
1293 }
1294
1295 if (ctor_args && zend_hash_num_elements(Z_ARRVAL_P(ctor_args)) > 0) {
1296 /* We increase the refcount and store it in case usercode has been messing around with the ctor args.
1297 * We need to store current_ctor separately as usercode may change the ctor_args which will cause a leak. */
1298 current_ctor = Z_ARRVAL_P(ctor_args);
1299 ZVAL_COPY(&stmt->fetch.cls.ctor_args, ctor_args);
1300 /* Protect against destruction by marking this as immutable: we consider this non-owned
1301 * as destruction is handled via current_ctor. */
1303 } else {
1305 }
1306
1307 do_fetch_class_prepare(stmt);
1308 break;
1309
1310 case PDO_FETCH_FUNC: /* Cannot be a default fetch mode */
1311 if (ZEND_NUM_ARGS() != 2) {
1313 zend_argument_count_error("%s() expects exactly 2 argument for PDO::FETCH_FUNC, %d given",
1315 zend_string_release(func);
1316 RETURN_THROWS();
1317 }
1318 if (arg2 == NULL) {
1319 /* TODO use "must be of type callable" format? */
1320 zend_argument_type_error(2, "must be a callable, null given");
1321 RETURN_THROWS();
1322 }
1323 /* TODO Check it is a callable? */
1325 if (do_fetch_func_prepare(stmt) == false) {
1326 RETURN_THROWS();
1327 }
1328 break;
1329
1330 case PDO_FETCH_COLUMN:
1331 if (ZEND_NUM_ARGS() > 2) {
1333 zend_argument_count_error("%s() expects at most 2 argument for the fetch mode provided, %d given",
1335 zend_string_release(func);
1336 RETURN_THROWS();
1337 }
1338 /* Is column index passed? */
1339 if (arg2) {
1340 // Reuse convert_to_long(arg2); ?
1341 if (Z_TYPE_P(arg2) != IS_LONG) {
1342 zend_argument_type_error(2, "must be of type int, %s given", zend_zval_value_name(arg2));
1343 RETURN_THROWS();
1344 }
1345 if (Z_LVAL_P(arg2) < 0) {
1346 zend_argument_value_error(2, "must be greater than or equal to 0");
1347 RETURN_THROWS();
1348 }
1350 } else {
1351 stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1352 }
1353 break;
1354
1355 default:
1356 /* No support for PDO_FETCH_INTO which takes 2 args??? */
1357 if (ZEND_NUM_ARGS() > 1) {
1359 zend_argument_count_error("%s() expects exactly 1 argument for the fetch mode provided, %d given",
1361 zend_string_release(func);
1362 RETURN_THROWS();
1363 }
1364 }
1365
1366 flags = how & PDO_FETCH_FLAGS;
1367
1368 if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1371 }
1372
1374
1375 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1377 ) {
1379 return_all = return_value;
1380 }
1381 if (!do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, return_all)) {
1382 error = true;
1383 }
1384
1385 if (!error) {
1386 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1388 ) {
1389 while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, return_all));
1390 } else {
1392 do {
1394 } while (do_fetch(stmt, &data, how | flags, PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL));
1395 }
1396 }
1397
1398 do_fetch_opt_finish(stmt, 0);
1399 if (current_ctor) {
1400 zend_array_release(current_ctor);
1401 }
1402
1403 /* Restore defaults which were changed by PDO_FETCH_CLASS mode */
1404 stmt->fetch.cls.ce = old_ce;
1405 /* ctor_args may have been changed to an owned object in the meantime, so destroy it.
1406 * If it was not, then the type flags update will have protected us against destruction. */
1408 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1409 stmt->fetch.cls.fci.param_count = old_arg_count;
1410
1411 /* on no results, return an empty array */
1412 if (error) {
1414 if (Z_TYPE_P(return_value) != IS_ARRAY) {
1416 }
1417 }
1418}
1419/* }}} */
1420
1421static void register_bound_param(INTERNAL_FUNCTION_PARAMETERS, int is_param) /* {{{ */
1422{
1423 struct pdo_bound_param_data param;
1426
1427 memset(&param, 0, sizeof(param));
1428
1430 Z_PARAM_STR_OR_LONG(param.name, param.paramno)
1437
1439
1440 param.param_type = (int) param_type;
1441
1442 if (param.name) {
1443 if (ZSTR_LEN(param.name) == 0) {
1444 zend_argument_must_not_be_empty_error(1);
1445 RETURN_THROWS();
1446 }
1447 param.paramno = -1;
1448 } else if (param.paramno > 0) {
1449 --param.paramno; /* make it zero-based internally */
1450 } else {
1451 zend_argument_value_error(1, "must be greater than or equal to 1");
1452 RETURN_THROWS();
1453 }
1454
1455 if (driver_params) {
1457 }
1458
1459 ZVAL_COPY(&param.parameter, parameter);
1460 if (!really_register_bound_param(&param, stmt, is_param)) {
1461 if (!Z_ISUNDEF(param.parameter)) {
1462 zval_ptr_dtor(&(param.parameter));
1463 }
1464
1466 }
1467
1469} /* }}} */
1470
1471/* {{{ bind an input parameter to the value of a PHP variable. $paramno is the 1-based position of the placeholder in the SQL statement (but can be the parameter name for drivers that support named placeholders). It should be called prior to execute(). */
1473{
1474 struct pdo_bound_param_data param;
1476 zval *parameter;
1477
1478 memset(&param, 0, sizeof(param));
1479
1481 Z_PARAM_STR_OR_LONG(param.name, param.paramno)
1486
1488 param.param_type = (int) param_type;
1489
1490 if (param.name) {
1491 if (ZSTR_LEN(param.name) == 0) {
1493 RETURN_THROWS();
1494 }
1495 param.paramno = -1;
1496 } else if (param.paramno > 0) {
1497 --param.paramno; /* make it zero-based internally */
1498 } else {
1499 zend_argument_value_error(1, "must be greater than or equal to 1");
1500 RETURN_THROWS();
1501 }
1502
1503 ZVAL_COPY(&param.parameter, parameter);
1504 if (!really_register_bound_param(&param, stmt, TRUE)) {
1505 if (!Z_ISUNDEF(param.parameter)) {
1506 zval_ptr_dtor(&(param.parameter));
1507 ZVAL_UNDEF(&param.parameter);
1508 }
1510 }
1512}
1513/* }}} */
1514
1515/* {{{ bind a parameter to a PHP variable. $paramno is the 1-based position of the placeholder in the SQL statement (but can be the parameter name for drivers that support named placeholders). This isn't supported by all drivers. It should be called prior to execute(). */
1517{
1518 register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1);
1519}
1520/* }}} */
1521
1522/* {{{ bind a column to a PHP variable. On each row fetch $param will contain the value of the corresponding column. $column is the 1-based offset of the column, or the column name. For portability, don't call this before execute(). */
1524{
1525 register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0);
1526}
1527/* }}} */
1528
1529/* {{{ Returns the number of rows in a result set, or the number of rows affected by the last execute(). It is not always meaningful. */
1537/* }}} */
1538
1539/* {{{ Fetch the error code associated with the last operation on the statement handle */
1541{
1543
1545 if (stmt->error_code[0] == '\0') {
1546 RETURN_NULL();
1547 }
1548
1550}
1551/* }}} */
1552
1553/* {{{ Fetch extended error information associated with the last operation on the statement handle */
1555{
1556 int error_count;
1557 int error_count_diff = 0;
1558 int error_expected_count = 3;
1559
1561
1565
1567 if (stmt->dbh->methods->fetch_err) {
1569 }
1570 }
1571
1572 error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1573
1574 if (error_expected_count > error_count) {
1575 int current_index;
1576
1577 error_count_diff = error_expected_count - error_count;
1578 for (current_index = 0; current_index < error_count_diff; current_index++) {
1580 }
1581 }
1582}
1583/* }}} */
1584
1585/* {{{ Set an attribute */
1587{
1589 zval *value = NULL;
1590
1595
1597
1598 /* Driver hasn't registered a function for setting attributes */
1599 if (!stmt->methods->set_attribute) {
1600 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes");
1602 }
1603
1607 }
1608
1609 /* Error while setting attribute */
1612}
1613/* }}} */
1614
1615/* {{{ Get an attribute */
1616
1617static bool generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, zend_long attr)
1618{
1619 switch (attr) {
1622 return 1;
1623 }
1624 return 0;
1625}
1626
1628{
1630
1634
1636 if (!stmt->methods->get_attribute) {
1637 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1638 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1639 "This driver doesn't support getting attributes");
1641 }
1642 return;
1643 }
1644
1647 case -1:
1650
1651 case 0:
1652 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1653 /* XXX: should do something better here */
1654 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1655 "driver doesn't support getting that attribute");
1657 }
1658 return;
1659
1660 default:
1661 return;
1662 }
1663}
1664/* }}} */
1665
1666/* {{{ Returns the number of columns in the result set */
1674/* }}} */
1675
1676/* {{{ Returns meta data for a numbered column */
1678{
1679 zend_long colno;
1680 struct pdo_column_data *col;
1681
1683 Z_PARAM_LONG(colno)
1685
1687 if (colno < 0) {
1688 zend_argument_value_error(1, "must be greater than or equal to 0");
1689 RETURN_THROWS();
1690 }
1691
1692 if (!stmt->methods->get_column_meta) {
1693 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data");
1695 }
1696
1698 if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value)) {
1701 }
1702
1703 /* add stock items */
1704 col = &stmt->columns[colno];
1705 add_assoc_str(return_value, "name", zend_string_copy(col->name));
1706 add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1707 add_assoc_long(return_value, "precision", col->precision);
1708}
1709/* }}} */
1710
1711/* {{{ Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1712
1713bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num,
1714 zval *args, uint32_t variadic_num_args)
1715{
1716 int flags = 0;
1717 uint32_t arg1_arg_num = mode_arg_num + 1;
1718 uint32_t constructor_arg_num = mode_arg_num + 2;
1719 uint32_t total_num_args = mode_arg_num + variadic_num_args;
1720
1721 switch (stmt->default_fetch_type) {
1722 case PDO_FETCH_INTO:
1723 if (!Z_ISUNDEF(stmt->fetch.into)) {
1724 zval_ptr_dtor(&stmt->fetch.into);
1725 ZVAL_UNDEF(&stmt->fetch.into);
1726 }
1727 break;
1728 default:
1729 ;
1730 }
1731
1733
1735
1736 if (!pdo_stmt_verify_mode(stmt, mode, mode_arg_num, false)) {
1737 return false;
1738 }
1739
1740 switch (mode & ~PDO_FETCH_FLAGS) {
1742 case PDO_FETCH_LAZY:
1743 case PDO_FETCH_ASSOC:
1744 case PDO_FETCH_NUM:
1745 case PDO_FETCH_BOTH:
1746 case PDO_FETCH_OBJ:
1747 case PDO_FETCH_BOUND:
1748 case PDO_FETCH_NAMED:
1749 case PDO_FETCH_KEY_PAIR:
1750 if (variadic_num_args != 0) {
1752 zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
1753 ZSTR_VAL(func), mode_arg_num, total_num_args);
1754 zend_string_release(func);
1755 return false;
1756 }
1757 break;
1758
1759 case PDO_FETCH_COLUMN:
1760 if (variadic_num_args != 1) {
1762 zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
1763 ZSTR_VAL(func), arg1_arg_num, total_num_args);
1764 zend_string_release(func);
1765 return false;
1766 }
1767 if (Z_TYPE(args[0]) != IS_LONG) {
1768 zend_argument_type_error(arg1_arg_num, "must be of type int, %s given", zend_zval_value_name(&args[0]));
1769 return false;
1770 }
1771 if (Z_LVAL(args[0]) < 0) {
1772 zend_argument_value_error(arg1_arg_num, "must be greater than or equal to 0");
1773 return false;
1774 }
1775 stmt->fetch.column = Z_LVAL(args[0]);
1776 break;
1777
1778 case PDO_FETCH_CLASS: {
1779 HashTable *constructor_args = NULL;
1780 /* Undef constructor arguments */
1781 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
1782 /* Gets its class name from 1st column */
1784 if (variadic_num_args != 0) {
1786 zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
1787 ZSTR_VAL(func), mode_arg_num, total_num_args);
1788 zend_string_release(func);
1789 return false;
1790 }
1791 stmt->fetch.cls.ce = NULL;
1792 } else {
1793 zend_class_entry *cep;
1794 if (variadic_num_args == 0) {
1796 zend_argument_count_error("%s() expects at least %d arguments for the fetch mode provided, %d given",
1797 ZSTR_VAL(func), arg1_arg_num, total_num_args);
1798 zend_string_release(func);
1799 return false;
1800 }
1801 /* constructor_arguments can be null/not passed */
1802 if (variadic_num_args > 2) {
1804 zend_argument_count_error("%s() expects at most %d arguments for the fetch mode provided, %d given",
1805 ZSTR_VAL(func), constructor_arg_num, total_num_args);
1806 zend_string_release(func);
1807 return false;
1808 }
1809 if (Z_TYPE(args[0]) != IS_STRING) {
1810 zend_argument_type_error(arg1_arg_num, "must be of type string, %s given", zend_zval_value_name(&args[0]));
1811 return false;
1812 }
1813 cep = zend_lookup_class(Z_STR(args[0]));
1814 if (!cep) {
1815 zend_argument_type_error(arg1_arg_num, "must be a valid class");
1816 return false;
1817 }
1818 /* Verify constructor_args (args[1]) is ?array */
1819 /* TODO: Improve logic? */
1820 if (variadic_num_args == 2) {
1821 if (Z_TYPE(args[1]) != IS_NULL && Z_TYPE(args[1]) != IS_ARRAY) {
1822 zend_argument_type_error(constructor_arg_num, "must be of type ?array, %s given",
1824 return false;
1825 }
1826 if (Z_TYPE(args[1]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[1]))) {
1827 constructor_args = Z_ARRVAL(args[1]);
1828 }
1829 }
1830 stmt->fetch.cls.ce = cep;
1831
1832 /* If constructor arguments are present and not empty */
1833 if (constructor_args) {
1834 ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(constructor_args));
1835 }
1836 }
1837
1838 do_fetch_class_prepare(stmt);
1839 break;
1840 }
1841 case PDO_FETCH_INTO:
1842 if (total_num_args != arg1_arg_num) {
1844 zend_argument_count_error("%s() expects exactly %d arguments for the fetch mode provided, %d given",
1845 ZSTR_VAL(func), arg1_arg_num, total_num_args);
1846 zend_string_release(func);
1847 return false;
1848 }
1849 if (Z_TYPE(args[0]) != IS_OBJECT) {
1850 zend_argument_type_error(arg1_arg_num, "must be of type object, %s given", zend_zval_value_name(&args[0]));
1851 return false;
1852 }
1853
1854 ZVAL_COPY(&stmt->fetch.into, &args[0]);
1855 break;
1856 default:
1857 zend_argument_value_error(mode_arg_num, "must be one of the PDO::FETCH_* constants");
1858 return false;
1859 }
1860
1861 stmt->default_fetch_type = mode;
1862
1863 return true;
1864}
1865
1867{
1868 zend_long fetch_mode;
1869 zval *args = NULL;
1870 uint32_t num_args = 0;
1871
1872 if (zend_parse_parameters(ZEND_NUM_ARGS(), "l*", &fetch_mode, &args, &num_args) == FAILURE) {
1873 RETURN_THROWS();
1874 }
1875
1877
1878 do_fetch_opt_finish(stmt, 1);
1879
1880 if (!pdo_stmt_setup_fetch_mode(stmt, fetch_mode, 1, args, num_args)) {
1881 RETURN_THROWS();
1882 }
1883
1884 // TODO Void return?
1886}
1887/* }}} */
1888
1889/* {{{ Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeeded, false otherwise */
1890
1891static bool pdo_stmt_do_next_rowset(pdo_stmt_t *stmt)
1892{
1893 pdo_stmt_reset_columns(stmt);
1894
1895 if (!stmt->methods->next_rowset(stmt)) {
1896 /* Set the executed flag to 0 to reallocate columns on next execute */
1897 stmt->executed = 0;
1898 return 0;
1899 }
1900
1902
1903 return 1;
1904}
1905
1907{
1909
1911 if (!stmt->methods->next_rowset) {
1912 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets");
1914 }
1915
1917
1918 if (!pdo_stmt_do_next_rowset(stmt)) {
1921 }
1922
1924}
1925/* }}} */
1926
1927/* {{{ Closes the cursor, leaving the statement ready for re-execution. */
1929{
1931
1933 if (!stmt->methods->cursor_closer) {
1934 /* emulate it by fetching and discarding rows */
1935 do {
1936 while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0))
1937 ;
1938 if (!stmt->methods->next_rowset) {
1939 break;
1940 }
1941
1942 if (!pdo_stmt_do_next_rowset(stmt)) {
1943 break;
1944 }
1945
1946 } while (1);
1947 stmt->executed = 0;
1949 }
1950
1952
1953 if (!stmt->methods->cursor_closer(stmt)) {
1956 }
1957 stmt->executed = 0;
1959}
1960/* }}} */
1961
1962/* {{{ A utility for internals hackers to debug parameter internals */
1963PHP_METHOD(PDOStatement, debugDumpParams)
1964{
1966
1967 php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
1968 struct pdo_bound_param_data *param;
1969
1971
1973
1974 if (out == NULL) {
1976 }
1977
1978 /* break into multiple operations so query string won't be truncated at FORMAT_CONV_MAX_PRECISION */
1979 php_stream_printf(out, "SQL: [%zd] ", ZSTR_LEN(stmt->query_string));
1981 php_stream_write(out, "\n", 1);
1982
1983 /* show parsed SQL if emulated prepares enabled */
1984 /* pointers will be equal if PDO::query() was invoked */
1986 /* break into multiple operations so query string won't be truncated at FORMAT_CONV_MAX_PRECISION */
1987 php_stream_printf(out, "Sent SQL: [%zd] ", ZSTR_LEN(stmt->active_query_string));
1989 php_stream_write(out, "\n", 1);
1990 }
1991
1992 php_stream_printf(out, "Params: %d\n",
1993 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
1994
1995 if (stmt->bound_params) {
1996 zend_ulong num;
1997 zend_string *key = NULL;
1999 if (key) {
2000 php_stream_printf(out, "Key: Name: [%zd] %.*s\n",
2001 ZSTR_LEN(key), (int) ZSTR_LEN(key), ZSTR_VAL(key));
2002 } else {
2003 php_stream_printf(out, "Key: Position #" ZEND_ULONG_FMT ":\n", num);
2004 }
2005
2007 "paramno=" ZEND_LONG_FMT "\n"
2008 "name=[%zd] \"%.*s\"\n"
2009 "is_param=%d\n"
2010 "param_type=%d\n",
2011 param->paramno, param->name ? ZSTR_LEN(param->name) : 0, param->name ? (int) ZSTR_LEN(param->name) : 0,
2012 param->name ? ZSTR_VAL(param->name) : "",
2013 param->is_param,
2014 param->param_type);
2015
2017 }
2018
2020}
2021/* }}} */
2022
2024{
2026 return;
2027 }
2028
2030}
2031
2032/* {{{ overloaded handlers for PDOStatement class */
2033static zval *dbstmt_prop_write(zend_object *object, zend_string *name, zval *value, void **cache_slot)
2034{
2035 if (zend_string_equals_literal(name, "queryString")) {
2036 zval *query_string = OBJ_PROP_NUM(object, 0);
2037 if (!Z_ISUNDEF_P(query_string)) {
2038 zend_throw_error(NULL, "Property queryString is read only");
2039 return value;
2040 }
2041 }
2042 return zend_std_write_property(object, name, value, cache_slot);
2043}
2044
2045static void dbstmt_prop_delete(zend_object *object, zend_string *name, void **cache_slot)
2046{
2047 if (zend_string_equals_literal(name, "queryString")) {
2048 zend_throw_error(NULL, "Property queryString is read only");
2049 } else {
2050 zend_std_unset_property(object, name, cache_slot);
2051 }
2052}
2053
2054static zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key)
2055{
2057 zend_string *lc_method_name;
2058 zend_object *object = *object_pp;
2059
2060 lc_method_name = zend_string_tolower(method_name);
2061
2062 if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
2063 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
2064 /* instance not created by PDO object */
2065 if (!stmt->dbh) {
2066 goto out;
2067 }
2068 /* not a pre-defined method, nor a user-defined method; check
2069 * the driver specific methods */
2074 goto out;
2075 }
2076 }
2077
2078 if ((fbc = zend_hash_find_ptr(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT], lc_method_name)) == NULL) {
2079 goto out;
2080 }
2081 /* got it */
2082 }
2083
2084out:
2085 zend_string_release_ex(lc_method_name, 0);
2086 if (!fbc) {
2087 fbc = zend_std_get_method(object_pp, method_name, key);
2088 }
2089 return fbc;
2090}
2091
2092static HashTable *dbstmt_get_gc(zend_object *object, zval **gc_data, int *gc_count)
2093{
2094 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
2095
2097 zend_get_gc_buffer_add_zval(gc_buffer, &stmt->database_object_handle);
2098 zend_get_gc_buffer_add_zval(gc_buffer, &stmt->fetch.into);
2099 zend_get_gc_buffer_use(gc_buffer, gc_data, gc_count);
2100
2105 if (object->properties == NULL && object->ce->default_properties_count <= 1) {
2106 return NULL;
2107 } else {
2108 return zend_std_get_properties(object);
2109 }
2110}
2111
2114
2116{
2117 if (stmt->bound_params) {
2121 }
2122 if (stmt->bound_param_map) {
2126 }
2127 if (stmt->bound_columns) {
2131 }
2132
2133 if (stmt->methods && stmt->methods->dtor) {
2134 stmt->methods->dtor(stmt);
2135 }
2137 zend_string_release(stmt->active_query_string);
2138 }
2139 if (stmt->query_string) {
2140 zend_string_release(stmt->query_string);
2141 }
2142
2143 pdo_stmt_reset_columns(stmt);
2144
2148 }
2149
2150 do_fetch_opt_finish(stmt, 1);
2151
2154 }
2156}
2157
2159{
2160 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(std);
2162}
2163
2165{
2167
2168 stmt = zend_object_alloc(sizeof(pdo_stmt_t), ce);
2171
2172 return &stmt->std;
2173}
2174/* }}} */
2175
2176/* {{{ statement iterator */
2177
2183
2184static void pdo_stmt_iter_dtor(zend_object_iterator *iter)
2185{
2186 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2187
2188 zval_ptr_dtor(&I->iter.data);
2189
2190 if (!Z_ISUNDEF(I->fetch_ahead)) {
2191 zval_ptr_dtor(&I->fetch_ahead);
2192 }
2193}
2194
2195static zend_result pdo_stmt_iter_valid(zend_object_iterator *iter)
2196{
2197 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2198
2199 return Z_ISUNDEF(I->fetch_ahead) ? FAILURE : SUCCESS;
2200}
2201
2202static zval *pdo_stmt_iter_get_data(zend_object_iterator *iter)
2203{
2204 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2205
2206 /* sanity */
2207 if (Z_ISUNDEF(I->fetch_ahead)) {
2208 return NULL;
2209 }
2210
2211 return &I->fetch_ahead;
2212}
2213
2214static void pdo_stmt_iter_get_key(zend_object_iterator *iter, zval *key)
2215{
2216 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2217
2218 if (I->key == (zend_ulong)-1) {
2219 ZVAL_NULL(key);
2220 } else {
2221 ZVAL_LONG(key, I->key);
2222 }
2223}
2224
2225static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter)
2226{
2227 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2228 pdo_stmt_t *stmt = Z_PDO_STMT_P(&I->iter.data); /* for PDO_HANDLE_STMT_ERR() */
2229
2230 if (!Z_ISUNDEF(I->fetch_ahead)) {
2231 zval_ptr_dtor(&I->fetch_ahead);
2232 }
2233
2234 if (!do_fetch(stmt, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2235 PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL)) {
2236
2238 I->key = (zend_ulong)-1;
2239 ZVAL_UNDEF(&I->fetch_ahead);
2240
2241 return;
2242 }
2243
2244 I->key++;
2245}
2246
2247static const zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2248 pdo_stmt_iter_dtor,
2249 pdo_stmt_iter_valid,
2250 pdo_stmt_iter_get_data,
2251 pdo_stmt_iter_get_key,
2252 pdo_stmt_iter_move_forwards,
2253 NULL,
2254 NULL,
2255 NULL, /* get_gc */
2256};
2257
2259{
2260 if (by_ref) {
2261 zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
2262 return NULL;
2263 }
2264
2265 pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
2266 if (!stmt->dbh) {
2267 zend_throw_error(NULL, "%s object is uninitialized", ZSTR_VAL(ce->name));
2268 return NULL;
2269 }
2270
2271 struct php_pdo_iterator *I = ecalloc(1, sizeof(struct php_pdo_iterator));
2272 zend_iterator_init(&I->iter);
2273 I->iter.funcs = &pdo_stmt_iter_funcs;
2274 Z_ADDREF_P(object);
2275 ZVAL_OBJ(&I->iter.data, Z_OBJ_P(object));
2276
2277 if (!do_fetch(stmt, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2278 PDO_FETCH_ORI_NEXT, /* offset */ 0, NULL)) {
2280 I->key = (zend_ulong)-1;
2281 ZVAL_UNDEF(&I->fetch_ahead);
2282 }
2283
2284 return &I->iter;
2285}
2286
2287/* }}} */
2288
2289/* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2290static zval *row_read_column_name(pdo_stmt_t *stmt, zend_string *name, zval *rv)
2291{
2292 /* TODO: replace this with a hash of available column names to column numbers */
2293 for (int colno = 0; colno < stmt->column_count; colno++) {
2294 if (zend_string_equals(stmt->columns[colno].name, name)) {
2295 fetch_value(stmt, rv, colno, NULL);
2296 return rv;
2297 }
2298 }
2299 return NULL;
2300}
2301
2302static zval *row_read_column_number(pdo_stmt_t *stmt, zend_long column, zval *rv)
2303{
2304 if (column >= 0 && column < stmt->column_count) {
2305 fetch_value(stmt, rv, column, NULL);
2306 return rv;
2307 }
2308 return NULL;
2309}
2310
2311static zval *row_prop_read(zend_object *object, zend_string *name, int type, void **cache_slot, zval *rv)
2312{
2313 pdo_row_t *row = (pdo_row_t *)object;
2314 pdo_stmt_t *stmt = row->stmt;
2315 zend_long lval;
2316 zval *retval;
2317 ZEND_ASSERT(stmt);
2318
2319 ZVAL_NULL(rv);
2320 if (zend_string_equals_literal(name, "queryString")) {
2321 return zend_std_read_property(&stmt->std, name, type, cache_slot, rv);
2322 } else if (is_numeric_str_function(name, &lval, /* dval */ NULL) == IS_LONG) {
2323 retval = row_read_column_number(stmt, lval, rv);
2324 } else {
2325 retval = row_read_column_name(stmt, name, rv);
2326 }
2327 if (UNEXPECTED(!retval)) {
2328 // TODO throw an error on master
2329 //if (type != BP_VAR_IS) {
2330 // if (is_numeric) {
2331 // zend_value_error("Invalid column index");
2332 // } else {
2333 // zend_throw_error(NULL, "No column named \"%s\" exists", ZSTR_VAL(name));
2334 // }
2335 //}
2336 //return &EG(uninitialized_zval);
2337 ZVAL_NULL(rv);
2338 return rv;
2339 }
2340 return retval;
2341}
2342
2343static zval *row_dim_read(zend_object *object, zval *offset, int type, zval *rv)
2344{
2345 if (UNEXPECTED(!offset)) {
2346 zend_throw_error(NULL, "Cannot append to PDORow offset");
2347 return NULL;
2348 }
2349 if (Z_TYPE_P(offset) == IS_LONG) {
2350 pdo_row_t *row = (pdo_row_t *)object;
2351 pdo_stmt_t *stmt = row->stmt;
2352 ZEND_ASSERT(stmt);
2353
2354 ZVAL_NULL(rv);
2355 if (Z_LVAL_P(offset) >= 0 && Z_LVAL_P(offset) < stmt->column_count) {
2356 fetch_value(stmt, rv, Z_LVAL_P(offset), NULL);
2357 }
2358 return rv;
2359 } else {
2360 zend_string *member = zval_try_get_string(offset);
2361 if (!member) {
2362 return NULL;
2363 }
2364 zval *result = row_prop_read(object, member, type, NULL, rv);
2365 zend_string_release_ex(member, false);
2366 return result;
2367 }
2368}
2369
2370static zval *row_prop_write(zend_object *object, zend_string *name, zval *value, void **cache_slot)
2371{
2372 zend_throw_error(NULL, "Cannot write to PDORow property");
2373 return value;
2374}
2375
2376static void row_dim_write(zend_object *object, zval *member, zval *value)
2377{
2378 if (!member) {
2379 zend_throw_error(NULL, "Cannot append to PDORow offset");
2380 } else {
2381 zend_throw_error(NULL, "Cannot write to PDORow offset");
2382 }
2383}
2384
2385// todo: make row_prop_exists return bool as well
2386static int row_prop_exists(zend_object *object, zend_string *name, int check_empty, void **cache_slot)
2387{
2388 pdo_row_t *row = (pdo_row_t *)object;
2389 pdo_stmt_t *stmt = row->stmt;
2390 zend_long lval;
2391 zval tmp_val;
2392 zval *retval = NULL;
2393 ZEND_ASSERT(stmt);
2394
2395 if (is_numeric_str_function(name, &lval, /* dval */ NULL) == IS_LONG) {
2396 retval = row_read_column_number(stmt, lval, &tmp_val);
2397 } else {
2398 retval = row_read_column_name(stmt, name, &tmp_val);
2399 }
2400
2401 if (!retval) {
2402 return false;
2403 }
2404 ZEND_ASSERT(retval == &tmp_val);
2405 bool res = check_empty ? i_zend_is_true(retval) : Z_TYPE(tmp_val) != IS_NULL;
2406 zval_ptr_dtor_nogc(retval);
2407
2408 return res;
2409}
2410
2411
2412// todo: make row_dim_exists return bool as well
2413static int row_dim_exists(zend_object *object, zval *offset, int check_empty)
2414{
2415 if (Z_TYPE_P(offset) == IS_LONG) {
2416 pdo_row_t *row = (pdo_row_t *)object;
2417 pdo_stmt_t *stmt = row->stmt;
2418 ZEND_ASSERT(stmt);
2419 zend_long column = Z_LVAL_P(offset);
2420
2421 if (!check_empty) {
2422 return column >= 0 && column < stmt->column_count;
2423 }
2424
2425 zval tmp_val;
2426 zval *retval = row_read_column_number(stmt, column, &tmp_val);
2427 if (!retval) {
2428 return false;
2429 }
2430 ZEND_ASSERT(retval == &tmp_val);
2431 bool res = check_empty ? i_zend_is_true(retval) : Z_TYPE(tmp_val) != IS_NULL;
2432 zval_ptr_dtor_nogc(retval);
2433 return res;
2434 } else {
2435 zend_string *member = zval_try_get_string(offset);
2436 if (!member) {
2437 return 0;
2438 }
2439 int result = row_prop_exists(object, member, check_empty, NULL);
2440 zend_string_release_ex(member, false);
2441 return result;
2442 }
2443}
2444
2445static void row_prop_delete(zend_object *object, zend_string *offset, void **cache_slot)
2446{
2447 zend_throw_error(NULL, "Cannot unset PDORow property");
2448}
2449
2450static void row_dim_delete(zend_object *object, zval *offset)
2451{
2452 zend_throw_error(NULL, "Cannot unset PDORow offset");
2453}
2454
2455static HashTable *row_get_properties_for(zend_object *object, zend_prop_purpose purpose)
2456{
2457 pdo_row_t *row = (pdo_row_t *)object;
2458 pdo_stmt_t *stmt = row->stmt;
2459 HashTable *props;
2460 int i;
2461 ZEND_ASSERT(stmt);
2462
2463 if (purpose != ZEND_PROP_PURPOSE_DEBUG) {
2464 return zend_std_get_properties_for(object, purpose);
2465 }
2466
2467 props = zend_array_dup(zend_std_get_properties_ex(&stmt->std));
2468 for (i = 0; i < stmt->column_count; i++) {
2469 if (zend_string_equals_literal(stmt->columns[i].name, "queryString")) {
2470 continue;
2471 }
2472
2473 zval val;
2474 fetch_value(stmt, &val, i, NULL);
2475
2476 zend_hash_update(props, stmt->columns[i].name, &val);
2477 }
2478 return props;
2479}
2480
2481static zend_function *row_get_ctor(zend_object *object)
2482{
2483 zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually");
2484 return NULL;
2485}
2486
2487static zval *pdo_row_get_property_ptr_ptr(zend_object *object, zend_string *name, int type, void **cache_slot)
2488{
2489 ZEND_IGNORE_VALUE(object);
2492
2493 if (cache_slot) {
2494 cache_slot[0] = cache_slot[1] = cache_slot[2] = NULL;
2495 }
2496 return NULL;
2497}
2498
2500{
2501 pdo_row_t *row = (pdo_row_t *)std;
2502 if (row->stmt) {
2504 OBJ_RELEASE(&row->stmt->std);
2505 }
2507}
2508
2510{
2511 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
2512 zend_object_std_init(&row->std, ce);
2513
2514 return &row->std;
2515}
2516
2518{
2519 pdo_dbstmt_ce = register_class_PDOStatement(zend_ce_aggregate);
2520 pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2521 pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2522 pdo_dbstmt_ce->default_object_handlers = &pdo_dbstmt_object_handlers;
2523
2527 pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2528 pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2529 pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2531 pdo_dbstmt_object_handlers.clone_obj = NULL;
2532 pdo_dbstmt_object_handlers.get_gc = dbstmt_get_gc;
2533
2534 pdo_row_ce = register_class_PDORow();
2535 pdo_row_ce->create_object = pdo_row_new;
2536 pdo_row_ce->default_object_handlers = &pdo_row_object_handlers;
2537
2540 pdo_row_object_handlers.clone_obj = NULL;
2541 pdo_row_object_handlers.get_property_ptr_ptr = pdo_row_get_property_ptr_ptr;
2542 pdo_row_object_handlers.read_property = row_prop_read;
2543 pdo_row_object_handlers.write_property = row_prop_write;
2544 pdo_row_object_handlers.has_property = row_prop_exists;
2545 pdo_row_object_handlers.unset_property = row_prop_delete;
2546 pdo_row_object_handlers.read_dimension = row_dim_read;
2547 pdo_row_object_handlers.write_dimension = row_dim_write;
2548 pdo_row_object_handlers.has_dimension = row_dim_exists;
2549 pdo_row_object_handlers.unset_dimension = row_dim_delete;
2550 pdo_row_object_handlers.get_properties_for = row_get_properties_for;
2551 pdo_row_object_handlers.get_constructor = row_get_ctor;
2553}
char s[4]
Definition cdf.c:77
error($message)
Definition ext_skel.php:22
zend_ffi_type * type
Definition ffi.c:3812
zend_string * res
Definition ffi.c:4692
memcpy(ptr1, ptr2, size)
memset(ptr, 0, type->size)
new_type attr
Definition ffi.c:4364
zval * val
Definition ffi.c:4262
HashTable * ht
Definition ffi.c:4838
#define I
Definition encoding.c:237
zend_long offset
char * mode
#define TRUE
Definition gd_gd.c:7
#define NULL
Definition gdcache.h:45
hash(string $algo, string $data, bool $binary=false, array $options=[])
Definition hash.stub.php:12
#define SUCCESS
Definition hash_sha3.c:261
foreach($dp as $el) foreach( $dp as $el) if( $pass2< 2) echo ""
PHPAPI ZEND_COLD void php_error_docref(const char *docref, int type, const char *format,...)
Definition main.c:1173
#define memmove(a, b, c)
zend_class_entry * pdo_row_ce
Definition pdo.c:34
zend_class_entry * pdo_dbstmt_ce
Definition pdo.c:34
PDO_API zend_class_entry * php_pdo_get_exception(void)
Definition pdo.c:62
void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, pdo_error_type sqlstate, const char *supp)
Definition pdo_dbh.c:68
bool pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
Definition pdo_dbh.c:1333
void pdo_row_free_storage(zend_object *std)
Definition pdo_stmt.c:2499
zend_object_handlers pdo_dbstmt_object_handlers
Definition pdo_stmt.c:2112
zend_object_handlers pdo_row_object_handlers
Definition pdo_stmt.c:2113
void pdo_stmt_init(void)
Definition pdo_stmt.c:2517
#define PHP_STMT_GET_OBJ
Definition pdo_stmt.c:37
zend_object * pdo_row_new(zend_class_entry *ce)
Definition pdo_stmt.c:2509
zend_object_iterator * pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref)
Definition pdo_stmt.c:2258
bool pdo_stmt_describe_columns(pdo_stmt_t *stmt)
Definition pdo_stmt.c:128
PDO_API void php_pdo_stmt_set_column_count(pdo_stmt_t *stmt, int new_count)
Definition pdo_stmt.c:195
bool pdo_stmt_setup_fetch_mode(pdo_stmt_t *stmt, zend_long mode, uint32_t mode_arg_num, zval *args, uint32_t variadic_num_args)
Definition pdo_stmt.c:1713
zend_object * pdo_dbstmt_new(zend_class_entry *ce)
Definition pdo_stmt.c:2164
PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
Definition pdo_stmt.c:2115
void pdo_dbstmt_free_storage(zend_object *std)
Definition pdo_stmt.c:2158
#define PHP_METHOD
Definition php.h:365
#define php_stream_memory_open(mode, str)
#define TEMP_STREAM_READONLY
#define PDO_API
Definition php_pdo.h:42
PDO_API int pdo_parse_params(pdo_stmt_t *stmt, zend_string *inquery, zend_string **outquery)
#define PDO_FETCH_SERIALIZE
#define PDO_ERR_NONE
#define PDO_FETCH_CLASSTYPE
#define PDO_FETCH_PROPS_LATE
struct _pdo_stmt_t pdo_stmt_t
#define Z_PDO_STMT_P(zv)
pdo_param_type
@ PDO_PARAM_LOB
@ PDO_PARAM_BOOL
@ PDO_PARAM_INT
@ PDO_PARAM_NULL
@ PDO_PARAM_STR
@ PDO_CASE_UPPER
@ PDO_CASE_LOWER
@ PDO_CASE_NATURAL
struct _pdo_row_t pdo_row_t
pdo_param_event
@ PDO_PARAM_EVT_ALLOC
@ PDO_PARAM_EVT_EXEC_PRE
@ PDO_PARAM_EVT_FETCH_POST
@ PDO_PARAM_EVT_NORMALIZE
@ PDO_PARAM_EVT_FETCH_PRE
@ PDO_PARAM_EVT_EXEC_POST
@ PDO_PARAM_EVT_FREE
@ PDO_NULL_TO_STRING
@ PDO_NULL_EMPTY_STRING
pdo_fetch_type
@ PDO_FETCH_BOTH
@ PDO_FETCH_FUNC
@ PDO_FETCH_OBJ
@ PDO_FETCH_KEY_PAIR
@ PDO_FETCH_NUM
@ PDO_FETCH_USE_DEFAULT
@ PDO_FETCH_LAZY
@ PDO_FETCH_CLASS
@ PDO_FETCH_NAMED
@ PDO_FETCH_COLUMN
@ PDO_FETCH__MAX
@ PDO_FETCH_INTO
@ PDO_FETCH_BOUND
@ PDO_FETCH_ASSOC
pdo_fetch_orientation
@ PDO_FETCH_ORI_NEXT
@ PDO_DBH_DRIVER_METHOD_KIND_STMT
@ PDO_PLACEHOLDER_NONE
#define PDO_FETCH_UNIQUE
#define PDO_FETCH_GROUP
#define PDO_PARAM_TYPE(x)
#define PDO_FETCH_FLAGS
#define Z_PDO_OBJECT_P(zv)
@ PDO_ATTR_EMULATE_PREPARES
#define PDO_STMT_CLEAR_ERR()
#define PDO_HANDLE_STMT_ERR()
unsigned char key[REFLECTION_KEY_LEN]
struct _php_stream php_stream
Definition php_streams.h:96
#define PHP_STREAM_COPY_ALL
#define php_stream_to_zval(stream, zval)
#define php_stream_printf
#define php_stream_close(stream)
#define php_stream_copy_to_mem(src, maxlen, persistent)
#define php_stream_open_wrapper(path, mode, options, opened)
#define php_stream_from_zval_no_verify(xstr, pzval)
#define php_stream_write(stream, buf, count)
zend_constant * data
zval rv
Definition session.c:1024
#define spprintf
Definition spprintf.h:29
HashTable * cls_methods[PDO_DBH_DRIVER_METHOD_KIND__MAX]
enum pdo_case_conversion native_case desired_case
unsigned stringify
unsigned alloc_own_columns
const struct pdo_dbh_methods * methods
unsigned skip_param_evt
unsigned oracle_nulls
zend_object std
pdo_stmt_t * stmt
const char * named_rewrite_template
zend_string * active_query_string
zend_string * query_string
zend_object std
struct _pdo_stmt_t::@000166265162112000164105002261207304326156154222::@025212024050336036211311351177267270061100211054 func
unsigned executed
unsigned supports_placeholders
zend_fcall_info fci
zend_class_entry * ce
pdo_error_type error_code
HashTable * bound_params
const struct pdo_stmt_methods * methods
struct pdo_column_data * columns
struct _pdo_stmt_t::@000166265162112000164105002261207304326156154222::@331145212346317037010055150102225036053125106064 cls
zend_fcall_info_cache fcc
enum pdo_fetch_type default_fetch_type
zval database_object_handle
union _pdo_stmt_t::@000166265162112000164105002261207304326156154222 fetch
HashTable * bound_param_map
zend_long row_count
pdo_dbh_t * dbh
HashTable * bound_columns
zend_string * name
Definition zend.h:149
zend_function * constructor
Definition zend.h:172
int(* unserialize)(zval *object, zend_class_entry *ce, const unsigned char *buf, size_t buf_len, zend_unserialize_data *data)
Definition zend.h:203
zend_function * function_handler
Definition zend_API.h:60
zend_class_entry * called_scope
Definition zend_API.h:62
zend_object * object
Definition zend_API.h:63
uint32_t param_count
Definition zend_API.h:51
zend_object * object
Definition zend_API.h:50
enum pdo_param_type param_type
zend_ulong precision
zend_string * name
pdo_dbh_fetch_error_func fetch_err
pdo_stmt_param_hook_func param_hook
pdo_stmt_fetch_func fetcher
pdo_stmt_dtor_func dtor
pdo_stmt_cursor_closer_func cursor_closer
pdo_stmt_next_rowset_func next_rowset
pdo_stmt_get_col_data_func get_col
pdo_stmt_get_attr_func get_attribute
pdo_stmt_execute_func executer
pdo_stmt_describe_col_func describer
pdo_stmt_get_column_meta_func get_column_meta
pdo_stmt_set_attr_func set_attribute
zend_ulong key
Definition pdo_stmt.c:2180
zend_object_iterator iter
Definition pdo_stmt.c:2179
ZEND_API ZEND_COLD void zend_argument_count_error(const char *format,...)
Definition zend.c:1836
ZEND_API ZEND_COLD void zend_throw_error(zend_class_entry *exception_ce, const char *format,...)
Definition zend.c:1772
ZEND_API zend_class_entry * zend_standard_class_def
Definition zend.c:83
ZEND_API ZEND_COLD void zend_type_error(const char *format,...)
Definition zend.c:1824
ZEND_API ZEND_COLD void zend_value_error(const char *format,...)
Definition zend.c:1849
#define INTERNAL_FUNCTION_PARAMETERS
Definition zend.h:49
#define ZEND_STANDARD_CLASS_DEF_PTR
Definition zend.h:406
#define INTERNAL_FUNCTION_PARAM_PASSTHRU
Definition zend.h:50
ZEND_API zend_result add_next_index_null(zval *arg)
Definition zend_API.c:2141
ZEND_API const char * zend_zval_value_name(const zval *arg)
Definition zend_API.c:148
ZEND_API zend_result object_init_ex(zval *arg, zend_class_entry *class_type)
Definition zend_API.c:1849
ZEND_API zend_result zend_fcall_info_init(zval *callable, uint32_t check_flags, zend_fcall_info *fci, zend_fcall_info_cache *fcc, zend_string **callable_name, char **error)
Definition zend_API.c:4310
ZEND_API zend_result zend_fcall_info_args_ex(zend_fcall_info *fci, zend_function *func, zval *args)
Definition zend_API.c:4364
ZEND_API void zend_fcall_info_args_clear(zend_fcall_info *fci, bool free_mem)
Definition zend_API.c:4328
ZEND_API zend_result zend_parse_parameters(uint32_t num_args, const char *type_spec,...)
Definition zend_API.c:1300
ZEND_API void object_properties_init(zend_object *object, zend_class_entry *class_type)
Definition zend_API.c:1688
ZEND_API ZEND_COLD void zend_argument_must_not_be_empty_error(uint32_t arg_num)
Definition zend_API.c:443
ZEND_API ZEND_COLD void zend_argument_value_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:433
ZEND_API ZEND_COLD void zend_argument_type_error(uint32_t arg_num, const char *format,...)
Definition zend_API.c:423
ZEND_API void zend_update_property_ex(zend_class_entry *scope, zend_object *object, zend_string *name, zval *value)
Definition zend_API.c:4979
ZEND_API zend_result add_next_index_string(zval *arg, const char *str)
Definition zend_API.c:2186
#define ZEND_NUM_ARGS()
Definition zend_API.h:530
struct _zend_fcall_info_cache zend_fcall_info_cache
#define Z_PARAM_ARRAY_OR_NULL(dest)
Definition zend_API.h:1685
#define Z_PARAM_CLASS_OR_NULL(dest)
Definition zend_API.h:1743
#define RETURN_STRING(s)
Definition zend_API.h:1043
#define ZEND_PARSE_PARAMETERS_END()
Definition zend_API.h:1641
#define RETURN_FALSE
Definition zend_API.h:1058
#define ZEND_PARSE_PARAMETERS_NONE()
Definition zend_API.h:1623
#define RETURN_NULL()
Definition zend_API.h:1036
#define array_init_size(arg, size)
Definition zend_API.h:538
#define Z_PARAM_OPTIONAL
Definition zend_API.h:1667
#define zend_parse_parameters_none()
Definition zend_API.h:353
#define ZEND_PARSE_PARAMETERS_START(min_num_args, max_num_args)
Definition zend_API.h:1620
#define Z_PARAM_LONG(dest)
Definition zend_API.h:1896
#define RETURN_LONG(l)
Definition zend_API.h:1037
#define RETURN_BOOL(b)
Definition zend_API.h:1035
struct _zend_fcall_info zend_fcall_info
#define RETURN_THROWS()
Definition zend_API.h:1060
#define RETVAL_TRUE
Definition zend_API.h:1033
#define ZEND_THIS
Definition zend_API.h:523
#define RETVAL_BOOL(b)
Definition zend_API.h:1009
#define Z_PARAM_STR_OR_LONG(dest_str, dest_long)
Definition zend_API.h:2165
#define Z_PARAM_ARRAY(dest)
Definition zend_API.h:1682
#define Z_PARAM_ZVAL_OR_NULL(dest)
Definition zend_API.h:2103
#define Z_PARAM_ZVAL(dest)
Definition zend_API.h:2100
#define RETVAL_FALSE
Definition zend_API.h:1032
ZEND_API zend_result zend_call_function(zend_fcall_info *fci, zend_fcall_info_cache *fci_cache)
#define RETURN_TRUE
Definition zend_API.h:1059
#define array_init(arg)
Definition zend_API.h:537
#define ZVAL_EMPTY_STRING(z)
Definition zend_API.h:961
#define ecalloc(nmemb, size)
Definition zend_alloc.h:158
#define efree(ptr)
Definition zend_alloc.h:155
#define FREE_HASHTABLE(ht)
Definition zend_alloc.h:234
#define safe_emalloc(nmemb, size, offset)
Definition zend_alloc.h:154
#define ALLOC_HASHTABLE(ht)
Definition zend_alloc.h:231
struct _zval_struct zval
strncmp(string $string1, string $string2, int $length)
uint32_t num_args
zend_string_release_ex(func->internal_function.function_name, 0)
execute_data func
zval * args
#define ZEND_FETCH_CLASS_AUTO
#define OBJ_PROP_NUM(obj, num)
#define E_DEPRECATED
Definition zend_errors.h:37
ZEND_API ZEND_COLD zend_object * zend_throw_exception_ex(zend_class_entry *exception_ce, zend_long code, const char *format,...)
ZEND_API zend_class_entry * zend_lookup_class(zend_string *name)
ZEND_API zend_class_entry * zend_fetch_class(zend_string *class_name, uint32_t fetch_type)
ZEND_API zend_string * get_active_function_or_method_name(void)
union _zend_function zend_function
ZEND_API zend_get_gc_buffer * zend_get_gc_buffer_create(void)
Definition zend_gc.c:2130
ZEND_API void ZEND_FASTCALL zend_hash_destroy(HashTable *ht)
Definition zend_hash.c:1727
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert_new(HashTable *ht, zval *pData)
Definition zend_hash.c:1229
ZEND_API zval *ZEND_FASTCALL zend_hash_index_add(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1209
ZEND_API zval *ZEND_FASTCALL zend_hash_next_index_insert(HashTable *ht, zval *pData)
Definition zend_hash.c:1224
ZEND_API zend_result ZEND_FASTCALL zend_hash_index_del(HashTable *ht, zend_ulong h)
Definition zend_hash.c:1692
ZEND_API zval *ZEND_FASTCALL zend_hash_index_update(HashTable *ht, zend_ulong h, zval *pData)
Definition zend_hash.c:1219
ZEND_API HashTable *ZEND_FASTCALL zend_array_dup(HashTable *source)
Definition zend_hash.c:2438
ZEND_API zval *ZEND_FASTCALL zend_hash_update(HashTable *ht, zend_string *key, zval *pData)
Definition zend_hash.c:997
ZEND_API zend_result ZEND_FASTCALL zend_hash_del(HashTable *ht, zend_string *key)
Definition zend_hash.c:1534
ZEND_API zval *ZEND_FASTCALL zend_hash_find(const HashTable *ht, zend_string *key)
Definition zend_hash.c:2668
#define zend_hash_init(ht, nSize, pHashFunction, pDestructor, persistent)
Definition zend_hash.h:108
#define ZEND_HASH_FOREACH_PTR(ht, _ptr)
Definition zend_hash.h:1118
#define ZEND_HASH_FOREACH_KEY_VAL(ht, _h, _key, _val)
Definition zend_hash.h:1181
#define ZEND_HASH_FOREACH_END()
Definition zend_hash.h:1086
#define ZEND_HASH_FOREACH_KEY_PTR(ht, _h, _key, _ptr)
Definition zend_hash.h:1235
ZEND_API zend_class_entry * zend_ce_aggregate
ZEND_API zend_result zend_create_internal_iterator_zval(zval *return_value, zval *obj)
ZEND_API void zend_iterator_init(zend_object_iterator *iter)
struct _zend_object_iterator zend_object_iterator
struct _zend_object_iterator_funcs zend_object_iterator_funcs
#define ZEND_ULONG_FMT
Definition zend_long.h:88
int32_t zend_long
Definition zend_long.h:42
uint32_t zend_ulong
Definition zend_long.h:43
#define ZEND_LONG_FMT
Definition zend_long.h:87
struct _zend_string zend_string
ZEND_API zend_function * zend_std_get_method(zend_object **obj_ptr, zend_string *method_name, const zval *key)
ZEND_API int zend_objects_not_comparable(zval *o1, zval *o2)
ZEND_API HashTable * zend_std_get_properties_for(zend_object *obj, zend_prop_purpose purpose)
ZEND_API HashTable * zend_std_get_properties(zend_object *zobj)
ZEND_API const zend_object_handlers std_object_handlers
ZEND_API zval * zend_std_write_property(zend_object *zobj, zend_string *name, zval *value, void **cache_slot)
ZEND_API void zend_std_unset_property(zend_object *zobj, zend_string *name, void **cache_slot)
ZEND_API zval * zend_std_read_property(zend_object *zobj, zend_string *name, int type, void **cache_slot, zval *rv)
enum _zend_prop_purpose zend_prop_purpose
@ ZEND_PROP_PURPOSE_DEBUG
ZEND_API void ZEND_FASTCALL zend_object_std_init(zend_object *object, zend_class_entry *ce)
ZEND_API void zend_object_std_dtor(zend_object *object)
#define OBJ_RELEASE(obj)
ZEND_API void ZEND_FASTCALL convert_to_boolean(zval *op)
ZEND_API uint8_t ZEND_FASTCALL is_numeric_str_function(const zend_string *str, zend_long *lval, double *dval)
ZEND_API void ZEND_FASTCALL convert_to_null(zval *op)
ZEND_API void ZEND_FASTCALL convert_to_long(zval *op)
#define convert_to_string(op)
#define ZEND_IGNORE_VALUE(x)
#define ZEND_FALLTHROUGH
#define XtOffsetOf(s_type, field)
#define ZEND_ASSERT(c)
#define EMPTY_SWITCH_DEFAULT_CASE()
#define UNEXPECTED(condition)
struct _zend_class_entry zend_class_entry
struct _zend_object zend_object
#define ZSTR_VAL(zstr)
Definition zend_string.h:68
#define zend_string_equals_literal(str, literal)
#define ZSTR_LEN(zstr)
Definition zend_string.h:69
#define ZSTR_CHAR(c)
#define Z_TYPE_P(zval_p)
Definition zend_types.h:660
#define IS_TRUE
Definition zend_types.h:603
#define ZVAL_STR(z, s)
#define ZVAL_UNDEF(z)
#define IS_FALSE
Definition zend_types.h:602
#define Z_ISUNDEF_P(zval_p)
Definition zend_types.h:957
#define Z_ARRVAL_P(zval_p)
Definition zend_types.h:987
#define ZVAL_NULL(z)
#define ZVAL_LONG(z, l)
#define IS_STRING
Definition zend_types.h:606
struct _zend_array HashTable
Definition zend_types.h:386
#define Z_ISNULL_P(zval_p)
Definition zend_types.h:960
#define IS_RESOURCE
Definition zend_types.h:609
#define Z_OBJ_P(zval_p)
Definition zend_types.h:990
#define IS_ARRAY
Definition zend_types.h:607
#define Z_ISUNDEF(zval)
Definition zend_types.h:956
#define Z_STR_P(zval_p)
Definition zend_types.h:972
#define Z_PTR_P(zval_p)
#define Z_STR(zval)
Definition zend_types.h:971
#define GC_DELREF(p)
Definition zend_types.h:710
#define GC_ADDREF(p)
Definition zend_types.h:709
#define Z_REFVAL(zval)
#define Z_ADDREF_P(pz)
#define Z_REFCOUNTED(zval)
Definition zend_types.h:917
#define Z_STRLEN_P(zval_p)
Definition zend_types.h:978
#define IS_NULL
Definition zend_types.h:601
#define ZVAL_OBJ(z, o)
#define Z_STRVAL(zval)
Definition zend_types.h:974
@ FAILURE
Definition zend_types.h:61
#define Z_TRY_ADDREF(z)
#define Z_STRLEN(zval)
Definition zend_types.h:977
#define IS_OBJECT
Definition zend_types.h:608
#define Z_ADDREF(z)
#define IS_LONG
Definition zend_types.h:604
#define ZVAL_ARR(z, a)
#define ZVAL_COPY(z, v)
#define Z_TYPE_INFO(zval)
Definition zend_types.h:668
ZEND_RESULT_CODE zend_result
Definition zend_types.h:64
#define Z_ISREF(zval)
Definition zend_types.h:953
struct _zend_object_handlers zend_object_handlers
Definition zend_types.h:88
#define Z_TYPE(zval)
Definition zend_types.h:659
#define ZVAL_INTERNED_STR(z, s)
#define Z_ARRVAL(zval)
Definition zend_types.h:986
#define Z_LVAL_P(zval_p)
Definition zend_types.h:966
#define ZVAL_COPY_VALUE(z, v)
#define Z_LVAL(zval)
Definition zend_types.h:965
ZEND_API void zval_ptr_dtor(zval *zval_ptr)
zval retval
zval * return_value
zval * arg2
zend_string * name
zend_function * fbc
bool result
object
zval * ret
value
out($f, $s)