1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) The PHP Group |
6 +----------------------------------------------------------------------+
7 | This source file is subject to version 3.01 of the PHP license, |
8 | that is bundled with this package in the file LICENSE, and is |
9 | available through the world-wide-web at the following url: |
10 | http://www.php.net/license/3_01.txt |
11 | If you did not receive a copy of the PHP license and are unable to |
12 | obtain it through the world-wide-web, please send a note to |
13 | license@php.net so we can mail you a copy immediately. |
14 +----------------------------------------------------------------------+
15 | Author: Wez Furlong <wez@php.net> |
16 | Marcus Boerger <helly@php.net> |
17 | Sterling Hughes <sterling@php.net> |
18 +----------------------------------------------------------------------+
19 */
20
21 /* The PDO Statement Handle Class */
22
23 #ifdef HAVE_CONFIG_H
24 #include "config.h"
25 #endif
26
27 #include "php.h"
28 #include "php_ini.h"
29 #include "ext/standard/info.h"
30 #include "ext/standard/php_var.h"
31 #include "php_pdo.h"
32 #include "php_pdo_driver.h"
33 #include "php_pdo_int.h"
34 #include "zend_exceptions.h"
35 #include "zend_interfaces.h"
36 #include "php_memory_streams.h"
37
38 /* {{{ arginfo */
39 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement__void, 0)
ZEND_END_ARG_INFO()40 ZEND_END_ARG_INFO()
41
42 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_execute, 0, 0, 0)
43 ZEND_ARG_INFO(0, bound_input_params) /* array */
44 ZEND_END_ARG_INFO()
45
46 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetch, 0, 0, 0)
47 ZEND_ARG_INFO(0, how)
48 ZEND_ARG_INFO(0, orientation)
49 ZEND_ARG_INFO(0, offset)
50 ZEND_END_ARG_INFO()
51
52 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchobject, 0, 0, 0)
53 ZEND_ARG_INFO(0, class_name)
54 ZEND_ARG_INFO(0, ctor_args) /* array */
55 ZEND_END_ARG_INFO()
56
57 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchcolumn, 0, 0, 0)
58 ZEND_ARG_INFO(0, column_number)
59 ZEND_END_ARG_INFO()
60
61 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchall, 0, 0, 0)
62 ZEND_ARG_INFO(0, how)
63 ZEND_ARG_INFO(0, class_name)
64 ZEND_ARG_INFO(0, ctor_args) /* array */
65 ZEND_END_ARG_INFO()
66
67 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindvalue, 0, 0, 2)
68 ZEND_ARG_INFO(0, paramno)
69 ZEND_ARG_INFO(0, param)
70 ZEND_ARG_INFO(0, type)
71 ZEND_END_ARG_INFO()
72
73 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindparam, 0, 0, 2)
74 ZEND_ARG_INFO(0, paramno)
75 ZEND_ARG_INFO(1, param)
76 ZEND_ARG_INFO(0, type)
77 ZEND_ARG_INFO(0, maxlen)
78 ZEND_ARG_INFO(0, driverdata)
79 ZEND_END_ARG_INFO()
80
81 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindcolumn, 0, 0, 2)
82 ZEND_ARG_INFO(0, column)
83 ZEND_ARG_INFO(1, param)
84 ZEND_ARG_INFO(0, type)
85 ZEND_ARG_INFO(0, maxlen)
86 ZEND_ARG_INFO(0, driverdata)
87 ZEND_END_ARG_INFO()
88
89 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_setattribute, 0)
90 ZEND_ARG_INFO(0, attribute)
91 ZEND_ARG_INFO(0, value)
92 ZEND_END_ARG_INFO()
93
94 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getattribute, 0)
95 ZEND_ARG_INFO(0, attribute)
96 ZEND_END_ARG_INFO()
97
98 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getcolumnmeta, 0)
99 ZEND_ARG_INFO(0, column)
100 ZEND_END_ARG_INFO()
101
102 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_setfetchmode, 0, 0, 1)
103 ZEND_ARG_INFO(0, mode)
104 ZEND_ARG_INFO(0, params)
105 ZEND_END_ARG_INFO()
106 /* }}} */
107
108 #define PHP_STMT_GET_OBJ \
109 pdo_stmt_t *stmt = Z_PDO_STMT_P(ZEND_THIS); \
110 if (!stmt->dbh) { \
111 RETURN_FALSE; \
112 } \
113
114 static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param) /* {{{ */
115 {
116 if (stmt->bound_param_map) {
117 /* rewriting :name to ? style.
118 * We need to fixup the parameter numbers on the parameters.
119 * If we find that a given named parameter has been used twice,
120 * we will raise an error, as we can't be sure that it is safe
121 * to bind multiple parameters onto the same zval in the underlying
122 * driver */
123 char *name;
124 int position = 0;
125
126 if (stmt->named_rewrite_template) {
127 /* this is not an error here */
128 return 1;
129 }
130 if (!param->name) {
131 /* do the reverse; map the parameter number to the name */
132 if ((name = zend_hash_index_find_ptr(stmt->bound_param_map, param->paramno)) != NULL) {
133 param->name = zend_string_init(name, strlen(name), 0);
134 return 1;
135 }
136 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
137 return 0;
138 }
139
140 ZEND_HASH_FOREACH_PTR(stmt->bound_param_map, name) {
141 if (strncmp(name, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1)) {
142 position++;
143 continue;
144 }
145 if (param->paramno >= 0) {
146 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");
147 return -1;
148 }
149 param->paramno = position;
150 return 1;
151 } ZEND_HASH_FOREACH_END();
152 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
153 return 0;
154 }
155 return 1;
156 }
157 /* }}} */
158
159 /* trigger callback hook for parameters */
dispatch_param_event(pdo_stmt_t * stmt,enum pdo_param_event event_type)160 static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type) /* {{{ */
161 {
162 int ret = 1, is_param = 1;
163 struct pdo_bound_param_data *param;
164 HashTable *ht;
165
166 if (stmt->dbh->skip_param_evt & (1 << event_type)) {
167 return 1;
168 }
169
170 if (!stmt->methods->param_hook) {
171 return 1;
172 }
173
174 ht = stmt->bound_params;
175
176 iterate:
177 if (ht) {
178 ZEND_HASH_FOREACH_PTR(ht, param) {
179 if (!stmt->methods->param_hook(stmt, param, event_type)) {
180 ret = 0;
181 break;
182 }
183 } ZEND_HASH_FOREACH_END();
184 }
185 if (ret && is_param) {
186 ht = stmt->bound_columns;
187 is_param = 0;
188 goto iterate;
189 }
190
191 return ret;
192 }
193 /* }}} */
194
pdo_stmt_describe_columns(pdo_stmt_t * stmt)195 int pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
196 {
197 int col;
198
199 stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
200
201 for (col = 0; col < stmt->column_count; col++) {
202 if (!stmt->methods->describer(stmt, col)) {
203 return 0;
204 }
205
206 /* if we are applying case conversions on column names, do so now */
207 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
208 char *s = ZSTR_VAL(stmt->columns[col].name);
209
210 switch (stmt->dbh->desired_case) {
211 case PDO_CASE_UPPER:
212 while (*s != '\0') {
213 *s = toupper(*s);
214 s++;
215 }
216 break;
217 case PDO_CASE_LOWER:
218 while (*s != '\0') {
219 *s = tolower(*s);
220 s++;
221 }
222 break;
223 default:
224 ;
225 }
226 }
227
228 /* update the column index on named bound parameters */
229 if (stmt->bound_columns) {
230 struct pdo_bound_param_data *param;
231
232 if ((param = zend_hash_find_ptr(stmt->bound_columns,
233 stmt->columns[col].name)) != NULL) {
234 param->paramno = col;
235 }
236 }
237
238 }
239 return 1;
240 }
241 /* }}} */
242
get_lazy_object(pdo_stmt_t * stmt,zval * return_value)243 static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
244 {
245 if (Z_ISUNDEF(stmt->lazy_object_ref)) {
246 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
247 row->stmt = stmt;
248 zend_object_std_init(&row->std, pdo_row_ce);
249 ZVAL_OBJ(&stmt->lazy_object_ref, &row->std);
250 row->std.handlers = &pdo_row_object_handlers;
251 GC_ADDREF(&stmt->std);
252 GC_DELREF(&row->std);
253 }
254 ZVAL_COPY(return_value, &stmt->lazy_object_ref);
255 }
256 /* }}} */
257
param_dtor(zval * el)258 static void param_dtor(zval *el) /* {{{ */
259 {
260 struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)Z_PTR_P(el);
261
262 /* tell the driver that it is going away */
263 if (param->stmt->methods->param_hook) {
264 param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE);
265 }
266
267 if (param->name) {
268 zend_string_release_ex(param->name, 0);
269 }
270
271 if (!Z_ISUNDEF(param->parameter)) {
272 zval_ptr_dtor(¶m->parameter);
273 ZVAL_UNDEF(¶m->parameter);
274 }
275 if (!Z_ISUNDEF(param->driver_params)) {
276 zval_ptr_dtor(¶m->driver_params);
277 }
278 efree(param);
279 }
280 /* }}} */
281
really_register_bound_param(struct pdo_bound_param_data * param,pdo_stmt_t * stmt,int is_param)282 static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param) /* {{{ */
283 {
284 HashTable *hash;
285 zval *parameter;
286 struct pdo_bound_param_data *pparam = NULL;
287
288 hash = is_param ? stmt->bound_params : stmt->bound_columns;
289
290 if (!hash) {
291 ALLOC_HASHTABLE(hash);
292 zend_hash_init(hash, 13, NULL, param_dtor, 0);
293
294 if (is_param) {
295 stmt->bound_params = hash;
296 } else {
297 stmt->bound_columns = hash;
298 }
299 }
300
301 if (!Z_ISREF(param->parameter)) {
302 parameter = ¶m->parameter;
303 } else {
304 parameter = Z_REFVAL(param->parameter);
305 }
306
307 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
308 if (Z_TYPE_P(parameter) == IS_DOUBLE) {
309 char *p;
310 int len = zend_spprintf_unchecked(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(parameter));
311 ZVAL_STRINGL(parameter, p, len);
312 efree(p);
313 } else {
314 if (!try_convert_to_string(parameter)) {
315 return 0;
316 }
317 }
318 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) {
319 convert_to_long(parameter);
320 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(parameter) == IS_LONG) {
321 convert_to_boolean(parameter);
322 }
323
324 param->stmt = stmt;
325 param->is_param = is_param;
326
327 if (Z_REFCOUNTED(param->driver_params)) {
328 Z_ADDREF(param->driver_params);
329 }
330
331 if (!is_param && param->name && stmt->columns) {
332 /* try to map the name to the column */
333 int i;
334
335 for (i = 0; i < stmt->column_count; i++) {
336 if (ZSTR_LEN(stmt->columns[i].name) == ZSTR_LEN(param->name) &&
337 strncmp(ZSTR_VAL(stmt->columns[i].name), ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1) == 0) {
338 param->paramno = i;
339 break;
340 }
341 }
342
343 /* if you prepare and then execute passing an array of params keyed by names,
344 * then this will trigger, and we don't want that */
345 if (param->paramno == -1) {
346 char *tmp;
347 spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
348 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
349 efree(tmp);
350 }
351 }
352
353 if (param->name) {
354 if (is_param && ZSTR_VAL(param->name)[0] != ':') {
355 zend_string *temp = zend_string_alloc(ZSTR_LEN(param->name) + 1, 0);
356 ZSTR_VAL(temp)[0] = ':';
357 memmove(ZSTR_VAL(temp) + 1, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1);
358 param->name = temp;
359 } else {
360 param->name = zend_string_init(ZSTR_VAL(param->name), ZSTR_LEN(param->name), 0);
361 }
362 }
363
364 if (is_param && !rewrite_name_to_position(stmt, param)) {
365 if (param->name) {
366 zend_string_release_ex(param->name, 0);
367 param->name = NULL;
368 }
369 return 0;
370 }
371
372 /* ask the driver to perform any normalization it needs on the
373 * parameter name. Note that it is illegal for the driver to take
374 * a reference to param, as it resides in transient storage only
375 * at this time. */
376 if (stmt->methods->param_hook) {
377 if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE
378 )) {
379 if (param->name) {
380 zend_string_release_ex(param->name, 0);
381 param->name = NULL;
382 }
383 return 0;
384 }
385 }
386
387 /* delete any other parameter registered with this number.
388 * If the parameter is named, it will be removed and correctly
389 * disposed of by the hash_update call that follows */
390 if (param->paramno >= 0) {
391 zend_hash_index_del(hash, param->paramno);
392 }
393
394 /* allocate storage for the parameter, keyed by its "canonical" name */
395 if (param->name) {
396 pparam = zend_hash_update_mem(hash, param->name, param, sizeof(struct pdo_bound_param_data));
397 } else {
398 pparam = zend_hash_index_update_mem(hash, param->paramno, param, sizeof(struct pdo_bound_param_data));
399 }
400
401 /* tell the driver we just created a parameter */
402 if (stmt->methods->param_hook) {
403 if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC
404 )) {
405 /* undo storage allocation; the hash will free the parameter
406 * name if required */
407 if (pparam->name) {
408 zend_hash_del(hash, pparam->name);
409 } else {
410 zend_hash_index_del(hash, pparam->paramno);
411 }
412 /* param->parameter is freed by hash dtor */
413 ZVAL_UNDEF(¶m->parameter);
414 return 0;
415 }
416 }
417 return 1;
418 }
419 /* }}} */
420
421 /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
422 Execute a prepared statement, optionally binding parameters */
PHP_METHOD(PDOStatement,execute)423 static PHP_METHOD(PDOStatement, execute)
424 {
425 zval *input_params = NULL;
426 int ret = 1;
427 PHP_STMT_GET_OBJ;
428
429 ZEND_PARSE_PARAMETERS_START(0, 1)
430 Z_PARAM_OPTIONAL
431 Z_PARAM_ARRAY_EX(input_params, 1, 0)
432 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
433
434 PDO_STMT_CLEAR_ERR();
435
436 if (input_params) {
437 struct pdo_bound_param_data param;
438 zval *tmp;
439 zend_string *key = NULL;
440 zend_ulong num_index;
441
442 if (stmt->bound_params) {
443 zend_hash_destroy(stmt->bound_params);
444 FREE_HASHTABLE(stmt->bound_params);
445 stmt->bound_params = NULL;
446 }
447
448 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) {
449 memset(¶m, 0, sizeof(param));
450
451 if (key) {
452 /* yes this is correct. we don't want to count the null byte. ask wez */
453 param.name = key;
454 param.paramno = -1;
455 } else {
456 /* we're okay to be zero based here */
457 /* num_index is unsignend
458 if (num_index < 0) {
459 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL);
460 RETURN_FALSE;
461 }
462 */
463 param.paramno = num_index;
464 }
465
466 param.param_type = PDO_PARAM_STR;
467 ZVAL_COPY(¶m.parameter, tmp);
468
469 if (!really_register_bound_param(¶m, stmt, 1)) {
470 if (!Z_ISUNDEF(param.parameter)) {
471 zval_ptr_dtor(¶m.parameter);
472 }
473 RETURN_FALSE;
474 }
475 } ZEND_HASH_FOREACH_END();
476 }
477
478 if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
479 /* handle the emulated parameter binding,
480 * stmt->active_query_string holds the query with binds expanded and
481 * quoted.
482 */
483
484 /* string is leftover from previous calls so PDOStatement::debugDumpParams() can access */
485 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
486 efree(stmt->active_query_string);
487 }
488 stmt->active_query_string = NULL;
489
490 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
491 &stmt->active_query_string, &stmt->active_query_stringlen);
492
493 if (ret == 0) {
494 /* no changes were made */
495 stmt->active_query_string = stmt->query_string;
496 stmt->active_query_stringlen = stmt->query_stringlen;
497 ret = 1;
498 } else if (ret == -1) {
499 /* something broke */
500 PDO_HANDLE_STMT_ERR();
501 RETURN_FALSE;
502 }
503 } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE)) {
504 PDO_HANDLE_STMT_ERR();
505 RETURN_FALSE;
506 }
507 if (stmt->methods->executer(stmt)) {
508 if (!stmt->executed) {
509 /* this is the first execute */
510
511 if (stmt->dbh->alloc_own_columns && !stmt->columns) {
512 /* for "big boy" drivers, we need to allocate memory to fetch
513 * the results into, so lets do that now */
514 ret = pdo_stmt_describe_columns(stmt);
515 }
516
517 stmt->executed = 1;
518 }
519
520 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST)) {
521 RETURN_FALSE;
522 }
523
524 RETURN_BOOL(ret);
525 }
526 PDO_HANDLE_STMT_ERR();
527 RETURN_FALSE;
528 }
529 /* }}} */
530
fetch_value(pdo_stmt_t * stmt,zval * dest,int colno,int * type_override)531 static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override) /* {{{ */
532 {
533 struct pdo_column_data *col;
534 char *value = NULL;
535 size_t value_len = 0;
536 int caller_frees = 0;
537 int type, new_type;
538
539 if (colno < 0 || colno >= stmt->column_count) {
540 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
541 ZVAL_FALSE(dest);
542
543 return;
544 }
545
546 col = &stmt->columns[colno];
547 type = PDO_PARAM_TYPE(col->param_type);
548 new_type = type_override ? (int)PDO_PARAM_TYPE(*type_override) : type;
549
550 value = NULL;
551 value_len = 0;
552
553 stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees);
554
555 switch (type) {
556 case PDO_PARAM_ZVAL:
557 if (value && value_len == sizeof(zval)) {
558 ZVAL_COPY_VALUE(dest, (zval *)value);
559 } else {
560 ZVAL_NULL(dest);
561 }
562
563 if (Z_TYPE_P(dest) == IS_NULL) {
564 type = new_type;
565 }
566 break;
567
568 case PDO_PARAM_INT:
569 if (value && value_len == sizeof(zend_long)) {
570 ZVAL_LONG(dest, *(zend_long*)value);
571 break;
572 }
573 ZVAL_NULL(dest);
574 break;
575
576 case PDO_PARAM_BOOL:
577 if (value && value_len == sizeof(zend_bool)) {
578 ZVAL_BOOL(dest, *(zend_bool*)value);
579 break;
580 }
581 ZVAL_NULL(dest);
582 break;
583
584 case PDO_PARAM_LOB:
585 if (value == NULL) {
586 ZVAL_NULL(dest);
587 } else if (value_len == 0) {
588 /* Warning, empty strings need to be passed as stream */
589 if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
590 zend_string *buf;
591 buf = php_stream_copy_to_mem((php_stream*)value, PHP_STREAM_COPY_ALL, 0);
592 if (buf == NULL) {
593 ZVAL_EMPTY_STRING(dest);
594 } else {
595 ZVAL_STR(dest, buf);
596 }
597 php_stream_close((php_stream*)value);
598 } else {
599 php_stream_to_zval((php_stream*)value, dest);
600 }
601 } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
602 /* they gave us a string, but LOBs are represented as streams in PDO */
603 php_stream *stm;
604 #ifdef TEMP_STREAM_TAKE_BUFFER
605 if (caller_frees) {
606 stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
607 if (stm) {
608 caller_frees = 0;
609 }
610 } else
611 #endif
612 {
613 stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
614 }
615 if (stm) {
616 php_stream_to_zval(stm, dest);
617 } else {
618 ZVAL_NULL(dest);
619 }
620 } else {
621 ZVAL_STRINGL(dest, value, value_len);
622 }
623 break;
624
625 case PDO_PARAM_STR:
626 if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
627 ZVAL_STRINGL(dest, value, value_len);
628 break;
629 }
630 default:
631 ZVAL_NULL(dest);
632 }
633
634 if (type != new_type) {
635 switch (new_type) {
636 case PDO_PARAM_INT:
637 convert_to_long_ex(dest);
638 break;
639 case PDO_PARAM_BOOL:
640 convert_to_boolean_ex(dest);
641 break;
642 case PDO_PARAM_STR:
643 convert_to_string_ex(dest);
644 break;
645 case PDO_PARAM_NULL:
646 convert_to_null_ex(dest);
647 break;
648 default:
649 ;
650 }
651 }
652
653 if (caller_frees && value) {
654 efree(value);
655 }
656
657 if (stmt->dbh->stringify) {
658 switch (Z_TYPE_P(dest)) {
659 case IS_LONG:
660 case IS_DOUBLE:
661 convert_to_string(dest);
662 break;
663 }
664 }
665
666 if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
667 ZVAL_EMPTY_STRING(dest);
668 }
669 }
670 /* }}} */
671
do_fetch_common(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,zend_long offset,int do_bind)672 static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset, int do_bind) /* {{{ */
673 {
674 if (!stmt->executed) {
675 return 0;
676 }
677
678 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE)) {
679 return 0;
680 }
681
682 if (!stmt->methods->fetcher(stmt, ori, offset)) {
683 return 0;
684 }
685
686 /* some drivers might need to describe the columns now */
687 if (!stmt->columns && !pdo_stmt_describe_columns(stmt)) {
688 return 0;
689 }
690
691 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST)) {
692 return 0;
693 }
694
695 if (do_bind && stmt->bound_columns) {
696 /* update those bound column variables now */
697 struct pdo_bound_param_data *param;
698
699 ZEND_HASH_FOREACH_PTR(stmt->bound_columns, param) {
700 if (param->paramno >= 0) {
701 if (!Z_ISREF(param->parameter)) {
702 continue;
703 }
704
705 /* delete old value */
706 zval_ptr_dtor(Z_REFVAL(param->parameter));
707
708 /* set new value */
709 fetch_value(stmt, Z_REFVAL(param->parameter), param->paramno, (int *)¶m->param_type);
710
711 /* TODO: some smart thing that avoids duplicating the value in the
712 * general loop below. For now, if you're binding output columns,
713 * it's better to use LAZY or BOUND fetches if you want to shave
714 * off those cycles */
715 }
716 } ZEND_HASH_FOREACH_END();
717 }
718
719 return 1;
720 }
721 /* }}} */
722
do_fetch_class_prepare(pdo_stmt_t * stmt)723 static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
724 {
725 zend_class_entry *ce = stmt->fetch.cls.ce;
726 zend_fcall_info *fci = &stmt->fetch.cls.fci;
727 zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
728
729 fci->size = sizeof(zend_fcall_info);
730
731 if (!ce) {
732 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
733 ce = ZEND_STANDARD_CLASS_DEF_PTR;
734 }
735
736 if (ce->constructor) {
737 ZVAL_UNDEF(&fci->function_name);
738 fci->retval = &stmt->fetch.cls.retval;
739 fci->param_count = 0;
740 fci->params = NULL;
741 fci->no_separation = 1;
742
743 zend_fcall_info_args_ex(fci, ce->constructor, &stmt->fetch.cls.ctor_args);
744
745 fcc->function_handler = ce->constructor;
746 fcc->called_scope = ce;
747 return 1;
748 } else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
749 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not have a constructor, use NULL for the ctor_params parameter, or simply omit it");
750 return 0;
751 } else {
752 return 1; /* no ctor no args is also ok */
753 }
754 }
755 /* }}} */
756
make_callable_ex(pdo_stmt_t * stmt,zval * callable,zend_fcall_info * fci,zend_fcall_info_cache * fcc,int num_args)757 static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args) /* {{{ */
758 {
759 char *is_callable_error = NULL;
760
761 if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error) == FAILURE) {
762 if (is_callable_error) {
763 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error);
764 efree(is_callable_error);
765 } else {
766 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback");
767 }
768 return 0;
769 }
770 if (is_callable_error) {
771 /* Possible error message */
772 efree(is_callable_error);
773 }
774
775 fci->param_count = num_args; /* probably less */
776 fci->params = safe_emalloc(sizeof(zval), num_args, 0);
777
778 return 1;
779 }
780 /* }}} */
781
do_fetch_func_prepare(pdo_stmt_t * stmt)782 static int do_fetch_func_prepare(pdo_stmt_t *stmt) /* {{{ */
783 {
784 zend_fcall_info *fci = &stmt->fetch.cls.fci;
785 zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
786
787 if (!make_callable_ex(stmt, &stmt->fetch.func.function, fci, fcc, stmt->column_count)) {
788 return 0;
789 } else {
790 stmt->fetch.func.values = safe_emalloc(sizeof(zval), stmt->column_count, 0);
791 return 1;
792 }
793 }
794 /* }}} */
795
do_fetch_opt_finish(pdo_stmt_t * stmt,int free_ctor_agrs)796 static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
797 {
798 /* fci.size is used to check if it is valid */
799 if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
800 if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
801 /* Added to free constructor arguments */
802 zend_fcall_info_args_clear(&stmt->fetch.cls.fci, 1);
803 } else {
804 efree(stmt->fetch.cls.fci.params);
805 }
806 stmt->fetch.cls.fci.params = NULL;
807 }
808
809 stmt->fetch.cls.fci.size = 0;
810 if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args) && free_ctor_agrs) {
811 zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
812 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
813 stmt->fetch.cls.fci.param_count = 0;
814 }
815 if (stmt->fetch.func.values) {
816 efree(stmt->fetch.func.values);
817 stmt->fetch.func.values = NULL;
818 }
819 }
820 /* }}} */
821
822 /* perform a fetch. If do_bind is true, update any bound columns.
823 * If return_value is not null, store values into it according to HOW. */
do_fetch(pdo_stmt_t * stmt,int do_bind,zval * return_value,enum pdo_fetch_type how,enum pdo_fetch_orientation ori,zend_long offset,zval * return_all)824 static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value, enum pdo_fetch_type how, enum pdo_fetch_orientation ori, zend_long offset, zval *return_all) /* {{{ */
825 {
826 int flags, idx, old_arg_count = 0;
827 zend_class_entry *ce = NULL, *old_ce = NULL;
828 zval grp_val, *pgrp, retval, old_ctor_args = {{0}};
829 int colno;
830
831 if (how == PDO_FETCH_USE_DEFAULT) {
832 how = stmt->default_fetch_type;
833 }
834 flags = how & PDO_FETCH_FLAGS;
835 how = how & ~PDO_FETCH_FLAGS;
836
837 if (!do_fetch_common(stmt, ori, offset, do_bind)) {
838 return 0;
839 }
840
841 if (how == PDO_FETCH_BOUND) {
842 RETVAL_TRUE;
843 return 1;
844 }
845
846 if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
847 colno = 1;
848 } else {
849 colno = stmt->fetch.column;
850 }
851
852 if (return_value) {
853 int i = 0;
854
855 if (how == PDO_FETCH_LAZY) {
856 get_lazy_object(stmt, return_value);
857 return 1;
858 }
859
860 RETVAL_FALSE;
861
862 switch (how) {
863 case PDO_FETCH_USE_DEFAULT:
864 case PDO_FETCH_ASSOC:
865 case PDO_FETCH_BOTH:
866 case PDO_FETCH_NUM:
867 case PDO_FETCH_NAMED:
868 if (!return_all) {
869 array_init_size(return_value, stmt->column_count);
870 } else {
871 array_init(return_value);
872 }
873 break;
874
875 case PDO_FETCH_KEY_PAIR:
876 if (stmt->column_count != 2) {
877 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain extactly 2 columns.");
878 return 0;
879 }
880 if (!return_all) {
881 array_init(return_value);
882 }
883 break;
884
885 case PDO_FETCH_COLUMN:
886 if (colno >= 0 && colno < stmt->column_count) {
887 if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
888 fetch_value(stmt, return_value, 1, NULL);
889 } else if (flags == PDO_FETCH_GROUP && colno) {
890 fetch_value(stmt, return_value, 0, NULL);
891 } else {
892 fetch_value(stmt, return_value, colno, NULL);
893 }
894 if (!return_all) {
895 return 1;
896 } else {
897 break;
898 }
899 } else {
900 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
901 }
902 return 0;
903
904 case PDO_FETCH_OBJ:
905 object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
906 break;
907
908 case PDO_FETCH_CLASS:
909 if (flags & PDO_FETCH_CLASSTYPE) {
910 zval val;
911 zend_class_entry *cep;
912
913 old_ce = stmt->fetch.cls.ce;
914 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
915 old_arg_count = stmt->fetch.cls.fci.param_count;
916 do_fetch_opt_finish(stmt, 0);
917
918 fetch_value(stmt, &val, i++, NULL);
919 if (Z_TYPE(val) != IS_NULL) {
920 if (!try_convert_to_string(&val)) {
921 return 0;
922 }
923 if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
924 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
925 } else {
926 stmt->fetch.cls.ce = cep;
927 }
928 }
929
930 do_fetch_class_prepare(stmt);
931 zval_ptr_dtor_str(&val);
932 }
933 ce = stmt->fetch.cls.ce;
934 if (!ce) {
935 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
936 return 0;
937 }
938 if ((flags & PDO_FETCH_SERIALIZE) == 0) {
939 if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
940 return 0;
941 }
942 if (!stmt->fetch.cls.fci.size) {
943 if (!do_fetch_class_prepare(stmt))
944 {
945 return 0;
946 }
947 }
948 if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
949 stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
950 stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
951 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
952 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
953 return 0;
954 } else {
955 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
956 zval_ptr_dtor(&stmt->fetch.cls.retval);
957 ZVAL_UNDEF(&stmt->fetch.cls.retval);
958 }
959 }
960 }
961 }
962 break;
963
964 case PDO_FETCH_INTO:
965 if (Z_ISUNDEF(stmt->fetch.into)) {
966 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
967 return 0;
968 break;
969 }
970
971 ZVAL_COPY(return_value, &stmt->fetch.into);
972
973 if (Z_OBJ_P(return_value)->ce == ZEND_STANDARD_CLASS_DEF_PTR) {
974 how = PDO_FETCH_OBJ;
975 }
976 break;
977
978 case PDO_FETCH_FUNC:
979 if (Z_ISUNDEF(stmt->fetch.func.function)) {
980 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
981 return 0;
982 }
983 if (!stmt->fetch.func.fci.size) {
984 if (!do_fetch_func_prepare(stmt))
985 {
986 return 0;
987 }
988 }
989 break;
990
991
992 default:
993 /* shouldn't happen */
994 return 0;
995 }
996
997 if (return_all && how != PDO_FETCH_KEY_PAIR) {
998 if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
999 fetch_value(stmt, &grp_val, colno, NULL);
1000 } else {
1001 fetch_value(stmt, &grp_val, i, NULL);
1002 }
1003 convert_to_string(&grp_val);
1004 if (how == PDO_FETCH_COLUMN) {
1005 i = stmt->column_count; /* no more data to fetch */
1006 } else {
1007 i++;
1008 }
1009 }
1010
1011 for (idx = 0; i < stmt->column_count; i++, idx++) {
1012 zval val;
1013 fetch_value(stmt, &val, i, NULL);
1014
1015 switch (how) {
1016 case PDO_FETCH_ASSOC:
1017 zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
1018 break;
1019
1020 case PDO_FETCH_KEY_PAIR:
1021 {
1022 zval tmp;
1023 fetch_value(stmt, &tmp, ++i, NULL);
1024
1025 if (Z_TYPE(val) == IS_LONG) {
1026 zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL(val), &tmp);
1027 } else {
1028 convert_to_string(&val);
1029 zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STR(val), &tmp);
1030 }
1031 zval_ptr_dtor(&val);
1032 return 1;
1033 }
1034 break;
1035
1036 case PDO_FETCH_USE_DEFAULT:
1037 case PDO_FETCH_BOTH:
1038 zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
1039 if (Z_REFCOUNTED(val)) {
1040 Z_ADDREF(val);
1041 }
1042 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val);
1043 break;
1044
1045 case PDO_FETCH_NAMED:
1046 /* already have an item with this name? */
1047 {
1048 zval *curr_val;
1049 if ((curr_val = zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name))) {
1050 zval arr;
1051 if (Z_TYPE_P(curr_val) != IS_ARRAY) {
1052 /* a little bit of black magic here:
1053 * we're creating a new array and swapping it for the
1054 * zval that's already stored in the hash under the name
1055 * we want. We then add that zval to the array.
1056 * This is effectively the same thing as:
1057 * if (!is_array($hash[$name])) {
1058 * $hash[$name] = array($hash[$name]);
1059 * }
1060 * */
1061 zval cur;
1062
1063 array_init(&arr);
1064
1065 ZVAL_COPY_VALUE(&cur, curr_val);
1066 ZVAL_COPY_VALUE(curr_val, &arr);
1067
1068 zend_hash_next_index_insert_new(Z_ARRVAL(arr), &cur);
1069 } else {
1070 ZVAL_COPY_VALUE(&arr, curr_val);
1071 }
1072 zend_hash_next_index_insert_new(Z_ARRVAL(arr), &val);
1073 } else {
1074 zend_hash_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
1075 }
1076 }
1077 break;
1078
1079 case PDO_FETCH_NUM:
1080 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &val);
1081 break;
1082
1083 case PDO_FETCH_OBJ:
1084 case PDO_FETCH_INTO:
1085 zend_update_property_ex(NULL, return_value,
1086 stmt->columns[i].name,
1087 &val);
1088 zval_ptr_dtor(&val);
1089 break;
1090
1091 case PDO_FETCH_CLASS:
1092 if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
1093 zend_update_property_ex(ce, return_value,
1094 stmt->columns[i].name,
1095 &val);
1096 zval_ptr_dtor(&val);
1097 } else {
1098 if (!ce->unserialize) {
1099 zval_ptr_dtor(&val);
1100 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
1101 return 0;
1102 } 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) {
1103 zval_ptr_dtor(&val);
1104 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
1105 zval_ptr_dtor(return_value);
1106 ZVAL_NULL(return_value);
1107 return 0;
1108 } else {
1109 zval_ptr_dtor(&val);
1110 }
1111 }
1112 break;
1113
1114 case PDO_FETCH_FUNC:
1115 ZVAL_COPY_VALUE(&stmt->fetch.func.values[idx], &val);
1116 ZVAL_COPY_VALUE(&stmt->fetch.cls.fci.params[idx], &stmt->fetch.func.values[idx]);
1117 break;
1118
1119 default:
1120 zval_ptr_dtor(&val);
1121 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range");
1122 return 0;
1123 break;
1124 }
1125 }
1126
1127 switch (how) {
1128 case PDO_FETCH_CLASS:
1129 if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
1130 stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
1131 stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
1132 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
1133 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
1134 return 0;
1135 } else {
1136 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
1137 zval_ptr_dtor(&stmt->fetch.cls.retval);
1138 }
1139 }
1140 }
1141 if (flags & PDO_FETCH_CLASSTYPE) {
1142 do_fetch_opt_finish(stmt, 0);
1143 stmt->fetch.cls.ce = old_ce;
1144 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1145 stmt->fetch.cls.fci.param_count = old_arg_count;
1146 }
1147 break;
1148
1149 case PDO_FETCH_FUNC:
1150 stmt->fetch.func.fci.param_count = idx;
1151 stmt->fetch.func.fci.retval = &retval;
1152 if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc) == FAILURE) {
1153 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
1154 return 0;
1155 } else {
1156 if (return_all) {
1157 zval_ptr_dtor(return_value); /* we don't need that */
1158 ZVAL_COPY_VALUE(return_value, &retval);
1159 } else if (!Z_ISUNDEF(retval)) {
1160 ZVAL_COPY_VALUE(return_value, &retval);
1161 }
1162 }
1163 while (idx--) {
1164 zval_ptr_dtor(&stmt->fetch.func.values[idx]);
1165 }
1166 break;
1167
1168 default:
1169 break;
1170 }
1171
1172 if (return_all) {
1173 if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
1174 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), return_value);
1175 } else {
1176 zval grp;
1177 if ((pgrp = zend_symtable_find(Z_ARRVAL_P(return_all), Z_STR(grp_val))) == NULL) {
1178 array_init(&grp);
1179 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), &grp);
1180 } else {
1181 ZVAL_COPY_VALUE(&grp, pgrp);
1182 }
1183 zend_hash_next_index_insert(Z_ARRVAL(grp), return_value);
1184 }
1185 zval_ptr_dtor_str(&grp_val);
1186 }
1187
1188 }
1189
1190 return 1;
1191 }
1192 /* }}} */
1193
pdo_stmt_verify_mode(pdo_stmt_t * stmt,zend_long mode,int fetch_all)1194 static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all) /* {{{ */
1195 {
1196 int flags = mode & PDO_FETCH_FLAGS;
1197
1198 mode = mode & ~PDO_FETCH_FLAGS;
1199
1200 if (mode < 0 || mode > PDO_FETCH__MAX) {
1201 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
1202 return 0;
1203 }
1204
1205 if (mode == PDO_FETCH_USE_DEFAULT) {
1206 flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
1207 mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1208 }
1209
1210 switch(mode) {
1211 case PDO_FETCH_FUNC:
1212 if (!fetch_all) {
1213 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()");
1214 return 0;
1215 }
1216 return 1;
1217
1218 case PDO_FETCH_LAZY:
1219 if (fetch_all) {
1220 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()");
1221 return 0;
1222 }
1223 /* fall through */
1224 default:
1225 if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1226 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS");
1227 return 0;
1228 }
1229 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1230 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS");
1231 return 0;
1232 }
1233 if (mode >= PDO_FETCH__MAX) {
1234 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
1235 return 0;
1236 }
1237 /* no break; */
1238
1239 case PDO_FETCH_CLASS:
1240 return 1;
1241 }
1242 }
1243 /* }}} */
1244
1245 /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
1246 Fetches the next row and returns it, or false if there are no more rows */
PHP_METHOD(PDOStatement,fetch)1247 static PHP_METHOD(PDOStatement, fetch)
1248 {
1249 zend_long how = PDO_FETCH_USE_DEFAULT;
1250 zend_long ori = PDO_FETCH_ORI_NEXT;
1251 zend_long off = 0;
1252 PHP_STMT_GET_OBJ;
1253
1254 ZEND_PARSE_PARAMETERS_START(0, 3)
1255 Z_PARAM_OPTIONAL
1256 Z_PARAM_LONG(how)
1257 Z_PARAM_LONG(ori)
1258 Z_PARAM_LONG(off)
1259 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1260
1261 PDO_STMT_CLEAR_ERR();
1262
1263 if (!pdo_stmt_verify_mode(stmt, how, 0)) {
1264 RETURN_FALSE;
1265 }
1266
1267 if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
1268 PDO_HANDLE_STMT_ERR();
1269 RETURN_FALSE;
1270 }
1271 }
1272 /* }}} */
1273
1274 /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
1275 Fetches the next row and returns it as an object. */
PHP_METHOD(PDOStatement,fetchObject)1276 static PHP_METHOD(PDOStatement, fetchObject)
1277 {
1278 zend_long how = PDO_FETCH_CLASS;
1279 zend_long ori = PDO_FETCH_ORI_NEXT;
1280 zend_long off = 0;
1281 zend_string *class_name = NULL;
1282 zend_class_entry *old_ce;
1283 zval old_ctor_args, *ctor_args = NULL;
1284 int error = 0, old_arg_count;
1285
1286 PHP_STMT_GET_OBJ;
1287
1288 ZEND_PARSE_PARAMETERS_START(0, 2)
1289 Z_PARAM_OPTIONAL
1290 Z_PARAM_STR_EX(class_name, 1, 0)
1291 Z_PARAM_ARRAY(ctor_args)
1292 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1293
1294 PDO_STMT_CLEAR_ERR();
1295
1296 if (!pdo_stmt_verify_mode(stmt, how, 0)) {
1297 RETURN_FALSE;
1298 }
1299
1300 old_ce = stmt->fetch.cls.ce;
1301 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
1302 old_arg_count = stmt->fetch.cls.fci.param_count;
1303
1304 do_fetch_opt_finish(stmt, 0);
1305
1306 if (ctor_args) {
1307 if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1308 ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL_P(ctor_args)));
1309 } else {
1310 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
1311 }
1312 }
1313 if (class_name && !error) {
1314 stmt->fetch.cls.ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
1315
1316 if (!stmt->fetch.cls.ce) {
1317 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class");
1318 error = 1;
1319 }
1320 } else if (!error) {
1321 stmt->fetch.cls.ce = zend_standard_class_def;
1322 }
1323
1324 if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
1325 error = 1;
1326 }
1327 if (error) {
1328 PDO_HANDLE_STMT_ERR();
1329 }
1330 do_fetch_opt_finish(stmt, 1);
1331
1332 stmt->fetch.cls.ce = old_ce;
1333 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1334 stmt->fetch.cls.fci.param_count = old_arg_count;
1335 if (error) {
1336 RETURN_FALSE;
1337 }
1338 }
1339 /* }}} */
1340
1341 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1342 Returns a data of the specified column in the result set. */
PHP_METHOD(PDOStatement,fetchColumn)1343 static PHP_METHOD(PDOStatement, fetchColumn)
1344 {
1345 zend_long col_n = 0;
1346 PHP_STMT_GET_OBJ;
1347
1348 ZEND_PARSE_PARAMETERS_START(0, 1)
1349 Z_PARAM_OPTIONAL
1350 Z_PARAM_LONG(col_n)
1351 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1352
1353 PDO_STMT_CLEAR_ERR();
1354
1355 if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE)) {
1356 PDO_HANDLE_STMT_ERR();
1357 RETURN_FALSE;
1358 }
1359
1360 fetch_value(stmt, return_value, col_n, NULL);
1361 }
1362 /* }}} */
1363
1364 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1365 Returns an array of all of the results. */
PHP_METHOD(PDOStatement,fetchAll)1366 static PHP_METHOD(PDOStatement, fetchAll)
1367 {
1368 zend_long how = PDO_FETCH_USE_DEFAULT;
1369 zval data, *return_all;
1370 zval *arg2 = NULL;
1371 zend_class_entry *old_ce;
1372 zval old_ctor_args, *ctor_args = NULL;
1373 int error = 0, flags, old_arg_count;
1374 PHP_STMT_GET_OBJ;
1375
1376 ZEND_PARSE_PARAMETERS_START(0, 3)
1377 Z_PARAM_OPTIONAL
1378 Z_PARAM_LONG(how)
1379 Z_PARAM_ZVAL(arg2)
1380 Z_PARAM_ZVAL(ctor_args)
1381 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1382
1383 if (!pdo_stmt_verify_mode(stmt, how, 1)) {
1384 RETURN_FALSE;
1385 }
1386
1387 old_ce = stmt->fetch.cls.ce;
1388 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
1389 old_arg_count = stmt->fetch.cls.fci.param_count;
1390
1391 do_fetch_opt_finish(stmt, 0);
1392
1393 switch(how & ~PDO_FETCH_FLAGS) {
1394 case PDO_FETCH_CLASS:
1395 switch(ZEND_NUM_ARGS()) {
1396 case 0:
1397 case 1:
1398 stmt->fetch.cls.ce = zend_standard_class_def;
1399 break;
1400 case 3:
1401 if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1402 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
1403 error = 1;
1404 break;
1405 }
1406 if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1407 ctor_args = NULL;
1408 }
1409 /* no break */
1410 case 2:
1411 if (ctor_args) {
1412 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, ctor_args); /* we're not going to free these */
1413 } else {
1414 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
1415 }
1416 if (Z_TYPE_P(arg2) != IS_STRING) {
1417 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)");
1418 error = 1;
1419 break;
1420 } else {
1421 stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO);
1422 if (!stmt->fetch.cls.ce) {
1423 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class");
1424 error = 1;
1425 break;
1426 }
1427 }
1428 }
1429 if (!error) {
1430 do_fetch_class_prepare(stmt);
1431 }
1432 break;
1433
1434 case PDO_FETCH_FUNC:
1435 switch (ZEND_NUM_ARGS()) {
1436 case 0:
1437 case 1:
1438 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified");
1439 error = 1;
1440 break;
1441 case 3:
1442 case 2:
1443 ZVAL_COPY_VALUE(&stmt->fetch.func.function, arg2);
1444 if (do_fetch_func_prepare(stmt) == 0) {
1445 error = 1;
1446 }
1447 break;
1448 }
1449 break;
1450
1451 case PDO_FETCH_COLUMN:
1452 switch(ZEND_NUM_ARGS()) {
1453 case 0:
1454 case 1:
1455 stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1456 break;
1457 case 2:
1458 convert_to_long(arg2);
1459 stmt->fetch.column = Z_LVAL_P(arg2);
1460 break;
1461 case 3:
1462 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN");
1463 error = 1;
1464 }
1465 break;
1466
1467 default:
1468 if (ZEND_NUM_ARGS() > 1) {
1469 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters");
1470 error = 1;
1471 }
1472 }
1473
1474 flags = how & PDO_FETCH_FLAGS;
1475
1476 if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1477 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1478 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1479 }
1480
1481 if (!error) {
1482 PDO_STMT_CLEAR_ERR();
1483 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1484 (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1485 ) {
1486 array_init(return_value);
1487 return_all = return_value;
1488 } else {
1489 return_all = 0;
1490 }
1491 if (!do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all)) {
1492 error = 2;
1493 }
1494 }
1495 if (!error) {
1496 if ((how & PDO_FETCH_GROUP)) {
1497 while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
1498 } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1499 while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
1500 } else {
1501 array_init(return_value);
1502 do {
1503 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &data);
1504 } while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0));
1505 }
1506 }
1507
1508 do_fetch_opt_finish(stmt, 0);
1509
1510 stmt->fetch.cls.ce = old_ce;
1511 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1512 stmt->fetch.cls.fci.param_count = old_arg_count;
1513
1514 if (error) {
1515 PDO_HANDLE_STMT_ERR();
1516 if (error != 2) {
1517 RETURN_FALSE;
1518 } else { /* on no results, return an empty array */
1519 if (Z_TYPE_P(return_value) != IS_ARRAY) {
1520 array_init(return_value);
1521 }
1522 return;
1523 }
1524 }
1525 }
1526 /* }}} */
1527
register_bound_param(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int is_param)1528 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1529 {
1530 struct pdo_bound_param_data param;
1531 zend_long param_type = PDO_PARAM_STR;
1532 zval *parameter, *driver_params = NULL;
1533
1534 memset(¶m, 0, sizeof(param));
1535 param.paramno = -1;
1536
1537 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
1538 "lz|llz!", ¶m.paramno, ¶meter, ¶m_type, ¶m.max_value_len,
1539 &driver_params)) {
1540 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|llz!", ¶m.name,
1541 ¶meter, ¶m_type, ¶m.max_value_len,
1542 &driver_params)) {
1543 return 0;
1544 }
1545 }
1546
1547 param.param_type = (int) param_type;
1548
1549 if (param.paramno > 0) {
1550 --param.paramno; /* make it zero-based internally */
1551 } else if (!param.name) {
1552 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
1553 return 0;
1554 }
1555
1556 if (driver_params) {
1557 ZVAL_COPY(¶m.driver_params, driver_params);
1558 }
1559
1560 ZVAL_COPY(¶m.parameter, parameter);
1561 if (!really_register_bound_param(¶m, stmt, is_param)) {
1562 if (!Z_ISUNDEF(param.parameter)) {
1563 zval_ptr_dtor(&(param.parameter));
1564 }
1565 return 0;
1566 }
1567 return 1;
1568 } /* }}} */
1569
1570 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1571 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(). */
PHP_METHOD(PDOStatement,bindValue)1572 static PHP_METHOD(PDOStatement, bindValue)
1573 {
1574 struct pdo_bound_param_data param;
1575 zend_long param_type = PDO_PARAM_STR;
1576 zval *parameter;
1577 PHP_STMT_GET_OBJ;
1578
1579 memset(¶m, 0, sizeof(param));
1580 param.paramno = -1;
1581
1582 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
1583 "lz|l", ¶m.paramno, ¶meter, ¶m_type)) {
1584 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|l", ¶m.name,
1585 ¶meter, ¶m_type)) {
1586 RETURN_FALSE;
1587 }
1588 }
1589
1590 param.param_type = (int) param_type;
1591
1592 if (param.paramno > 0) {
1593 --param.paramno; /* make it zero-based internally */
1594 } else if (!param.name) {
1595 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
1596 RETURN_FALSE;
1597 }
1598
1599 ZVAL_COPY(¶m.parameter, parameter);
1600 if (!really_register_bound_param(¶m, stmt, TRUE)) {
1601 if (!Z_ISUNDEF(param.parameter)) {
1602 zval_ptr_dtor(&(param.parameter));
1603 ZVAL_UNDEF(¶m.parameter);
1604 }
1605 RETURN_FALSE;
1606 }
1607 RETURN_TRUE;
1608 }
1609 /* }}} */
1610
1611 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1612 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(). */
PHP_METHOD(PDOStatement,bindParam)1613 static PHP_METHOD(PDOStatement, bindParam)
1614 {
1615 PHP_STMT_GET_OBJ;
1616 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1617 }
1618 /* }}} */
1619
1620 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1621 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(). */
PHP_METHOD(PDOStatement,bindColumn)1622 static PHP_METHOD(PDOStatement, bindColumn)
1623 {
1624 PHP_STMT_GET_OBJ;
1625 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 0));
1626 }
1627 /* }}} */
1628
1629 /* {{{ proto int PDOStatement::rowCount()
1630 Returns the number of rows in a result set, or the number of rows affected by the last execute(). It is not always meaningful. */
PHP_METHOD(PDOStatement,rowCount)1631 static PHP_METHOD(PDOStatement, rowCount)
1632 {
1633 PHP_STMT_GET_OBJ;
1634
1635 RETURN_LONG(stmt->row_count);
1636 }
1637 /* }}} */
1638
1639 /* {{{ proto string PDOStatement::errorCode()
1640 Fetch the error code associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorCode)1641 static PHP_METHOD(PDOStatement, errorCode)
1642 {
1643 PHP_STMT_GET_OBJ;
1644
1645 if (zend_parse_parameters_none() == FAILURE) {
1646 return;
1647 }
1648
1649 if (stmt->error_code[0] == '\0') {
1650 RETURN_NULL();
1651 }
1652
1653 RETURN_STRING(stmt->error_code);
1654 }
1655 /* }}} */
1656
1657 /* {{{ proto array PDOStatement::errorInfo()
1658 Fetch extended error information associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorInfo)1659 static PHP_METHOD(PDOStatement, errorInfo)
1660 {
1661 int error_count;
1662 int error_count_diff = 0;
1663 int error_expected_count = 3;
1664
1665 PHP_STMT_GET_OBJ;
1666
1667 if (zend_parse_parameters_none() == FAILURE) {
1668 return;
1669 }
1670
1671 array_init(return_value);
1672 add_next_index_string(return_value, stmt->error_code);
1673
1674 if (stmt->dbh->methods->fetch_err) {
1675 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value);
1676 }
1677
1678 error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1679
1680 if (error_expected_count > error_count) {
1681 int current_index;
1682
1683 error_count_diff = error_expected_count - error_count;
1684 for (current_index = 0; current_index < error_count_diff; current_index++) {
1685 add_next_index_null(return_value);
1686 }
1687 }
1688 }
1689 /* }}} */
1690
1691 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1692 Set an attribute */
PHP_METHOD(PDOStatement,setAttribute)1693 static PHP_METHOD(PDOStatement, setAttribute)
1694 {
1695 zend_long attr;
1696 zval *value = NULL;
1697 PHP_STMT_GET_OBJ;
1698
1699 ZEND_PARSE_PARAMETERS_START(2, 2)
1700 Z_PARAM_LONG(attr)
1701 Z_PARAM_ZVAL_EX(value, 1, 0)
1702 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1703
1704 if (!stmt->methods->set_attribute) {
1705 goto fail;
1706 }
1707
1708 PDO_STMT_CLEAR_ERR();
1709 if (stmt->methods->set_attribute(stmt, attr, value)) {
1710 RETURN_TRUE;
1711 }
1712
1713 fail:
1714 if (!stmt->methods->set_attribute) {
1715 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes");
1716 } else {
1717 PDO_HANDLE_STMT_ERR();
1718 }
1719 RETURN_FALSE;
1720 }
1721 /* }}} */
1722
1723 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1724 Get an attribute */
1725
generic_stmt_attr_get(pdo_stmt_t * stmt,zval * return_value,zend_long attr)1726 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, zend_long attr)
1727 {
1728 switch (attr) {
1729 case PDO_ATTR_EMULATE_PREPARES:
1730 RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1731 return 1;
1732 }
1733 return 0;
1734 }
1735
PHP_METHOD(PDOStatement,getAttribute)1736 static PHP_METHOD(PDOStatement, getAttribute)
1737 {
1738 zend_long attr;
1739 PHP_STMT_GET_OBJ;
1740
1741 ZEND_PARSE_PARAMETERS_START(1, 1)
1742 Z_PARAM_LONG(attr)
1743 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1744
1745 if (!stmt->methods->get_attribute) {
1746 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1747 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1748 "This driver doesn't support getting attributes");
1749 RETURN_FALSE;
1750 }
1751 return;
1752 }
1753
1754 PDO_STMT_CLEAR_ERR();
1755 switch (stmt->methods->get_attribute(stmt, attr, return_value)) {
1756 case -1:
1757 PDO_HANDLE_STMT_ERR();
1758 RETURN_FALSE;
1759
1760 case 0:
1761 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1762 /* XXX: should do something better here */
1763 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1764 "driver doesn't support getting that attribute");
1765 RETURN_FALSE;
1766 }
1767 return;
1768
1769 default:
1770 return;
1771 }
1772 }
1773 /* }}} */
1774
1775 /* {{{ proto int PDOStatement::columnCount()
1776 Returns the number of columns in the result set */
PHP_METHOD(PDOStatement,columnCount)1777 static PHP_METHOD(PDOStatement, columnCount)
1778 {
1779 PHP_STMT_GET_OBJ;
1780 if (zend_parse_parameters_none() == FAILURE) {
1781 return;
1782 }
1783 RETURN_LONG(stmt->column_count);
1784 }
1785 /* }}} */
1786
1787 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1788 Returns meta data for a numbered column */
PHP_METHOD(PDOStatement,getColumnMeta)1789 static PHP_METHOD(PDOStatement, getColumnMeta)
1790 {
1791 zend_long colno;
1792 struct pdo_column_data *col;
1793 PHP_STMT_GET_OBJ;
1794
1795 ZEND_PARSE_PARAMETERS_START(1, 1)
1796 Z_PARAM_LONG(colno)
1797 ZEND_PARSE_PARAMETERS_END_EX(RETURN_FALSE);
1798
1799 if(colno < 0) {
1800 pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative");
1801 RETURN_FALSE;
1802 }
1803
1804 if (!stmt->methods->get_column_meta) {
1805 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data");
1806 RETURN_FALSE;
1807 }
1808
1809 PDO_STMT_CLEAR_ERR();
1810 if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value)) {
1811 PDO_HANDLE_STMT_ERR();
1812 RETURN_FALSE;
1813 }
1814
1815 /* add stock items */
1816 col = &stmt->columns[colno];
1817 add_assoc_str(return_value, "name", zend_string_copy(col->name));
1818 add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1819 add_assoc_long(return_value, "precision", col->precision);
1820 if (col->param_type != PDO_PARAM_ZVAL) {
1821 /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1822 add_assoc_long(return_value, "pdo_type", col->param_type);
1823 }
1824 }
1825 /* }}} */
1826
1827 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1828 Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1829
pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int skip)1830 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1831 {
1832 zend_long mode = PDO_FETCH_BOTH;
1833 int flags = 0, argc = ZEND_NUM_ARGS() - skip;
1834 zval *args;
1835 zend_class_entry *cep;
1836 int retval;
1837
1838 do_fetch_opt_finish(stmt, 1);
1839
1840 switch (stmt->default_fetch_type) {
1841 case PDO_FETCH_INTO:
1842 if (!Z_ISUNDEF(stmt->fetch.into)) {
1843 zval_ptr_dtor(&stmt->fetch.into);
1844 ZVAL_UNDEF(&stmt->fetch.into);
1845 }
1846 break;
1847 default:
1848 ;
1849 }
1850
1851 stmt->default_fetch_type = PDO_FETCH_BOTH;
1852
1853 if (argc == 0) {
1854 return SUCCESS;
1855 }
1856
1857 args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
1858
1859 retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1860
1861 if (SUCCESS == retval) {
1862 if (Z_TYPE(args[skip]) != IS_LONG) {
1863 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer");
1864 retval = FAILURE;
1865 } else {
1866 mode = Z_LVAL(args[skip]);
1867 flags = mode & PDO_FETCH_FLAGS;
1868
1869 /* pdo_stmt_verify_mode() returns a boolean value */
1870 retval = pdo_stmt_verify_mode(stmt, mode, 0) ? SUCCESS : FAILURE;
1871 }
1872 }
1873
1874 if (FAILURE == retval) {
1875 PDO_STMT_CLEAR_ERR();
1876 efree(args);
1877 return FAILURE;
1878 }
1879
1880 retval = FAILURE;
1881 switch (mode & ~PDO_FETCH_FLAGS) {
1882 case PDO_FETCH_USE_DEFAULT:
1883 case PDO_FETCH_LAZY:
1884 case PDO_FETCH_ASSOC:
1885 case PDO_FETCH_NUM:
1886 case PDO_FETCH_BOTH:
1887 case PDO_FETCH_OBJ:
1888 case PDO_FETCH_BOUND:
1889 case PDO_FETCH_NAMED:
1890 case PDO_FETCH_KEY_PAIR:
1891 if (argc != 1) {
1892 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
1893 } else {
1894 retval = SUCCESS;
1895 }
1896 break;
1897
1898 case PDO_FETCH_COLUMN:
1899 if (argc != 2) {
1900 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument");
1901 } else if (Z_TYPE(args[skip+1]) != IS_LONG) {
1902 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer");
1903 } else {
1904 stmt->fetch.column = Z_LVAL(args[skip+1]);
1905 retval = SUCCESS;
1906 }
1907 break;
1908
1909 case PDO_FETCH_CLASS:
1910 /* Gets its class name from 1st column */
1911 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1912 if (argc != 1) {
1913 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments");
1914 } else {
1915 stmt->fetch.cls.ce = NULL;
1916 retval = SUCCESS;
1917 }
1918 } else {
1919 if (argc < 2) {
1920 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument");
1921 } else if (argc > 3) {
1922 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments");
1923 } else if (Z_TYPE(args[skip+1]) != IS_STRING) {
1924 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string");
1925 } else {
1926 cep = zend_lookup_class(Z_STR(args[skip+1]));
1927 if (cep) {
1928 retval = SUCCESS;
1929 stmt->fetch.cls.ce = cep;
1930 }
1931 }
1932 }
1933
1934 if (SUCCESS == retval) {
1935 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
1936 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
1937 if (stmt->dbh->is_persistent) {
1938 php_error_docref(NULL, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release");
1939 }
1940 #endif
1941 if (argc == 3) {
1942 if (Z_TYPE(args[skip+2]) != IS_NULL && Z_TYPE(args[skip+2]) != IS_ARRAY) {
1943 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
1944 retval = FAILURE;
1945 } else if (Z_TYPE(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL(args[skip+2]))) {
1946 ZVAL_ARR(&stmt->fetch.cls.ctor_args, zend_array_dup(Z_ARRVAL(args[skip+2])));
1947 }
1948 }
1949
1950 if (SUCCESS == retval) {
1951 do_fetch_class_prepare(stmt);
1952 }
1953 }
1954
1955 break;
1956
1957 case PDO_FETCH_INTO:
1958 if (argc != 2) {
1959 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter");
1960 } else if (Z_TYPE(args[skip+1]) != IS_OBJECT) {
1961 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object");
1962 } else {
1963 retval = SUCCESS;
1964 }
1965
1966 if (SUCCESS == retval) {
1967 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
1968 if (stmt->dbh->is_persistent) {
1969 php_error_docref(NULL, E_WARNING, "PHP might crash if you don't call $stmt->setFetchMode() to reset to defaults on this persistent statement. This will be fixed in a later release");
1970 }
1971 #endif
1972 ZVAL_COPY(&stmt->fetch.into, &args[skip+1]);
1973 }
1974
1975 break;
1976
1977 default:
1978 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified");
1979 }
1980
1981 if (SUCCESS == retval) {
1982 stmt->default_fetch_type = mode;
1983 }
1984
1985 /*
1986 * PDO error (if any) has already been raised at this point.
1987 *
1988 * The error_code is cleared, otherwise the caller will read the
1989 * last error message from the driver.
1990 *
1991 */
1992 PDO_STMT_CLEAR_ERR();
1993
1994 efree(args);
1995
1996 return retval;
1997 }
1998
PHP_METHOD(PDOStatement,setFetchMode)1999 static PHP_METHOD(PDOStatement, setFetchMode)
2000 {
2001 PHP_STMT_GET_OBJ;
2002
2003 RETVAL_BOOL(
2004 pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2005 stmt, 0) == SUCCESS
2006 );
2007 }
2008 /* }}} */
2009
2010 /* {{{ proto bool PDOStatement::nextRowset()
2011 Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeeded, false otherwise */
2012
pdo_stmt_do_next_rowset(pdo_stmt_t * stmt)2013 static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt)
2014 {
2015 /* un-describe */
2016 if (stmt->columns) {
2017 int i;
2018 struct pdo_column_data *cols = stmt->columns;
2019
2020 for (i = 0; i < stmt->column_count; i++) {
2021 if (cols[i].name) {
2022 zend_string_release_ex(cols[i].name, 0);
2023 }
2024 }
2025 efree(stmt->columns);
2026 stmt->columns = NULL;
2027 stmt->column_count = 0;
2028 }
2029
2030 if (!stmt->methods->next_rowset(stmt)) {
2031 /* Set the executed flag to 0 to reallocate columns on next execute */
2032 stmt->executed = 0;
2033 return 0;
2034 }
2035
2036 pdo_stmt_describe_columns(stmt);
2037
2038 return 1;
2039 }
2040
PHP_METHOD(PDOStatement,nextRowset)2041 static PHP_METHOD(PDOStatement, nextRowset)
2042 {
2043 PHP_STMT_GET_OBJ;
2044
2045 if (!stmt->methods->next_rowset) {
2046 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets");
2047 RETURN_FALSE;
2048 }
2049
2050 PDO_STMT_CLEAR_ERR();
2051
2052 if (!pdo_stmt_do_next_rowset(stmt)) {
2053 PDO_HANDLE_STMT_ERR();
2054 RETURN_FALSE;
2055 }
2056
2057 RETURN_TRUE;
2058 }
2059 /* }}} */
2060
2061 /* {{{ proto bool PDOStatement::closeCursor()
2062 Closes the cursor, leaving the statement ready for re-execution. */
PHP_METHOD(PDOStatement,closeCursor)2063 static PHP_METHOD(PDOStatement, closeCursor)
2064 {
2065 PHP_STMT_GET_OBJ;
2066
2067 if (!stmt->methods->cursor_closer) {
2068 /* emulate it by fetching and discarding rows */
2069 do {
2070 while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0))
2071 ;
2072 if (!stmt->methods->next_rowset) {
2073 break;
2074 }
2075
2076 if (!pdo_stmt_do_next_rowset(stmt)) {
2077 break;
2078 }
2079
2080 } while (1);
2081 stmt->executed = 0;
2082 RETURN_TRUE;
2083 }
2084
2085 PDO_STMT_CLEAR_ERR();
2086
2087 if (!stmt->methods->cursor_closer(stmt)) {
2088 PDO_HANDLE_STMT_ERR();
2089 RETURN_FALSE;
2090 }
2091 stmt->executed = 0;
2092 RETURN_TRUE;
2093 }
2094 /* }}} */
2095
2096 /* {{{ proto void PDOStatement::debugDumpParams()
2097 A utility for internals hackers to debug parameter internals */
PHP_METHOD(PDOStatement,debugDumpParams)2098 static PHP_METHOD(PDOStatement, debugDumpParams)
2099 {
2100 php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
2101 struct pdo_bound_param_data *param;
2102 PHP_STMT_GET_OBJ;
2103
2104 if (out == NULL) {
2105 RETURN_FALSE;
2106 }
2107
2108 /* break into multiple operations so query string won't be truncated at FORMAT_CONV_MAX_PRECISION */
2109 php_stream_printf(out, "SQL: [%zd] ", stmt->query_stringlen);
2110 php_stream_write(out, stmt->query_string, stmt->query_stringlen);
2111 php_stream_write(out, "\n", 1);
2112
2113 /* show parsed SQL if emulated prepares enabled */
2114 /* pointers will be equal if PDO::query() was invoked */
2115 if (stmt->active_query_string != NULL && stmt->active_query_string != stmt->query_string) {
2116 /* break into multiple operations so query string won't be truncated at FORMAT_CONV_MAX_PRECISION */
2117 php_stream_printf(out, "Sent SQL: [%zd] ", stmt->active_query_stringlen);
2118 php_stream_write(out, stmt->active_query_string, stmt->active_query_stringlen);
2119 php_stream_write(out, "\n", 1);
2120 }
2121
2122 php_stream_printf(out, "Params: %d\n",
2123 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2124
2125 if (stmt->bound_params) {
2126 zend_ulong num;
2127 zend_string *key = NULL;
2128 ZEND_HASH_FOREACH_KEY_PTR(stmt->bound_params, num, key, param) {
2129 if (key) {
2130 php_stream_printf(out, "Key: Name: [%zd] %.*s\n",
2131 ZSTR_LEN(key), (int) ZSTR_LEN(key), ZSTR_VAL(key));
2132 } else {
2133 php_stream_printf(out, "Key: Position #" ZEND_ULONG_FMT ":\n", num);
2134 }
2135
2136 php_stream_printf(out,
2137 "paramno=" ZEND_LONG_FMT "\n"
2138 "name=[%zd] \"%.*s\"\n"
2139 "is_param=%d\n"
2140 "param_type=%d\n",
2141 param->paramno, param->name ? ZSTR_LEN(param->name) : 0, param->name ? (int) ZSTR_LEN(param->name) : 0,
2142 param->name ? ZSTR_VAL(param->name) : "",
2143 param->is_param,
2144 param->param_type);
2145
2146 } ZEND_HASH_FOREACH_END();
2147 }
2148
2149 php_stream_close(out);
2150 }
2151 /* }}} */
2152
2153 const zend_function_entry pdo_dbstmt_functions[] = {
2154 PHP_ME(PDOStatement, execute, arginfo_pdostatement_execute, ZEND_ACC_PUBLIC)
2155 PHP_ME(PDOStatement, fetch, arginfo_pdostatement_fetch, ZEND_ACC_PUBLIC)
2156 PHP_ME(PDOStatement, bindParam, arginfo_pdostatement_bindparam, ZEND_ACC_PUBLIC)
2157 PHP_ME(PDOStatement, bindColumn, arginfo_pdostatement_bindcolumn, ZEND_ACC_PUBLIC)
2158 PHP_ME(PDOStatement, bindValue, arginfo_pdostatement_bindvalue, ZEND_ACC_PUBLIC)
2159 PHP_ME(PDOStatement, rowCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2160 PHP_ME(PDOStatement, fetchColumn, arginfo_pdostatement_fetchcolumn, ZEND_ACC_PUBLIC)
2161 PHP_ME(PDOStatement, fetchAll, arginfo_pdostatement_fetchall, ZEND_ACC_PUBLIC)
2162 PHP_ME(PDOStatement, fetchObject, arginfo_pdostatement_fetchobject, ZEND_ACC_PUBLIC)
2163 PHP_ME(PDOStatement, errorCode, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2164 PHP_ME(PDOStatement, errorInfo, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2165 PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
2166 PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
2167 PHP_ME(PDOStatement, columnCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2168 PHP_ME(PDOStatement, getColumnMeta, arginfo_pdostatement_getcolumnmeta, ZEND_ACC_PUBLIC)
2169 PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
2170 PHP_ME(PDOStatement, nextRowset, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2171 PHP_ME(PDOStatement, closeCursor, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2172 PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2173 PHP_FE_END
2174 };
2175
2176 /* {{{ overloaded handlers for PDOStatement class */
dbstmt_prop_write(zval * object,zval * member,zval * value,void ** cache_slot)2177 static zval *dbstmt_prop_write(zval *object, zval *member, zval *value, void **cache_slot)
2178 {
2179 pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
2180
2181 if (!try_convert_to_string(member)) {
2182 return value;
2183 }
2184
2185 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2186 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
2187 return value;
2188 } else {
2189 return zend_std_write_property(object, member, value, cache_slot);
2190 }
2191 }
2192
dbstmt_prop_delete(zval * object,zval * member,void ** cache_slot)2193 static void dbstmt_prop_delete(zval *object, zval *member, void **cache_slot)
2194 {
2195 pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
2196
2197 if (!try_convert_to_string(member)) {
2198 return;
2199 }
2200
2201 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2202 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
2203 } else {
2204 zend_std_unset_property(object, member, cache_slot);
2205 }
2206 }
2207
dbstmt_method_get(zend_object ** object_pp,zend_string * method_name,const zval * key)2208 static zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key)
2209 {
2210 zend_function *fbc = NULL;
2211 zend_string *lc_method_name;
2212 zend_object *object = *object_pp;
2213
2214 lc_method_name = zend_string_tolower(method_name);
2215
2216 if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
2217 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
2218 /* instance not created by PDO object */
2219 if (!stmt->dbh) {
2220 goto out;
2221 }
2222 /* not a pre-defined method, nor a user-defined method; check
2223 * the driver specific methods */
2224 if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2225 if (!pdo_hash_methods(Z_PDO_OBJECT_P(&stmt->database_object_handle),
2226 PDO_DBH_DRIVER_METHOD_KIND_STMT)
2227 || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2228 goto out;
2229 }
2230 }
2231
2232 if ((fbc = zend_hash_find_ptr(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT], lc_method_name)) == NULL) {
2233 goto out;
2234 }
2235 /* got it */
2236 }
2237
2238 out:
2239 zend_string_release_ex(lc_method_name, 0);
2240 if (!fbc) {
2241 fbc = zend_std_get_method(object_pp, method_name, key);
2242 }
2243 return fbc;
2244 }
2245
dbstmt_compare(zval * object1,zval * object2)2246 static int dbstmt_compare(zval *object1, zval *object2)
2247 {
2248 return -1;
2249 }
2250
2251 zend_object_handlers pdo_dbstmt_object_handlers;
2252 zend_object_handlers pdo_row_object_handlers;
2253
php_pdo_free_statement(pdo_stmt_t * stmt)2254 PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
2255 {
2256 if (stmt->bound_params) {
2257 zend_hash_destroy(stmt->bound_params);
2258 FREE_HASHTABLE(stmt->bound_params);
2259 stmt->bound_params = NULL;
2260 }
2261 if (stmt->bound_param_map) {
2262 zend_hash_destroy(stmt->bound_param_map);
2263 FREE_HASHTABLE(stmt->bound_param_map);
2264 stmt->bound_param_map = NULL;
2265 }
2266 if (stmt->bound_columns) {
2267 zend_hash_destroy(stmt->bound_columns);
2268 FREE_HASHTABLE(stmt->bound_columns);
2269 stmt->bound_columns = NULL;
2270 }
2271
2272 if (stmt->methods && stmt->methods->dtor) {
2273 stmt->methods->dtor(stmt);
2274 }
2275 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
2276 efree(stmt->active_query_string);
2277 }
2278 if (stmt->query_string) {
2279 efree(stmt->query_string);
2280 }
2281
2282 if (stmt->columns) {
2283 int i;
2284 struct pdo_column_data *cols = stmt->columns;
2285
2286 for (i = 0; i < stmt->column_count; i++) {
2287 if (cols[i].name) {
2288 zend_string_release_ex(cols[i].name, 0);
2289 cols[i].name = NULL;
2290 }
2291 }
2292 efree(stmt->columns);
2293 stmt->columns = NULL;
2294 }
2295
2296 if (!Z_ISUNDEF(stmt->fetch.into) && stmt->default_fetch_type == PDO_FETCH_INTO) {
2297 zval_ptr_dtor(&stmt->fetch.into);
2298 ZVAL_UNDEF(&stmt->fetch.into);
2299 }
2300
2301 do_fetch_opt_finish(stmt, 1);
2302
2303 if (!Z_ISUNDEF(stmt->database_object_handle)) {
2304 zval_ptr_dtor(&stmt->database_object_handle);
2305 }
2306 zend_object_std_dtor(&stmt->std);
2307 }
2308
pdo_dbstmt_free_storage(zend_object * std)2309 void pdo_dbstmt_free_storage(zend_object *std)
2310 {
2311 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(std);
2312 php_pdo_free_statement(stmt);
2313 }
2314
pdo_dbstmt_new(zend_class_entry * ce)2315 zend_object *pdo_dbstmt_new(zend_class_entry *ce)
2316 {
2317 pdo_stmt_t *stmt;
2318
2319 stmt = zend_object_alloc(sizeof(pdo_stmt_t), ce);
2320 zend_object_std_init(&stmt->std, ce);
2321 object_properties_init(&stmt->std, ce);
2322
2323 stmt->std.handlers = &pdo_dbstmt_object_handlers;
2324
2325 return &stmt->std;
2326 }
2327 /* }}} */
2328
2329 /* {{{ statement iterator */
2330
2331 struct php_pdo_iterator {
2332 zend_object_iterator iter;
2333 zend_ulong key;
2334 zval fetch_ahead;
2335 };
2336
pdo_stmt_iter_dtor(zend_object_iterator * iter)2337 static void pdo_stmt_iter_dtor(zend_object_iterator *iter)
2338 {
2339 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2340
2341 zval_ptr_dtor(&I->iter.data);
2342
2343 if (!Z_ISUNDEF(I->fetch_ahead)) {
2344 zval_ptr_dtor(&I->fetch_ahead);
2345 }
2346 }
2347
pdo_stmt_iter_valid(zend_object_iterator * iter)2348 static int pdo_stmt_iter_valid(zend_object_iterator *iter)
2349 {
2350 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2351
2352 return Z_ISUNDEF(I->fetch_ahead) ? FAILURE : SUCCESS;
2353 }
2354
pdo_stmt_iter_get_data(zend_object_iterator * iter)2355 static zval *pdo_stmt_iter_get_data(zend_object_iterator *iter)
2356 {
2357 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2358
2359 /* sanity */
2360 if (Z_ISUNDEF(I->fetch_ahead)) {
2361 return NULL;
2362 }
2363
2364 return &I->fetch_ahead;
2365 }
2366
pdo_stmt_iter_get_key(zend_object_iterator * iter,zval * key)2367 static void pdo_stmt_iter_get_key(zend_object_iterator *iter, zval *key)
2368 {
2369 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2370
2371 if (I->key == (zend_ulong)-1) {
2372 ZVAL_NULL(key);
2373 } else {
2374 ZVAL_LONG(key, I->key);
2375 }
2376 }
2377
pdo_stmt_iter_move_forwards(zend_object_iterator * iter)2378 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter)
2379 {
2380 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2381 pdo_stmt_t *stmt = Z_PDO_STMT_P(&I->iter.data); /* for PDO_HANDLE_STMT_ERR() */
2382
2383 if (!Z_ISUNDEF(I->fetch_ahead)) {
2384 zval_ptr_dtor(&I->fetch_ahead);
2385 }
2386
2387 if (!do_fetch(stmt, TRUE, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2388 PDO_FETCH_ORI_NEXT, 0, 0)) {
2389
2390 PDO_HANDLE_STMT_ERR();
2391 I->key = (zend_ulong)-1;
2392 ZVAL_UNDEF(&I->fetch_ahead);
2393
2394 return;
2395 }
2396
2397 I->key++;
2398 }
2399
2400 static const zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2401 pdo_stmt_iter_dtor,
2402 pdo_stmt_iter_valid,
2403 pdo_stmt_iter_get_data,
2404 pdo_stmt_iter_get_key,
2405 pdo_stmt_iter_move_forwards,
2406 NULL,
2407 NULL
2408 };
2409
pdo_stmt_iter_get(zend_class_entry * ce,zval * object,int by_ref)2410 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref)
2411 {
2412 pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
2413 struct php_pdo_iterator *I;
2414
2415 if (by_ref) {
2416 zend_throw_error(NULL, "An iterator cannot be used with foreach by reference");
2417 return NULL;
2418 }
2419
2420 I = ecalloc(1, sizeof(struct php_pdo_iterator));
2421 zend_iterator_init(&I->iter);
2422 I->iter.funcs = &pdo_stmt_iter_funcs;
2423 Z_ADDREF_P(object);
2424 ZVAL_OBJ(&I->iter.data, Z_OBJ_P(object));
2425
2426 if (!do_fetch(stmt, 1, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2427 PDO_FETCH_ORI_NEXT, 0, 0)) {
2428 PDO_HANDLE_STMT_ERR();
2429 I->key = (zend_ulong)-1;
2430 ZVAL_UNDEF(&I->fetch_ahead);
2431 }
2432
2433 return &I->iter;
2434 }
2435
2436 /* }}} */
2437
2438 /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2439
2440 const zend_function_entry pdo_row_functions[] = {
2441 PHP_FE_END
2442 };
2443
row_prop_read(zval * object,zval * member,int type,void ** cache_slot,zval * rv)2444 static zval *row_prop_read(zval *object, zval *member, int type, void **cache_slot, zval *rv)
2445 {
2446 pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
2447 pdo_stmt_t *stmt = row->stmt;
2448 int colno = -1;
2449 zval zobj;
2450 zend_long lval;
2451
2452 ZVAL_NULL(rv);
2453 if (stmt) {
2454 if (Z_TYPE_P(member) == IS_LONG) {
2455 if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
2456 fetch_value(stmt, rv, Z_LVAL_P(member), NULL);
2457 }
2458 } else if (Z_TYPE_P(member) == IS_STRING
2459 && is_numeric_string_ex(Z_STRVAL_P(member), Z_STRLEN_P(member), &lval, NULL, 0, NULL) == IS_LONG) {
2460 if (lval >= 0 && lval < stmt->column_count) {
2461 fetch_value(stmt, rv, lval, NULL);
2462 }
2463 } else {
2464 if (!try_convert_to_string(member)) {
2465 return &EG(uninitialized_zval);
2466 }
2467
2468 /* TODO: replace this with a hash of available column names to column
2469 * numbers */
2470 for (colno = 0; colno < stmt->column_count; colno++) {
2471 if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
2472 strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
2473 fetch_value(stmt, rv, colno, NULL);
2474 return rv;
2475 }
2476 }
2477 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2478 ZVAL_OBJ(&zobj, &stmt->std);
2479 //zval_ptr_dtor(rv);
2480 return zend_std_read_property(&zobj, member, type, cache_slot, rv);
2481 }
2482 }
2483 }
2484
2485 return rv;
2486 }
2487
row_dim_read(zval * object,zval * member,int type,zval * rv)2488 static zval *row_dim_read(zval *object, zval *member, int type, zval *rv)
2489 {
2490 return row_prop_read(object, member, type, NULL, rv);
2491 }
2492
row_prop_write(zval * object,zval * member,zval * value,void ** cache_slot)2493 static zval *row_prop_write(zval *object, zval *member, zval *value, void **cache_slot)
2494 {
2495 php_error_docref(NULL, E_WARNING, "This PDORow is not from a writable result set");
2496 return value;
2497 }
2498
row_dim_write(zval * object,zval * member,zval * value)2499 static void row_dim_write(zval *object, zval *member, zval *value)
2500 {
2501 php_error_docref(NULL, E_WARNING, "This PDORow is not from a writable result set");
2502 }
2503
row_prop_exists(zval * object,zval * member,int check_empty,void ** cache_slot)2504 static int row_prop_exists(zval *object, zval *member, int check_empty, void **cache_slot)
2505 {
2506 pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
2507 pdo_stmt_t *stmt = row->stmt;
2508 int colno = -1;
2509 zend_long lval;
2510
2511 if (stmt) {
2512 if (Z_TYPE_P(member) == IS_LONG) {
2513 return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
2514 } else if (Z_TYPE_P(member) == IS_STRING) {
2515 if (is_numeric_string_ex(Z_STRVAL_P(member), Z_STRLEN_P(member), &lval, NULL, 0, NULL) == IS_LONG) {
2516 return lval >=0 && lval < stmt->column_count;
2517 }
2518 } else {
2519 if (!try_convert_to_string(member)) {
2520 return 0;
2521 }
2522 }
2523
2524 /* TODO: replace this with a hash of available column names to column
2525 * numbers */
2526 for (colno = 0; colno < stmt->column_count; colno++) {
2527 if (ZSTR_LEN(stmt->columns[colno].name) == Z_STRLEN_P(member) &&
2528 strncmp(ZSTR_VAL(stmt->columns[colno].name), Z_STRVAL_P(member), Z_STRLEN_P(member)) == 0) {
2529 int res;
2530 zval val;
2531
2532 fetch_value(stmt, &val, colno, NULL);
2533 res = check_empty ? i_zend_is_true(&val) : Z_TYPE(val) != IS_NULL;
2534 zval_ptr_dtor_nogc(&val);
2535
2536 return res;
2537 }
2538 }
2539 }
2540
2541 return 0;
2542 }
2543
row_dim_exists(zval * object,zval * member,int check_empty)2544 static int row_dim_exists(zval *object, zval *member, int check_empty)
2545 {
2546 return row_prop_exists(object, member, check_empty, NULL);
2547 }
2548
row_prop_delete(zval * object,zval * offset,void ** cache_slot)2549 static void row_prop_delete(zval *object, zval *offset, void **cache_slot)
2550 {
2551 php_error_docref(NULL, E_WARNING, "Cannot delete properties from a PDORow");
2552 }
2553
row_dim_delete(zval * object,zval * offset)2554 static void row_dim_delete(zval *object, zval *offset)
2555 {
2556 php_error_docref(NULL, E_WARNING, "Cannot delete properties from a PDORow");
2557 }
2558
row_get_properties_for(zval * object,zend_prop_purpose purpose)2559 static HashTable *row_get_properties_for(zval *object, zend_prop_purpose purpose)
2560 {
2561 pdo_row_t *row = (pdo_row_t *)Z_OBJ_P(object);
2562 pdo_stmt_t *stmt = row->stmt;
2563 HashTable *props;
2564 int i;
2565
2566 if (purpose != ZEND_PROP_PURPOSE_DEBUG || stmt == NULL) {
2567 return zend_std_get_properties_for(object, purpose);
2568 }
2569
2570 if (!stmt->std.properties) {
2571 rebuild_object_properties(&stmt->std);
2572 }
2573 props = zend_array_dup(stmt->std.properties);
2574 for (i = 0; i < stmt->column_count; i++) {
2575 zval val;
2576 fetch_value(stmt, &val, i, NULL);
2577
2578 zend_hash_update(props, stmt->columns[i].name, &val);
2579 }
2580 return props;
2581 }
2582
row_method_get(zend_object ** object_pp,zend_string * method_name,const zval * key)2583 static zend_function *row_method_get(
2584 zend_object **object_pp,
2585 zend_string *method_name, const zval *key)
2586 {
2587 zend_function *fbc;
2588 zend_string *lc_method_name;
2589
2590 lc_method_name = zend_string_tolower(method_name);
2591
2592 if ((fbc = zend_hash_find_ptr(&pdo_row_ce->function_table, lc_method_name)) == NULL) {
2593 zend_string_release_ex(lc_method_name, 0);
2594 return NULL;
2595 }
2596
2597 zend_string_release_ex(lc_method_name, 0);
2598
2599 return fbc;
2600 }
2601
row_call_method(zend_string * method,zend_object * object,INTERNAL_FUNCTION_PARAMETERS)2602 static int row_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
2603 {
2604 return FAILURE;
2605 }
2606
row_get_ctor(zend_object * object)2607 static zend_function *row_get_ctor(zend_object *object)
2608 {
2609 zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually");
2610 return NULL;
2611 }
2612
row_get_classname(const zend_object * object)2613 static zend_string *row_get_classname(const zend_object *object)
2614 {
2615 return zend_string_init("PDORow", sizeof("PDORow") - 1, 0);
2616 }
2617
row_compare(zval * object1,zval * object2)2618 static int row_compare(zval *object1, zval *object2)
2619 {
2620 return -1;
2621 }
2622
pdo_row_free_storage(zend_object * std)2623 void pdo_row_free_storage(zend_object *std)
2624 {
2625 pdo_row_t *row = (pdo_row_t *)std;
2626 if (row->stmt) {
2627 ZVAL_UNDEF(&row->stmt->lazy_object_ref);
2628 OBJ_RELEASE(&row->stmt->std);
2629 }
2630 }
2631
pdo_row_new(zend_class_entry * ce)2632 zend_object *pdo_row_new(zend_class_entry *ce)
2633 {
2634 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
2635 zend_object_std_init(&row->std, ce);
2636 row->std.handlers = &pdo_row_object_handlers;
2637
2638 return &row->std;
2639 }
2640
pdo_stmt_init(void)2641 void pdo_stmt_init(void)
2642 {
2643 zend_class_entry ce;
2644
2645 INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2646 pdo_dbstmt_ce = zend_register_internal_class(&ce);
2647 pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2648 pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2649 pdo_dbstmt_ce->serialize = zend_class_serialize_deny;
2650 pdo_dbstmt_ce->unserialize = zend_class_unserialize_deny;
2651 zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_traversable);
2652 zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC);
2653
2654 memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2655 pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std);
2656 pdo_dbstmt_object_handlers.dtor_obj = zend_objects_destroy_object;
2657 pdo_dbstmt_object_handlers.free_obj = pdo_dbstmt_free_storage;
2658 pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2659 pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2660 pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2661 pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2662 pdo_dbstmt_object_handlers.clone_obj = NULL;
2663
2664 INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2665 pdo_row_ce = zend_register_internal_class(&ce);
2666 pdo_row_ce->ce_flags |= ZEND_ACC_FINAL; /* when removing this a lot of handlers need to be redone */
2667 pdo_row_ce->create_object = pdo_row_new;
2668 pdo_row_ce->serialize = zend_class_serialize_deny;
2669 pdo_row_ce->unserialize = zend_class_unserialize_deny;
2670
2671 memcpy(&pdo_row_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2672 pdo_row_object_handlers.free_obj = pdo_row_free_storage;
2673 pdo_row_object_handlers.clone_obj = NULL;
2674 pdo_row_object_handlers.get_property_ptr_ptr = NULL;
2675 pdo_row_object_handlers.read_property = row_prop_read;
2676 pdo_row_object_handlers.write_property = row_prop_write;
2677 pdo_row_object_handlers.has_property = row_prop_exists;
2678 pdo_row_object_handlers.unset_property = row_prop_delete;
2679 pdo_row_object_handlers.read_dimension = row_dim_read;
2680 pdo_row_object_handlers.write_dimension = row_dim_write;
2681 pdo_row_object_handlers.has_dimension = row_dim_exists;
2682 pdo_row_object_handlers.unset_dimension = row_dim_delete;
2683 pdo_row_object_handlers.get_properties_for = row_get_properties_for;
2684 pdo_row_object_handlers.get_method = row_method_get;
2685 pdo_row_object_handlers.call_method = row_call_method;
2686 pdo_row_object_handlers.get_constructor = row_get_ctor;
2687 pdo_row_object_handlers.get_class_name = row_get_classname;
2688 pdo_row_object_handlers.compare_objects = row_compare;
2689 }
2690