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