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