1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 7 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2017 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 PHP_FUNCTION(dbrow_constructor) /* {{{ */
117 {
118 zend_throw_exception_ex(php_pdo_get_exception(), 0, "You may not create a PDORow manually");
119 }
120 /* }}} */
121
rewrite_name_to_position(pdo_stmt_t * stmt,struct pdo_bound_param_data * param)122 static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param) /* {{{ */
123 {
124 if (stmt->bound_param_map) {
125 /* rewriting :name to ? style.
126 * We need to fixup the parameter numbers on the parameters.
127 * If we find that a given named parameter has been used twice,
128 * we will raise an error, as we can't be sure that it is safe
129 * to bind multiple parameters onto the same zval in the underlying
130 * driver */
131 char *name;
132 int position = 0;
133
134 if (stmt->named_rewrite_template) {
135 /* this is not an error here */
136 return 1;
137 }
138 if (!param->name) {
139 /* do the reverse; map the parameter number to the name */
140 if ((name = zend_hash_index_find_ptr(stmt->bound_param_map, param->paramno)) != NULL) {
141 param->name = zend_string_init(name, strlen(name), 0);
142 return 1;
143 }
144 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
145 return 0;
146 }
147
148 ZEND_HASH_FOREACH_PTR(stmt->bound_param_map, name) {
149 if (strncmp(name, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1)) {
150 position++;
151 continue;
152 }
153 if (param->paramno >= 0) {
154 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");
155 return -1;
156 }
157 param->paramno = position;
158 return 1;
159 } ZEND_HASH_FOREACH_END();
160 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined");
161 return 0;
162 }
163 return 1;
164 }
165 /* }}} */
166
167 /* trigger callback hook for parameters */
dispatch_param_event(pdo_stmt_t * stmt,enum pdo_param_event event_type)168 static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type) /* {{{ */
169 {
170 int ret = 1, is_param = 1;
171 struct pdo_bound_param_data *param;
172 HashTable *ht;
173
174 if (!stmt->methods->param_hook) {
175 return 1;
176 }
177
178 ht = stmt->bound_params;
179
180 iterate:
181 if (ht) {
182 ZEND_HASH_FOREACH_PTR(ht, param) {
183 if (!stmt->methods->param_hook(stmt, param, event_type)) {
184 ret = 0;
185 break;
186 }
187 } ZEND_HASH_FOREACH_END();
188 }
189 if (ret && is_param) {
190 ht = stmt->bound_columns;
191 is_param = 0;
192 goto iterate;
193 }
194
195 return ret;
196 }
197 /* }}} */
198
pdo_stmt_describe_columns(pdo_stmt_t * stmt)199 int pdo_stmt_describe_columns(pdo_stmt_t *stmt) /* {{{ */
200 {
201 int col;
202
203 stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
204
205 for (col = 0; col < stmt->column_count; col++) {
206 if (!stmt->methods->describer(stmt, col)) {
207 return 0;
208 }
209
210 /* if we are applying case conversions on column names, do so now */
211 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
212 char *s = ZSTR_VAL(stmt->columns[col].name);
213
214 switch (stmt->dbh->desired_case) {
215 case PDO_CASE_UPPER:
216 while (*s != '\0') {
217 *s = toupper(*s);
218 s++;
219 }
220 break;
221 case PDO_CASE_LOWER:
222 while (*s != '\0') {
223 *s = tolower(*s);
224 s++;
225 }
226 break;
227 default:
228 ;
229 }
230 }
231
232 #if 0
233 /* update the column index on named bound parameters */
234 if (stmt->bound_params) {
235 struct pdo_bound_param_data *param;
236
237 if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
238 stmt->columns[col].namelen, (void**)¶m)) {
239 param->paramno = col;
240 }
241 }
242 #endif
243 if (stmt->bound_columns) {
244 struct pdo_bound_param_data *param;
245
246 if ((param = zend_hash_find_ptr(stmt->bound_columns,
247 stmt->columns[col].name)) != NULL) {
248 param->paramno = col;
249 }
250 }
251
252 }
253 return 1;
254 }
255 /* }}} */
256
get_lazy_object(pdo_stmt_t * stmt,zval * return_value)257 static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value) /* {{{ */
258 {
259 if (Z_ISUNDEF(stmt->lazy_object_ref)) {
260 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
261 row->stmt = stmt;
262 zend_object_std_init(&row->std, pdo_row_ce);
263 ZVAL_OBJ(&stmt->lazy_object_ref, &row->std);
264 row->std.handlers = &pdo_row_object_handlers;
265 GC_REFCOUNT(&stmt->std)++;
266 GC_REFCOUNT(&row->std)--;
267 }
268 ZVAL_COPY(return_value, &stmt->lazy_object_ref);
269 }
270 /* }}} */
271
param_dtor(zval * el)272 static void param_dtor(zval *el) /* {{{ */
273 {
274 struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)Z_PTR_P(el);
275
276 /* tell the driver that it is going away */
277 if (param->stmt->methods->param_hook) {
278 param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE);
279 }
280
281 if (param->name) {
282 zend_string_release(param->name);
283 }
284
285 if (!Z_ISUNDEF(param->parameter)) {
286 zval_ptr_dtor(¶m->parameter);
287 ZVAL_UNDEF(¶m->parameter);
288 }
289 if (!Z_ISUNDEF(param->driver_params)) {
290 zval_ptr_dtor(¶m->driver_params);
291 }
292 efree(param);
293 }
294 /* }}} */
295
really_register_bound_param(struct pdo_bound_param_data * param,pdo_stmt_t * stmt,int is_param)296 static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param) /* {{{ */
297 {
298 HashTable *hash;
299 zval *parameter;
300 struct pdo_bound_param_data *pparam = NULL;
301
302 hash = is_param ? stmt->bound_params : stmt->bound_columns;
303
304 if (!hash) {
305 ALLOC_HASHTABLE(hash);
306 zend_hash_init(hash, 13, NULL, param_dtor, 0);
307
308 if (is_param) {
309 stmt->bound_params = hash;
310 } else {
311 stmt->bound_columns = hash;
312 }
313 }
314
315 if (!Z_ISREF(param->parameter)) {
316 parameter = ¶m->parameter;
317 } else {
318 parameter = Z_REFVAL(param->parameter);
319 }
320
321 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && !Z_ISNULL_P(parameter)) {
322 if (Z_TYPE_P(parameter) == IS_DOUBLE) {
323 char *p;
324 int len = spprintf(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(parameter));
325 ZVAL_STRINGL(parameter, p, len);
326 efree(p);
327 } else {
328 convert_to_string(parameter);
329 }
330 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && (Z_TYPE_P(parameter) == IS_FALSE || Z_TYPE_P(parameter) == IS_TRUE)) {
331 convert_to_long(parameter);
332 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(parameter) == IS_LONG) {
333 convert_to_boolean(parameter);
334 }
335
336 param->stmt = stmt;
337 param->is_param = is_param;
338
339 if (Z_REFCOUNTED(param->driver_params)) {
340 Z_ADDREF(param->driver_params);
341 }
342
343 if (!is_param && param->name && stmt->columns) {
344 /* try to map the name to the column */
345 int i;
346
347 for (i = 0; i < stmt->column_count; i++) {
348 if (ZSTR_LEN(stmt->columns[i].name) == ZSTR_LEN(param->name) &&
349 strncmp(ZSTR_VAL(stmt->columns[i].name), ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1) == 0) {
350 param->paramno = i;
351 break;
352 }
353 }
354
355 /* if you prepare and then execute passing an array of params keyed by names,
356 * then this will trigger, and we don't want that */
357 if (param->paramno == -1) {
358 char *tmp;
359 spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", ZSTR_VAL(param->name));
360 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp);
361 efree(tmp);
362 }
363 }
364
365 if (param->name) {
366 if (is_param && ZSTR_VAL(param->name)[0] != ':') {
367 zend_string *temp = zend_string_alloc(ZSTR_LEN(param->name) + 1, 0);
368 ZSTR_VAL(temp)[0] = ':';
369 memmove(ZSTR_VAL(temp) + 1, ZSTR_VAL(param->name), ZSTR_LEN(param->name) + 1);
370 param->name = temp;
371 } else {
372 param->name = zend_string_init(ZSTR_VAL(param->name), ZSTR_LEN(param->name), 0);
373 }
374 }
375
376 if (is_param && !rewrite_name_to_position(stmt, param)) {
377 if (param->name) {
378 zend_string_release(param->name);
379 param->name = NULL;
380 }
381 return 0;
382 }
383
384 /* ask the driver to perform any normalization it needs on the
385 * parameter name. Note that it is illegal for the driver to take
386 * a reference to param, as it resides in transient storage only
387 * at this time. */
388 if (stmt->methods->param_hook) {
389 if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE
390 )) {
391 if (param->name) {
392 zend_string_release(param->name);
393 param->name = NULL;
394 }
395 return 0;
396 }
397 }
398
399 /* delete any other parameter registered with this number.
400 * If the parameter is named, it will be removed and correctly
401 * disposed of by the hash_update call that follows */
402 if (param->paramno >= 0) {
403 zend_hash_index_del(hash, param->paramno);
404 }
405
406 /* allocate storage for the parameter, keyed by its "canonical" name */
407 if (param->name) {
408 pparam = zend_hash_update_mem(hash, param->name, param, sizeof(struct pdo_bound_param_data));
409 } else {
410 pparam = zend_hash_index_update_mem(hash, param->paramno, param, sizeof(struct pdo_bound_param_data));
411 }
412
413 /* tell the driver we just created a parameter */
414 if (stmt->methods->param_hook) {
415 if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC
416 )) {
417 /* undo storage allocation; the hash will free the parameter
418 * name if required */
419 if (pparam->name) {
420 zend_hash_del(hash, pparam->name);
421 } else {
422 zend_hash_index_del(hash, pparam->paramno);
423 }
424 /* param->parameter is freed by hash dtor */
425 ZVAL_UNDEF(¶m->parameter);
426 return 0;
427 }
428 }
429 return 1;
430 }
431 /* }}} */
432
433 /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
434 Execute a prepared statement, optionally binding parameters */
PHP_METHOD(PDOStatement,execute)435 static PHP_METHOD(PDOStatement, execute)
436 {
437 zval *input_params = NULL;
438 int ret = 1;
439 PHP_STMT_GET_OBJ;
440
441 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|a!", &input_params)) {
442 RETURN_FALSE;
443 }
444
445 PDO_STMT_CLEAR_ERR();
446
447 if (input_params) {
448 struct pdo_bound_param_data param;
449 zval *tmp;
450 zend_string *key = NULL;
451 zend_ulong num_index;
452
453 if (stmt->bound_params) {
454 zend_hash_destroy(stmt->bound_params);
455 FREE_HASHTABLE(stmt->bound_params);
456 stmt->bound_params = NULL;
457 }
458
459 ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(input_params), num_index, key, tmp) {
460 memset(¶m, 0, sizeof(param));
461
462 if (key) {
463 /* yes this is correct. we don't want to count the null byte. ask wez */
464 param.name = key;
465 param.paramno = -1;
466 } else {
467 /* we're okay to be zero based here */
468 /* num_index is unsignend
469 if (num_index < 0) {
470 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL);
471 RETURN_FALSE;
472 }
473 */
474 param.paramno = num_index;
475 }
476
477 param.param_type = PDO_PARAM_STR;
478 ZVAL_COPY(¶m.parameter, tmp);
479
480 if (!really_register_bound_param(¶m, stmt, 1)) {
481 if (!Z_ISUNDEF(param.parameter)) {
482 zval_ptr_dtor(¶m.parameter);
483 }
484 RETURN_FALSE;
485 }
486 } ZEND_HASH_FOREACH_END();
487 }
488
489 if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
490 /* handle the emulated parameter binding,
491 * stmt->active_query_string holds the query with binds expanded and
492 * quoted.
493 */
494
495 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
496 &stmt->active_query_string, &stmt->active_query_stringlen);
497
498 if (ret == 0) {
499 /* no changes were made */
500 stmt->active_query_string = stmt->query_string;
501 stmt->active_query_stringlen = stmt->query_stringlen;
502 ret = 1;
503 } else if (ret == -1) {
504 /* something broke */
505 PDO_HANDLE_STMT_ERR();
506 RETURN_FALSE;
507 }
508 } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE)) {
509 PDO_HANDLE_STMT_ERR();
510 RETURN_FALSE;
511 }
512 if (stmt->methods->executer(stmt)) {
513 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
514 efree(stmt->active_query_string);
515 }
516 stmt->active_query_string = NULL;
517 if (!stmt->executed) {
518 /* this is the first execute */
519
520 if (stmt->dbh->alloc_own_columns && !stmt->columns) {
521 /* for "big boy" drivers, we need to allocate memory to fetch
522 * the results into, so lets do that now */
523 ret = pdo_stmt_describe_columns(stmt);
524 }
525
526 stmt->executed = 1;
527 }
528
529 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST)) {
530 RETURN_FALSE;
531 }
532
533 RETURN_BOOL(ret);
534 }
535 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
536 efree(stmt->active_query_string);
537 }
538 stmt->active_query_string = NULL;
539 PDO_HANDLE_STMT_ERR();
540 RETURN_FALSE;
541 }
542 /* }}} */
543
fetch_value(pdo_stmt_t * stmt,zval * dest,int colno,int * type_override)544 static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override) /* {{{ */
545 {
546 struct pdo_column_data *col;
547 char *value = NULL;
548 size_t value_len = 0;
549 int caller_frees = 0;
550 int type, new_type;
551
552 col = &stmt->columns[colno];
553 type = PDO_PARAM_TYPE(col->param_type);
554 new_type = type_override ? PDO_PARAM_TYPE(*type_override) : type;
555
556 value = NULL;
557 value_len = 0;
558
559 stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees);
560
561 switch (type) {
562 case PDO_PARAM_ZVAL:
563 if (value && value_len == sizeof(zval)) {
564 ZVAL_COPY_VALUE(dest, (zval *)value);
565 } else {
566 ZVAL_NULL(dest);
567 }
568
569 if (Z_TYPE_P(dest) == IS_NULL) {
570 type = new_type;
571 }
572 break;
573
574 case PDO_PARAM_INT:
575 if (value && value_len == sizeof(zend_long)) {
576 ZVAL_LONG(dest, *(zend_long*)value);
577 break;
578 }
579 ZVAL_NULL(dest);
580 break;
581
582 case PDO_PARAM_BOOL:
583 if (value && value_len == sizeof(zend_bool)) {
584 ZVAL_BOOL(dest, *(zend_bool*)value);
585 break;
586 }
587 ZVAL_NULL(dest);
588 break;
589
590 case PDO_PARAM_LOB:
591 if (value == NULL) {
592 ZVAL_NULL(dest);
593 } else if (value_len == 0) {
594 /* Warning, empty strings need to be passed as stream */
595 if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
596 zend_string *buf;
597 buf = php_stream_copy_to_mem((php_stream*)value, PHP_STREAM_COPY_ALL, 0);
598 if (buf == NULL) {
599 ZVAL_EMPTY_STRING(dest);
600 } else {
601 ZVAL_STR(dest, buf);
602 }
603 php_stream_close((php_stream*)value);
604 } else {
605 php_stream_to_zval((php_stream*)value, dest);
606 }
607 } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
608 /* they gave us a string, but LOBs are represented as streams in PDO */
609 php_stream *stm;
610 #ifdef TEMP_STREAM_TAKE_BUFFER
611 if (caller_frees) {
612 stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
613 if (stm) {
614 caller_frees = 0;
615 }
616 } else
617 #endif
618 {
619 stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
620 }
621 if (stm) {
622 php_stream_to_zval(stm, dest);
623 } else {
624 ZVAL_NULL(dest);
625 }
626 } else {
627 ZVAL_STRINGL(dest, value, value_len);
628 }
629 break;
630
631 case PDO_PARAM_STR:
632 if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
633 ZVAL_STRINGL(dest, value, value_len);
634 break;
635 }
636 default:
637 ZVAL_NULL(dest);
638 }
639
640 if (type != new_type) {
641 switch (new_type) {
642 case PDO_PARAM_INT:
643 convert_to_long_ex(dest);
644 break;
645 case PDO_PARAM_BOOL:
646 convert_to_boolean_ex(dest);
647 break;
648 case PDO_PARAM_STR:
649 convert_to_string_ex(dest);
650 break;
651 case PDO_PARAM_NULL:
652 convert_to_null_ex(dest);
653 break;
654 default:
655 ;
656 }
657 }
658
659 if (caller_frees && value) {
660 efree(value);
661 }
662
663 if (stmt->dbh->stringify) {
664 switch (Z_TYPE_P(dest)) {
665 case IS_LONG:
666 case IS_DOUBLE:
667 convert_to_string(dest);
668 break;
669 }
670 }
671
672 if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
673 ZVAL_EMPTY_STRING(dest);
674 }
675 }
676 /* }}} */
677
do_fetch_common(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,zend_long offset,int do_bind)678 static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori, zend_long offset, int do_bind) /* {{{ */
679 {
680 if (!stmt->executed) {
681 return 0;
682 }
683
684 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE)) {
685 return 0;
686 }
687
688 if (!stmt->methods->fetcher(stmt, ori, offset)) {
689 return 0;
690 }
691
692 /* some drivers might need to describe the columns now */
693 if (!stmt->columns && !pdo_stmt_describe_columns(stmt)) {
694 return 0;
695 }
696
697 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST)) {
698 return 0;
699 }
700
701 if (do_bind && stmt->bound_columns) {
702 /* update those bound column variables now */
703 struct pdo_bound_param_data *param;
704
705 ZEND_HASH_FOREACH_PTR(stmt->bound_columns, param) {
706 if (param->paramno >= 0) {
707 if (!Z_ISREF(param->parameter)) {
708 continue;
709 }
710
711 /* delete old value */
712 zval_ptr_dtor(Z_REFVAL(param->parameter));
713
714 /* set new value */
715 fetch_value(stmt, Z_REFVAL(param->parameter), param->paramno, (int *)¶m->param_type);
716
717 /* TODO: some smart thing that avoids duplicating the value in the
718 * general loop below. For now, if you're binding output columns,
719 * it's better to use LAZY or BOUND fetches if you want to shave
720 * off those cycles */
721 }
722 } ZEND_HASH_FOREACH_END();
723 }
724
725 return 1;
726 }
727 /* }}} */
728
do_fetch_class_prepare(pdo_stmt_t * stmt)729 static int do_fetch_class_prepare(pdo_stmt_t *stmt) /* {{{ */
730 {
731 zend_class_entry *ce = stmt->fetch.cls.ce;
732 zend_fcall_info *fci = &stmt->fetch.cls.fci;
733 zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
734
735 fci->size = sizeof(zend_fcall_info);
736
737 if (!ce) {
738 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
739 ce = ZEND_STANDARD_CLASS_DEF_PTR;
740 }
741
742 if (ce->constructor) {
743 fci->function_table = &ce->function_table;
744 ZVAL_UNDEF(&fci->function_name);
745 fci->symbol_table = NULL;
746 fci->retval = &stmt->fetch.cls.retval;
747 fci->param_count = 0;
748 fci->params = NULL;
749 fci->no_separation = 1;
750
751 zend_fcall_info_args_ex(fci, ce->constructor, &stmt->fetch.cls.ctor_args);
752
753 fcc->initialized = 1;
754 fcc->function_handler = ce->constructor;
755 fcc->calling_scope = EG(scope);
756 fcc->called_scope = ce;
757 return 1;
758 } else if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
759 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");
760 return 0;
761 } else {
762 return 1; /* no ctor no args is also ok */
763 }
764 }
765 /* }}} */
766
make_callable_ex(pdo_stmt_t * stmt,zval * callable,zend_fcall_info * fci,zend_fcall_info_cache * fcc,int num_args)767 static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args) /* {{{ */
768 {
769 char *is_callable_error = NULL;
770
771 if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error) == FAILURE) {
772 if (is_callable_error) {
773 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error);
774 efree(is_callable_error);
775 } else {
776 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback");
777 }
778 return 0;
779 }
780 if (is_callable_error) {
781 /* Possible E_STRICT error message */
782 efree(is_callable_error);
783 }
784
785 fci->param_count = num_args; /* probably less */
786 fci->params = safe_emalloc(sizeof(zval), num_args, 0);
787
788 return 1;
789 }
790 /* }}} */
791
do_fetch_func_prepare(pdo_stmt_t * stmt)792 static int do_fetch_func_prepare(pdo_stmt_t *stmt) /* {{{ */
793 {
794 zend_fcall_info *fci = &stmt->fetch.cls.fci;
795 zend_fcall_info_cache *fcc = &stmt->fetch.cls.fcc;
796
797 if (!make_callable_ex(stmt, &stmt->fetch.func.function, fci, fcc, stmt->column_count)) {
798 return 0;
799 } else {
800 stmt->fetch.func.values = safe_emalloc(sizeof(zval), stmt->column_count, 0);
801 return 1;
802 }
803 }
804 /* }}} */
805
do_fetch_opt_finish(pdo_stmt_t * stmt,int free_ctor_agrs)806 static void do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs) /* {{{ */
807 {
808 /* fci.size is used to check if it is valid */
809 if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
810 if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args)) {
811 /* Added to free constructor arguments */
812 zend_fcall_info_args_clear(&stmt->fetch.cls.fci, 1);
813 } else {
814 efree(stmt->fetch.cls.fci.params);
815 }
816 stmt->fetch.cls.fci.params = NULL;
817 }
818
819 stmt->fetch.cls.fci.size = 0;
820 if (!Z_ISUNDEF(stmt->fetch.cls.ctor_args) && free_ctor_agrs) {
821 zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
822 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
823 stmt->fetch.cls.fci.param_count = 0;
824 }
825 if (stmt->fetch.func.values) {
826 efree(stmt->fetch.func.values);
827 stmt->fetch.func.values = NULL;
828 }
829 }
830 /* }}} */
831
832 /* perform a fetch. If do_bind is true, update any bound columns.
833 * 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)834 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) /* {{{ */
835 {
836 int flags, idx, old_arg_count = 0;
837 zend_class_entry *ce = NULL, *old_ce = NULL;
838 zval grp_val, *pgrp, retval, old_ctor_args;
839 int colno;
840
841 if (how == PDO_FETCH_USE_DEFAULT) {
842 how = stmt->default_fetch_type;
843 }
844 flags = how & PDO_FETCH_FLAGS;
845 how = how & ~PDO_FETCH_FLAGS;
846
847 if (!do_fetch_common(stmt, ori, offset, do_bind)) {
848 return 0;
849 }
850
851 if (how == PDO_FETCH_BOUND) {
852 RETVAL_TRUE;
853 return 1;
854 }
855
856 if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
857 colno = 1;
858 } else {
859 colno = stmt->fetch.column;
860 }
861
862 if (return_value) {
863 int i = 0;
864
865 if (how == PDO_FETCH_LAZY) {
866 get_lazy_object(stmt, return_value);
867 return 1;
868 }
869
870 RETVAL_FALSE;
871
872 switch (how) {
873 case PDO_FETCH_USE_DEFAULT:
874 case PDO_FETCH_ASSOC:
875 case PDO_FETCH_BOTH:
876 case PDO_FETCH_NUM:
877 case PDO_FETCH_NAMED:
878 if (!return_all) {
879 ZVAL_NEW_ARR(return_value);
880 zend_hash_init(Z_ARRVAL_P(return_value), stmt->column_count, NULL, ZVAL_PTR_DTOR, 0);;
881 } else {
882 array_init(return_value);
883 }
884 break;
885
886 case PDO_FETCH_KEY_PAIR:
887 if (stmt->column_count != 2) {
888 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain extactly 2 columns.");
889 return 0;
890 }
891 if (!return_all) {
892 array_init(return_value);
893 }
894 break;
895
896 case PDO_FETCH_COLUMN:
897 if (colno >= 0 && colno < stmt->column_count) {
898 if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
899 fetch_value(stmt, return_value, 1, NULL);
900 } else if (flags == PDO_FETCH_GROUP && colno) {
901 fetch_value(stmt, return_value, 0, NULL);
902 } else {
903 fetch_value(stmt, return_value, colno, NULL);
904 }
905 if (!return_all) {
906 return 1;
907 } else {
908 break;
909 }
910 } else {
911 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index");
912 }
913 return 0;
914
915 case PDO_FETCH_OBJ:
916 object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
917 break;
918
919 case PDO_FETCH_CLASS:
920 if (flags & PDO_FETCH_CLASSTYPE) {
921 zval val;
922 zend_class_entry *cep;
923
924 old_ce = stmt->fetch.cls.ce;
925 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
926 old_arg_count = stmt->fetch.cls.fci.param_count;
927 do_fetch_opt_finish(stmt, 0);
928
929 fetch_value(stmt, &val, i++, NULL);
930 if (Z_TYPE(val) != IS_NULL) {
931 convert_to_string(&val);
932 if ((cep = zend_lookup_class(Z_STR(val))) == NULL) {
933 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
934 } else {
935 stmt->fetch.cls.ce = cep;
936 }
937 }
938
939 do_fetch_class_prepare(stmt);
940 zval_dtor(&val);
941 }
942 ce = stmt->fetch.cls.ce;
943 if (!ce) {
944 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified");
945 return 0;
946 }
947 if ((flags & PDO_FETCH_SERIALIZE) == 0) {
948 if (UNEXPECTED(object_init_ex(return_value, ce) != SUCCESS)) {
949 return 0;
950 }
951 if (!stmt->fetch.cls.fci.size) {
952 if (!do_fetch_class_prepare(stmt))
953 {
954 return 0;
955 }
956 }
957 if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
958 stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
959 stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
960 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
961 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
962 return 0;
963 } else {
964 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
965 zval_ptr_dtor(&stmt->fetch.cls.retval);
966 ZVAL_UNDEF(&stmt->fetch.cls.retval);
967 }
968 }
969 }
970 }
971 break;
972
973 case PDO_FETCH_INTO:
974 if (Z_ISUNDEF(stmt->fetch.into)) {
975 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified.");
976 return 0;
977 break;
978 }
979
980 ZVAL_COPY(return_value, &stmt->fetch.into);
981
982 if (Z_OBJ_P(return_value)->ce == ZEND_STANDARD_CLASS_DEF_PTR) {
983 how = PDO_FETCH_OBJ;
984 }
985 break;
986
987 case PDO_FETCH_FUNC:
988 if (Z_ISUNDEF(stmt->fetch.func.function)) {
989 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified");
990 return 0;
991 }
992 if (!stmt->fetch.func.fci.size) {
993 if (!do_fetch_func_prepare(stmt))
994 {
995 return 0;
996 }
997 }
998 break;
999
1000
1001 default:
1002 /* shouldn't happen */
1003 return 0;
1004 }
1005
1006 if (return_all && how != PDO_FETCH_KEY_PAIR) {
1007 if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
1008 fetch_value(stmt, &grp_val, colno, NULL);
1009 } else {
1010 fetch_value(stmt, &grp_val, i, NULL);
1011 }
1012 convert_to_string(&grp_val);
1013 if (how == PDO_FETCH_COLUMN) {
1014 i = stmt->column_count; /* no more data to fetch */
1015 } else {
1016 i++;
1017 }
1018 }
1019
1020 for (idx = 0; i < stmt->column_count; i++, idx++) {
1021 zval val;
1022 fetch_value(stmt, &val, i, NULL);
1023
1024 switch (how) {
1025 case PDO_FETCH_ASSOC:
1026 zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
1027 break;
1028
1029 case PDO_FETCH_KEY_PAIR:
1030 {
1031 zval tmp;
1032 fetch_value(stmt, &tmp, ++i, NULL);
1033
1034 if (Z_TYPE(val) == IS_LONG) {
1035 zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL(val), &tmp);
1036 } else {
1037 convert_to_string(&val);
1038 zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STR(val), &tmp);
1039 }
1040 zval_ptr_dtor(&val);
1041 return 1;
1042 }
1043 break;
1044
1045 case PDO_FETCH_USE_DEFAULT:
1046 case PDO_FETCH_BOTH:
1047 zend_symtable_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
1048 if (Z_REFCOUNTED(val)) {
1049 Z_ADDREF(val);
1050 }
1051 zend_hash_next_index_insert(Z_ARRVAL_P(return_value), &val);
1052 break;
1053
1054 case PDO_FETCH_NAMED:
1055 /* already have an item with this name? */
1056 {
1057 zval *curr_val;
1058 if ((curr_val = zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name))) {
1059 zval arr;
1060 if (Z_TYPE_P(curr_val) != IS_ARRAY) {
1061 /* a little bit of black magic here:
1062 * we're creating a new array and swapping it for the
1063 * zval that's already stored in the hash under the name
1064 * we want. We then add that zval to the array.
1065 * This is effectively the same thing as:
1066 * if (!is_array($hash[$name])) {
1067 * $hash[$name] = array($hash[$name]);
1068 * }
1069 * */
1070 zval cur;
1071
1072 array_init(&arr);
1073
1074 ZVAL_COPY_VALUE(&cur, curr_val);
1075 ZVAL_COPY_VALUE(curr_val, &arr);
1076
1077 zend_hash_next_index_insert_new(Z_ARRVAL(arr), &cur);
1078 } else {
1079 ZVAL_COPY_VALUE(&arr, curr_val);
1080 }
1081 zend_hash_next_index_insert_new(Z_ARRVAL(arr), &val);
1082 } else {
1083 zend_hash_update(Z_ARRVAL_P(return_value), stmt->columns[i].name, &val);
1084 }
1085 }
1086 break;
1087
1088 case PDO_FETCH_NUM:
1089 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &val);
1090 break;
1091
1092 case PDO_FETCH_OBJ:
1093 case PDO_FETCH_INTO:
1094 zend_update_property_ex(NULL, return_value,
1095 stmt->columns[i].name,
1096 &val);
1097 zval_ptr_dtor(&val);
1098 break;
1099
1100 case PDO_FETCH_CLASS:
1101 if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
1102 zend_update_property_ex(ce, return_value,
1103 stmt->columns[i].name,
1104 &val);
1105 zval_ptr_dtor(&val);
1106 } else {
1107 #ifdef MBO_0
1108 php_unserialize_data_t var_hash;
1109
1110 PHP_VAR_UNSERIALIZE_INIT(var_hash);
1111 if (php_var_unserialize(return_value, (const unsigned char**)&Z_STRVAL(val), Z_STRVAL(val)+Z_STRLEN(val), NULL) == FAILURE) {
1112 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data");
1113 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1114 return 0;
1115 }
1116 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1117 #endif
1118 if (!ce->unserialize) {
1119 zval_ptr_dtor(&val);
1120 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
1121 return 0;
1122 } 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) {
1123 zval_ptr_dtor(&val);
1124 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class");
1125 zval_dtor(return_value);
1126 ZVAL_NULL(return_value);
1127 return 0;
1128 } else {
1129 zval_ptr_dtor(&val);
1130 }
1131 }
1132 break;
1133
1134 case PDO_FETCH_FUNC:
1135 ZVAL_COPY_VALUE(&stmt->fetch.func.values[idx], &val);
1136 ZVAL_COPY_VALUE(&stmt->fetch.cls.fci.params[idx], &stmt->fetch.func.values[idx]);
1137 break;
1138
1139 default:
1140 zval_ptr_dtor(&val);
1141 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range");
1142 return 0;
1143 break;
1144 }
1145 }
1146
1147 switch (how) {
1148 case PDO_FETCH_CLASS:
1149 if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
1150 stmt->fetch.cls.fci.object = Z_OBJ_P(return_value);
1151 stmt->fetch.cls.fcc.object = Z_OBJ_P(return_value);
1152 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc) == FAILURE) {
1153 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor");
1154 return 0;
1155 } else {
1156 if (!Z_ISUNDEF(stmt->fetch.cls.retval)) {
1157 zval_ptr_dtor(&stmt->fetch.cls.retval);
1158 }
1159 }
1160 }
1161 if (flags & PDO_FETCH_CLASSTYPE) {
1162 do_fetch_opt_finish(stmt, 0);
1163 stmt->fetch.cls.ce = old_ce;
1164 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1165 stmt->fetch.cls.fci.param_count = old_arg_count;
1166 }
1167 break;
1168
1169 case PDO_FETCH_FUNC:
1170 stmt->fetch.func.fci.param_count = idx;
1171 stmt->fetch.func.fci.retval = &retval;
1172 if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc) == FAILURE) {
1173 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function");
1174 return 0;
1175 } else {
1176 if (return_all) {
1177 zval_ptr_dtor(return_value); /* we don't need that */
1178 ZVAL_COPY_VALUE(return_value, &retval);
1179 } else if (!Z_ISUNDEF(retval)) {
1180 ZVAL_COPY_VALUE(return_value, &retval);
1181 }
1182 }
1183 while (idx--) {
1184 zval_ptr_dtor(&stmt->fetch.func.values[idx]);
1185 }
1186 break;
1187
1188 default:
1189 break;
1190 }
1191
1192 if (return_all) {
1193 if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
1194 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), return_value);
1195 } else {
1196 zval grp;
1197 if ((pgrp = zend_symtable_find(Z_ARRVAL_P(return_all), Z_STR(grp_val))) == NULL) {
1198 array_init(&grp);
1199 zend_symtable_update(Z_ARRVAL_P(return_all), Z_STR(grp_val), &grp);
1200 } else {
1201 ZVAL_COPY_VALUE(&grp, pgrp);
1202 }
1203 zend_hash_next_index_insert(Z_ARRVAL(grp), return_value);
1204 }
1205 zval_dtor(&grp_val);
1206 }
1207
1208 }
1209
1210 return 1;
1211 }
1212 /* }}} */
1213
pdo_stmt_verify_mode(pdo_stmt_t * stmt,zend_long mode,int fetch_all)1214 static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, zend_long mode, int fetch_all) /* {{{ */
1215 {
1216 int flags = mode & PDO_FETCH_FLAGS;
1217
1218 mode = mode & ~PDO_FETCH_FLAGS;
1219
1220 if (mode < 0 || mode > PDO_FETCH__MAX) {
1221 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
1222 return 0;
1223 }
1224
1225 if (mode == PDO_FETCH_USE_DEFAULT) {
1226 flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
1227 mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1228 }
1229
1230 switch(mode) {
1231 case PDO_FETCH_FUNC:
1232 if (!fetch_all) {
1233 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()");
1234 return 0;
1235 }
1236 return 1;
1237
1238 case PDO_FETCH_LAZY:
1239 if (fetch_all) {
1240 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()");
1241 return 0;
1242 }
1243 /* fall through */
1244 default:
1245 if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1246 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS");
1247 return 0;
1248 }
1249 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1250 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS");
1251 return 0;
1252 }
1253 if (mode >= PDO_FETCH__MAX) {
1254 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode");
1255 return 0;
1256 }
1257 /* no break; */
1258
1259 case PDO_FETCH_CLASS:
1260 return 1;
1261 }
1262 }
1263 /* }}} */
1264
1265 /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
1266 Fetches the next row and returns it, or false if there are no more rows */
PHP_METHOD(PDOStatement,fetch)1267 static PHP_METHOD(PDOStatement, fetch)
1268 {
1269 zend_long how = PDO_FETCH_USE_DEFAULT;
1270 zend_long ori = PDO_FETCH_ORI_NEXT;
1271 zend_long off = 0;
1272 PHP_STMT_GET_OBJ;
1273
1274 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|lll", &how,
1275 &ori, &off)) {
1276 RETURN_FALSE;
1277 }
1278
1279 PDO_STMT_CLEAR_ERR();
1280
1281 if (!pdo_stmt_verify_mode(stmt, how, 0)) {
1282 RETURN_FALSE;
1283 }
1284
1285 if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
1286 PDO_HANDLE_STMT_ERR();
1287 RETURN_FALSE;
1288 }
1289 }
1290 /* }}} */
1291
1292 /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
1293 Fetches the next row and returns it as an object. */
PHP_METHOD(PDOStatement,fetchObject)1294 static PHP_METHOD(PDOStatement, fetchObject)
1295 {
1296 zend_long how = PDO_FETCH_CLASS;
1297 zend_long ori = PDO_FETCH_ORI_NEXT;
1298 zend_long off = 0;
1299 zend_string *class_name = NULL;
1300 zend_class_entry *old_ce;
1301 zval old_ctor_args, *ctor_args = NULL;
1302 int error = 0, old_arg_count;
1303
1304 PHP_STMT_GET_OBJ;
1305
1306 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|S!a", &class_name, &ctor_args)) {
1307 RETURN_FALSE;
1308 }
1309
1310 PDO_STMT_CLEAR_ERR();
1311
1312 if (!pdo_stmt_verify_mode(stmt, how, 0)) {
1313 RETURN_FALSE;
1314 }
1315
1316 old_ce = stmt->fetch.cls.ce;
1317 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
1318 old_arg_count = stmt->fetch.cls.fci.param_count;
1319
1320 do_fetch_opt_finish(stmt, 0);
1321
1322 if (ctor_args) {
1323 if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1324 ZVAL_DUP(&stmt->fetch.cls.ctor_args, ctor_args);
1325 } else {
1326 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
1327 }
1328 }
1329 if (class_name && !error) {
1330 stmt->fetch.cls.ce = zend_fetch_class(class_name, ZEND_FETCH_CLASS_AUTO);
1331
1332 if (!stmt->fetch.cls.ce) {
1333 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class");
1334 error = 1;
1335 }
1336 } else if (!error) {
1337 stmt->fetch.cls.ce = zend_standard_class_def;
1338 }
1339
1340 if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0)) {
1341 error = 1;
1342 }
1343 if (error) {
1344 PDO_HANDLE_STMT_ERR();
1345 }
1346 do_fetch_opt_finish(stmt, 1);
1347
1348 stmt->fetch.cls.ce = old_ce;
1349 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1350 stmt->fetch.cls.fci.param_count = old_arg_count;
1351 if (error) {
1352 RETURN_FALSE;
1353 }
1354 }
1355 /* }}} */
1356
1357 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1358 Returns a data of the specified column in the result set. */
PHP_METHOD(PDOStatement,fetchColumn)1359 static PHP_METHOD(PDOStatement, fetchColumn)
1360 {
1361 zend_long col_n = 0;
1362 PHP_STMT_GET_OBJ;
1363
1364 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|l", &col_n)) {
1365 RETURN_FALSE;
1366 }
1367
1368 PDO_STMT_CLEAR_ERR();
1369
1370 if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE)) {
1371 PDO_HANDLE_STMT_ERR();
1372 RETURN_FALSE;
1373 }
1374
1375 fetch_value(stmt, return_value, col_n, NULL);
1376 }
1377 /* }}} */
1378
1379 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1380 Returns an array of all of the results. */
PHP_METHOD(PDOStatement,fetchAll)1381 static PHP_METHOD(PDOStatement, fetchAll)
1382 {
1383 zend_long how = PDO_FETCH_USE_DEFAULT;
1384 zval data, *return_all;
1385 zval *arg2;
1386 zend_class_entry *old_ce;
1387 zval old_ctor_args, *ctor_args = NULL;
1388 int error = 0, flags, old_arg_count;
1389 PHP_STMT_GET_OBJ;
1390
1391 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|lzz", &how, &arg2, &ctor_args)) {
1392 RETURN_FALSE;
1393 }
1394
1395 if (!pdo_stmt_verify_mode(stmt, how, 1)) {
1396 RETURN_FALSE;
1397 }
1398
1399 old_ce = stmt->fetch.cls.ce;
1400 ZVAL_COPY_VALUE(&old_ctor_args, &stmt->fetch.cls.ctor_args);
1401 old_arg_count = stmt->fetch.cls.fci.param_count;
1402
1403 do_fetch_opt_finish(stmt, 0);
1404
1405 switch(how & ~PDO_FETCH_FLAGS) {
1406 case PDO_FETCH_CLASS:
1407 switch(ZEND_NUM_ARGS()) {
1408 case 0:
1409 case 1:
1410 stmt->fetch.cls.ce = zend_standard_class_def;
1411 break;
1412 case 3:
1413 if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1414 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array");
1415 error = 1;
1416 break;
1417 }
1418 if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1419 ctor_args = NULL;
1420 }
1421 /* no break */
1422 case 2:
1423 if (ctor_args) {
1424 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, ctor_args); /* we're not going to free these */
1425 } else {
1426 ZVAL_UNDEF(&stmt->fetch.cls.ctor_args);
1427 }
1428 if (Z_TYPE_P(arg2) != IS_STRING) {
1429 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)");
1430 error = 1;
1431 break;
1432 } else {
1433 stmt->fetch.cls.ce = zend_fetch_class(Z_STR_P(arg2), ZEND_FETCH_CLASS_AUTO);
1434 if (!stmt->fetch.cls.ce) {
1435 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class");
1436 error = 1;
1437 break;
1438 }
1439 }
1440 }
1441 if (!error) {
1442 do_fetch_class_prepare(stmt);
1443 }
1444 break;
1445
1446 case PDO_FETCH_FUNC:
1447 switch (ZEND_NUM_ARGS()) {
1448 case 0:
1449 case 1:
1450 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified");
1451 error = 1;
1452 break;
1453 case 3:
1454 case 2:
1455 ZVAL_COPY_VALUE(&stmt->fetch.func.function, arg2);
1456 if (do_fetch_func_prepare(stmt) == 0) {
1457 error = 1;
1458 }
1459 break;
1460 }
1461 break;
1462
1463 case PDO_FETCH_COLUMN:
1464 switch(ZEND_NUM_ARGS()) {
1465 case 0:
1466 case 1:
1467 stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1468 break;
1469 case 2:
1470 convert_to_long(arg2);
1471 stmt->fetch.column = Z_LVAL_P(arg2);
1472 break;
1473 case 3:
1474 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN");
1475 error = 1;
1476 }
1477 break;
1478
1479 default:
1480 if (ZEND_NUM_ARGS() > 1) {
1481 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters");
1482 error = 1;
1483 }
1484 }
1485
1486 flags = how & PDO_FETCH_FLAGS;
1487
1488 if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1489 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1490 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1491 }
1492
1493 if (!error) {
1494 PDO_STMT_CLEAR_ERR();
1495 if ((how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1496 (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1497 ) {
1498 array_init(return_value);
1499 return_all = return_value;
1500 } else {
1501 return_all = 0;
1502 }
1503 if (!do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all)) {
1504 error = 2;
1505 }
1506 }
1507 if (!error) {
1508 if ((how & PDO_FETCH_GROUP)) {
1509 while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
1510 } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1511 while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all));
1512 } else {
1513 array_init(return_value);
1514 do {
1515 zend_hash_next_index_insert_new(Z_ARRVAL_P(return_value), &data);
1516 } while (do_fetch(stmt, 1, &data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0));
1517 }
1518 }
1519
1520 do_fetch_opt_finish(stmt, 0);
1521
1522 stmt->fetch.cls.ce = old_ce;
1523 ZVAL_COPY_VALUE(&stmt->fetch.cls.ctor_args, &old_ctor_args);
1524 stmt->fetch.cls.fci.param_count = old_arg_count;
1525
1526 if (error) {
1527 PDO_HANDLE_STMT_ERR();
1528 if (error != 2) {
1529 RETURN_FALSE;
1530 } else { /* on no results, return an empty array */
1531 if (Z_TYPE_P(return_value) != IS_ARRAY) {
1532 array_init(return_value);
1533 }
1534 return;
1535 }
1536 }
1537 }
1538 /* }}} */
1539
register_bound_param(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int is_param)1540 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1541 {
1542 struct pdo_bound_param_data param = {{{0}}};
1543 zend_long param_type = PDO_PARAM_STR;
1544 zval *parameter, *driver_params = NULL;
1545
1546 param.paramno = -1;
1547
1548 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
1549 "lz|llz!", ¶m.paramno, ¶meter, ¶m_type, ¶m.max_value_len,
1550 &driver_params)) {
1551 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz|llz!", ¶m.name,
1552 ¶meter, ¶m_type, ¶m.max_value_len,
1553 &driver_params)) {
1554 return 0;
1555 }
1556 }
1557
1558 param.param_type = (int) param_type;
1559
1560 if (param.paramno > 0) {
1561 --param.paramno; /* make it zero-based internally */
1562 } else if (!param.name) {
1563 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
1564 return 0;
1565 }
1566
1567 if (driver_params) {
1568 ZVAL_COPY(¶m.driver_params, driver_params);
1569 }
1570
1571 ZVAL_COPY(¶m.parameter, parameter);
1572 if (!really_register_bound_param(¶m, stmt, is_param)) {
1573 if (!Z_ISUNDEF(param.parameter)) {
1574 zval_ptr_dtor(&(param.parameter));
1575 }
1576 return 0;
1577 }
1578 return 1;
1579 } /* }}} */
1580
1581 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1582 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)1583 static PHP_METHOD(PDOStatement, bindValue)
1584 {
1585 struct pdo_bound_param_data param = {{{0}}};
1586 zend_long param_type = PDO_PARAM_STR;
1587 zval *parameter;
1588 PHP_STMT_GET_OBJ;
1589
1590 param.paramno = -1;
1591
1592 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS(),
1593 "lz/|l", ¶m.paramno, ¶meter, ¶m_type)) {
1594 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "Sz/|l", ¶m.name,
1595 ¶meter, ¶m_type)) {
1596 RETURN_FALSE;
1597 }
1598 }
1599
1600 param.param_type = (int) param_type;
1601
1602 if (param.paramno > 0) {
1603 --param.paramno; /* make it zero-based internally */
1604 } else if (!param.name) {
1605 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based");
1606 RETURN_FALSE;
1607 }
1608
1609 ZVAL_COPY(¶m.parameter, parameter);
1610 if (!really_register_bound_param(¶m, stmt, TRUE)) {
1611 if (!Z_ISUNDEF(param.parameter)) {
1612 zval_ptr_dtor(&(param.parameter));
1613 ZVAL_UNDEF(¶m.parameter);
1614 }
1615 RETURN_FALSE;
1616 }
1617 RETURN_TRUE;
1618 }
1619 /* }}} */
1620
1621 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1622 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)1623 static PHP_METHOD(PDOStatement, bindParam)
1624 {
1625 PHP_STMT_GET_OBJ;
1626 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1627 }
1628 /* }}} */
1629
1630 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1631 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)1632 static PHP_METHOD(PDOStatement, bindColumn)
1633 {
1634 PHP_STMT_GET_OBJ;
1635 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 0));
1636 }
1637 /* }}} */
1638
1639 /* {{{ proto int PDOStatement::rowCount()
1640 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)1641 static PHP_METHOD(PDOStatement, rowCount)
1642 {
1643 PHP_STMT_GET_OBJ;
1644
1645 RETURN_LONG(stmt->row_count);
1646 }
1647 /* }}} */
1648
1649 /* {{{ proto string PDOStatement::errorCode()
1650 Fetch the error code associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorCode)1651 static PHP_METHOD(PDOStatement, errorCode)
1652 {
1653 PHP_STMT_GET_OBJ;
1654
1655 if (zend_parse_parameters_none() == FAILURE) {
1656 return;
1657 }
1658
1659 if (stmt->error_code[0] == '\0') {
1660 RETURN_NULL();
1661 }
1662
1663 RETURN_STRING(stmt->error_code);
1664 }
1665 /* }}} */
1666
1667 /* {{{ proto array PDOStatement::errorInfo()
1668 Fetch extended error information associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorInfo)1669 static PHP_METHOD(PDOStatement, errorInfo)
1670 {
1671 int error_count;
1672 int error_count_diff = 0;
1673 int error_expected_count = 3;
1674
1675 PHP_STMT_GET_OBJ;
1676
1677 if (zend_parse_parameters_none() == FAILURE) {
1678 return;
1679 }
1680
1681 array_init(return_value);
1682 add_next_index_string(return_value, stmt->error_code);
1683
1684 if (stmt->dbh->methods->fetch_err) {
1685 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value);
1686 }
1687
1688 error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1689
1690 if (error_expected_count > error_count) {
1691 int current_index;
1692
1693 error_count_diff = error_expected_count - error_count;
1694 for (current_index = 0; current_index < error_count_diff; current_index++) {
1695 add_next_index_null(return_value);
1696 }
1697 }
1698 }
1699 /* }}} */
1700
1701 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1702 Set an attribute */
PHP_METHOD(PDOStatement,setAttribute)1703 static PHP_METHOD(PDOStatement, setAttribute)
1704 {
1705 zend_long attr;
1706 zval *value = NULL;
1707 PHP_STMT_GET_OBJ;
1708
1709 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "lz!", &attr, &value)) {
1710 RETURN_FALSE;
1711 }
1712
1713 if (!stmt->methods->set_attribute) {
1714 goto fail;
1715 }
1716
1717 PDO_STMT_CLEAR_ERR();
1718 if (stmt->methods->set_attribute(stmt, attr, value)) {
1719 RETURN_TRUE;
1720 }
1721
1722 fail:
1723 if (!stmt->methods->set_attribute) {
1724 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes");
1725 } else {
1726 PDO_HANDLE_STMT_ERR();
1727 }
1728 RETURN_FALSE;
1729 }
1730 /* }}} */
1731
1732 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1733 Get an attribute */
1734
generic_stmt_attr_get(pdo_stmt_t * stmt,zval * return_value,zend_long attr)1735 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, zend_long attr)
1736 {
1737 switch (attr) {
1738 case PDO_ATTR_EMULATE_PREPARES:
1739 RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1740 return 1;
1741 }
1742 return 0;
1743 }
1744
PHP_METHOD(PDOStatement,getAttribute)1745 static PHP_METHOD(PDOStatement, getAttribute)
1746 {
1747 zend_long attr;
1748 PHP_STMT_GET_OBJ;
1749
1750 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr)) {
1751 RETURN_FALSE;
1752 }
1753
1754 if (!stmt->methods->get_attribute) {
1755 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1756 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1757 "This driver doesn't support getting attributes");
1758 RETURN_FALSE;
1759 }
1760 return;
1761 }
1762
1763 PDO_STMT_CLEAR_ERR();
1764 switch (stmt->methods->get_attribute(stmt, attr, return_value)) {
1765 case -1:
1766 PDO_HANDLE_STMT_ERR();
1767 RETURN_FALSE;
1768
1769 case 0:
1770 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1771 /* XXX: should do something better here */
1772 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1773 "driver doesn't support getting that attribute");
1774 RETURN_FALSE;
1775 }
1776 return;
1777
1778 default:
1779 return;
1780 }
1781 }
1782 /* }}} */
1783
1784 /* {{{ proto int PDOStatement::columnCount()
1785 Returns the number of columns in the result set */
PHP_METHOD(PDOStatement,columnCount)1786 static PHP_METHOD(PDOStatement, columnCount)
1787 {
1788 PHP_STMT_GET_OBJ;
1789 if (zend_parse_parameters_none() == FAILURE) {
1790 return;
1791 }
1792 RETURN_LONG(stmt->column_count);
1793 }
1794 /* }}} */
1795
1796 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1797 Returns meta data for a numbered column */
PHP_METHOD(PDOStatement,getColumnMeta)1798 static PHP_METHOD(PDOStatement, getColumnMeta)
1799 {
1800 zend_long colno;
1801 struct pdo_column_data *col;
1802 PHP_STMT_GET_OBJ;
1803
1804 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &colno)) {
1805 RETURN_FALSE;
1806 }
1807 if(colno < 0) {
1808 pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative");
1809 RETURN_FALSE;
1810 }
1811
1812 if (!stmt->methods->get_column_meta) {
1813 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data");
1814 RETURN_FALSE;
1815 }
1816
1817 PDO_STMT_CLEAR_ERR();
1818 if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value)) {
1819 PDO_HANDLE_STMT_ERR();
1820 RETURN_FALSE;
1821 }
1822
1823 /* add stock items */
1824 col = &stmt->columns[colno];
1825 add_assoc_str(return_value, "name", zend_string_copy(col->name));
1826 add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1827 add_assoc_long(return_value, "precision", col->precision);
1828 if (col->param_type != PDO_PARAM_ZVAL) {
1829 /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1830 add_assoc_long(return_value, "pdo_type", col->param_type);
1831 }
1832 }
1833 /* }}} */
1834
1835 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1836 Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1837
pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int skip)1838 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1839 {
1840 zend_long mode = PDO_FETCH_BOTH;
1841 int flags = 0, argc = ZEND_NUM_ARGS() - skip;
1842 zval *args;
1843 zend_class_entry *cep;
1844 int retval;
1845
1846 do_fetch_opt_finish(stmt, 1);
1847
1848 switch (stmt->default_fetch_type) {
1849 case PDO_FETCH_INTO:
1850 if (!Z_ISUNDEF(stmt->fetch.into)) {
1851 zval_ptr_dtor(&stmt->fetch.into);
1852 ZVAL_UNDEF(&stmt->fetch.into);
1853 }
1854 break;
1855 default:
1856 ;
1857 }
1858
1859 stmt->default_fetch_type = PDO_FETCH_BOTH;
1860
1861 if (argc == 0) {
1862 return SUCCESS;
1863 }
1864
1865 args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval), 0);
1866
1867 retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1868
1869 if (SUCCESS == retval) {
1870 if (Z_TYPE(args[skip]) != IS_LONG) {
1871 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer");
1872 retval = FAILURE;
1873 } else {
1874 mode = Z_LVAL(args[skip]);
1875 flags = mode & PDO_FETCH_FLAGS;
1876
1877 retval = pdo_stmt_verify_mode(stmt, mode, 0);
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_DUP(&stmt->fetch.cls.ctor_args, &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(cols[i].name);
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 php_stream_printf(out, "Params: %d\n",
2121 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2122
2123 if (stmt->bound_params) {
2124 zend_ulong num;
2125 zend_string *key = NULL;
2126 ZEND_HASH_FOREACH_KEY_PTR(stmt->bound_params, num, key, param) {
2127 if (key) {
2128 php_stream_printf(out, "Key: Name: [%zd] %.*s\n",
2129 ZSTR_LEN(key), (int) ZSTR_LEN(key), ZSTR_VAL(key));
2130 } else {
2131 php_stream_printf(out, "Key: Position #%pd:\n", num);
2132 }
2133
2134 php_stream_printf(out, "paramno=%pd\nname=[%zd] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
2135 param->paramno, param->name ? ZSTR_LEN(param->name) : 0, param->name ? (int) ZSTR_LEN(param->name) : 0,
2136 param->name ? ZSTR_VAL(param->name) : "",
2137 param->is_param,
2138 param->param_type);
2139
2140 } ZEND_HASH_FOREACH_END();
2141 }
2142
2143 php_stream_close(out);
2144 }
2145 /* }}} */
2146
2147 /* {{{ proto int PDOStatement::__wakeup()
2148 Prevents use of a PDOStatement instance that has been unserialized */
PHP_METHOD(PDOStatement,__wakeup)2149 static PHP_METHOD(PDOStatement, __wakeup)
2150 {
2151 zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDOStatement instances");
2152 }
2153 /* }}} */
2154
2155 /* {{{ proto int PDOStatement::__sleep()
2156 Prevents serialization of a PDOStatement instance */
PHP_METHOD(PDOStatement,__sleep)2157 static PHP_METHOD(PDOStatement, __sleep)
2158 {
2159 zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDOStatement instances");
2160 }
2161 /* }}} */
2162
2163 const zend_function_entry pdo_dbstmt_functions[] = {
2164 PHP_ME(PDOStatement, execute, arginfo_pdostatement_execute, ZEND_ACC_PUBLIC)
2165 PHP_ME(PDOStatement, fetch, arginfo_pdostatement_fetch, ZEND_ACC_PUBLIC)
2166 PHP_ME(PDOStatement, bindParam, arginfo_pdostatement_bindparam, ZEND_ACC_PUBLIC)
2167 PHP_ME(PDOStatement, bindColumn, arginfo_pdostatement_bindcolumn, ZEND_ACC_PUBLIC)
2168 PHP_ME(PDOStatement, bindValue, arginfo_pdostatement_bindvalue, ZEND_ACC_PUBLIC)
2169 PHP_ME(PDOStatement, rowCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2170 PHP_ME(PDOStatement, fetchColumn, arginfo_pdostatement_fetchcolumn, ZEND_ACC_PUBLIC)
2171 PHP_ME(PDOStatement, fetchAll, arginfo_pdostatement_fetchall, ZEND_ACC_PUBLIC)
2172 PHP_ME(PDOStatement, fetchObject, arginfo_pdostatement_fetchobject, ZEND_ACC_PUBLIC)
2173 PHP_ME(PDOStatement, errorCode, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2174 PHP_ME(PDOStatement, errorInfo, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2175 PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
2176 PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
2177 PHP_ME(PDOStatement, columnCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2178 PHP_ME(PDOStatement, getColumnMeta, arginfo_pdostatement_getcolumnmeta, ZEND_ACC_PUBLIC)
2179 PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
2180 PHP_ME(PDOStatement, nextRowset, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2181 PHP_ME(PDOStatement, closeCursor, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2182 PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2183 PHP_ME(PDOStatement, __wakeup, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2184 PHP_ME(PDOStatement, __sleep, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2185 {NULL, NULL, NULL}
2186 };
2187
2188 /* {{{ overloaded handlers for PDOStatement class */
dbstmt_prop_write(zval * object,zval * member,zval * value,void ** cache_slot)2189 static void dbstmt_prop_write(zval *object, zval *member, zval *value, void **cache_slot)
2190 {
2191 pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
2192
2193 convert_to_string(member);
2194
2195 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2196 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only");
2197 } else {
2198 std_object_handlers.write_property(object, member, value, cache_slot);
2199 }
2200 }
2201
dbstmt_prop_delete(zval * object,zval * member,void ** cache_slot)2202 static void dbstmt_prop_delete(zval *object, zval *member, 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 std_object_handlers.unset_property(object, member, cache_slot);
2212 }
2213 }
2214
dbstmt_method_get(zend_object ** object_pp,zend_string * method_name,const zval * key)2215 static union _zend_function *dbstmt_method_get(zend_object **object_pp, zend_string *method_name, const zval *key)
2216 {
2217 zend_function *fbc = NULL;
2218 zend_string *lc_method_name;
2219 zend_object *object = *object_pp;
2220
2221 lc_method_name = zend_string_alloc(ZSTR_LEN(method_name), 0);
2222 zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
2223
2224
2225 if ((fbc = zend_hash_find_ptr(&object->ce->function_table, lc_method_name)) == NULL) {
2226 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(object);
2227 /* instance not created by PDO object */
2228 if (!stmt->dbh) {
2229 goto out;
2230 }
2231 /* not a pre-defined method, nor a user-defined method; check
2232 * the driver specific methods */
2233 if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2234 if (!pdo_hash_methods(Z_PDO_OBJECT_P(&stmt->database_object_handle),
2235 PDO_DBH_DRIVER_METHOD_KIND_STMT)
2236 || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2237 goto out;
2238 }
2239 }
2240
2241 if ((fbc = zend_hash_find_ptr(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT], lc_method_name)) == NULL) {
2242 goto out;
2243 }
2244 /* got it */
2245 }
2246
2247 out:
2248 zend_string_release(lc_method_name);
2249 if (!fbc) {
2250 fbc = std_object_handlers.get_method(object_pp, method_name, key);
2251 }
2252 return fbc;
2253 }
2254
dbstmt_compare(zval * object1,zval * object2)2255 static int dbstmt_compare(zval *object1, zval *object2)
2256 {
2257 return -1;
2258 }
2259
dbstmt_clone_obj(zval * zobject)2260 static zend_object *dbstmt_clone_obj(zval *zobject)
2261 {
2262 pdo_stmt_t *stmt;
2263 pdo_stmt_t *old_stmt;
2264
2265 stmt = ecalloc(1, sizeof(pdo_stmt_t) + zend_object_properties_size(Z_OBJCE_P(zobject)));
2266 zend_object_std_init(&stmt->std, Z_OBJCE_P(zobject));
2267 object_properties_init(&stmt->std, Z_OBJCE_P(zobject));
2268
2269 old_stmt = Z_PDO_STMT_P(zobject);
2270
2271 zend_objects_clone_members(&stmt->std, &old_stmt->std);
2272
2273 return &stmt->std;
2274 }
2275
2276 zend_object_handlers pdo_dbstmt_object_handlers;
2277 static int pdo_row_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data);
2278
pdo_stmt_init(void)2279 void pdo_stmt_init(void)
2280 {
2281 zend_class_entry ce;
2282
2283 INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2284 pdo_dbstmt_ce = zend_register_internal_class(&ce);
2285 pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2286 pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2287 zend_class_implements(pdo_dbstmt_ce, 1, zend_ce_traversable);
2288 zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC);
2289
2290 memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2291 pdo_dbstmt_object_handlers.offset = XtOffsetOf(pdo_stmt_t, std);
2292 pdo_dbstmt_object_handlers.dtor_obj = zend_objects_destroy_object;
2293 pdo_dbstmt_object_handlers.free_obj = pdo_dbstmt_free_storage;
2294 pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2295 pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2296 pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2297 pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2298 pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
2299
2300 INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2301 pdo_row_ce = zend_register_internal_class(&ce);
2302 pdo_row_ce->ce_flags |= ZEND_ACC_FINAL; /* when removing this a lot of handlers need to be redone */
2303 pdo_row_ce->create_object = pdo_row_new;
2304 pdo_row_ce->serialize = pdo_row_serialize;
2305 pdo_row_ce->unserialize = zend_class_unserialize_deny;
2306 }
2307
php_pdo_free_statement(pdo_stmt_t * stmt)2308 PDO_API void php_pdo_free_statement(pdo_stmt_t *stmt)
2309 {
2310 if (stmt->bound_params) {
2311 zend_hash_destroy(stmt->bound_params);
2312 FREE_HASHTABLE(stmt->bound_params);
2313 stmt->bound_params = NULL;
2314 }
2315 if (stmt->bound_param_map) {
2316 zend_hash_destroy(stmt->bound_param_map);
2317 FREE_HASHTABLE(stmt->bound_param_map);
2318 stmt->bound_param_map = NULL;
2319 }
2320 if (stmt->bound_columns) {
2321 zend_hash_destroy(stmt->bound_columns);
2322 FREE_HASHTABLE(stmt->bound_columns);
2323 stmt->bound_columns = NULL;
2324 }
2325
2326 if (stmt->methods && stmt->methods->dtor) {
2327 stmt->methods->dtor(stmt);
2328 }
2329 if (stmt->query_string) {
2330 efree(stmt->query_string);
2331 }
2332
2333 if (stmt->columns) {
2334 int i;
2335 struct pdo_column_data *cols = stmt->columns;
2336
2337 for (i = 0; i < stmt->column_count; i++) {
2338 if (cols[i].name) {
2339 zend_string_release(cols[i].name);
2340 cols[i].name = NULL;
2341 }
2342 }
2343 efree(stmt->columns);
2344 stmt->columns = NULL;
2345 }
2346
2347 if (!Z_ISUNDEF(stmt->fetch.into) && stmt->default_fetch_type == PDO_FETCH_INTO) {
2348 zval_ptr_dtor(&stmt->fetch.into);
2349 ZVAL_UNDEF(&stmt->fetch.into);
2350 }
2351
2352 do_fetch_opt_finish(stmt, 1);
2353
2354 if (!Z_ISUNDEF(stmt->database_object_handle)) {
2355 zval_ptr_dtor(&stmt->database_object_handle);
2356 }
2357 zend_object_std_dtor(&stmt->std);
2358 }
2359
pdo_dbstmt_free_storage(zend_object * std)2360 void pdo_dbstmt_free_storage(zend_object *std)
2361 {
2362 pdo_stmt_t *stmt = php_pdo_stmt_fetch_object(std);
2363 php_pdo_free_statement(stmt);
2364 }
2365
pdo_dbstmt_new(zend_class_entry * ce)2366 zend_object *pdo_dbstmt_new(zend_class_entry *ce)
2367 {
2368 pdo_stmt_t *stmt;
2369
2370 stmt = ecalloc(1, sizeof(pdo_stmt_t) + zend_object_properties_size(ce));
2371 zend_object_std_init(&stmt->std, ce);
2372 object_properties_init(&stmt->std, ce);
2373
2374 stmt->std.handlers = &pdo_dbstmt_object_handlers;
2375
2376 return &stmt->std;
2377 }
2378 /* }}} */
2379
2380 /* {{{ statement iterator */
2381
2382 struct php_pdo_iterator {
2383 zend_object_iterator iter;
2384 zend_ulong key;
2385 zval fetch_ahead;
2386 };
2387
pdo_stmt_iter_dtor(zend_object_iterator * iter)2388 static void pdo_stmt_iter_dtor(zend_object_iterator *iter)
2389 {
2390 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2391
2392 zval_ptr_dtor(&I->iter.data);
2393
2394 if (!Z_ISUNDEF(I->fetch_ahead)) {
2395 zval_ptr_dtor(&I->fetch_ahead);
2396 }
2397 }
2398
pdo_stmt_iter_valid(zend_object_iterator * iter)2399 static int pdo_stmt_iter_valid(zend_object_iterator *iter)
2400 {
2401 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2402
2403 return Z_ISUNDEF(I->fetch_ahead) ? FAILURE : SUCCESS;
2404 }
2405
pdo_stmt_iter_get_data(zend_object_iterator * iter)2406 static zval *pdo_stmt_iter_get_data(zend_object_iterator *iter)
2407 {
2408 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2409
2410 /* sanity */
2411 if (Z_ISUNDEF(I->fetch_ahead)) {
2412 return NULL;
2413 }
2414
2415 return &I->fetch_ahead;
2416 }
2417
pdo_stmt_iter_get_key(zend_object_iterator * iter,zval * key)2418 static void pdo_stmt_iter_get_key(zend_object_iterator *iter, zval *key)
2419 {
2420 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2421
2422 if (I->key == (ulong)-1) {
2423 ZVAL_NULL(key);
2424 } else {
2425 ZVAL_LONG(key, I->key);
2426 }
2427 }
2428
pdo_stmt_iter_move_forwards(zend_object_iterator * iter)2429 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter)
2430 {
2431 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter;
2432 pdo_stmt_t *stmt = Z_PDO_STMT_P(&I->iter.data); /* for PDO_HANDLE_STMT_ERR() */
2433
2434 if (!Z_ISUNDEF(I->fetch_ahead)) {
2435 zval_ptr_dtor(&I->fetch_ahead);
2436 }
2437
2438 if (!do_fetch(stmt, TRUE, &I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2439 PDO_FETCH_ORI_NEXT, 0, 0)) {
2440
2441 PDO_HANDLE_STMT_ERR();
2442 I->key = (ulong)-1;
2443 ZVAL_UNDEF(&I->fetch_ahead);
2444
2445 return;
2446 }
2447
2448 I->key++;
2449 }
2450
2451 static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2452 pdo_stmt_iter_dtor,
2453 pdo_stmt_iter_valid,
2454 pdo_stmt_iter_get_data,
2455 pdo_stmt_iter_get_key,
2456 pdo_stmt_iter_move_forwards,
2457 NULL
2458 };
2459
pdo_stmt_iter_get(zend_class_entry * ce,zval * object,int by_ref)2460 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref)
2461 {
2462 pdo_stmt_t *stmt = Z_PDO_STMT_P(object);
2463 struct php_pdo_iterator *I;
2464
2465 if (by_ref) {
2466 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
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 {NULL, NULL, NULL}
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 std_object_handlers.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_dtor(&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_alloc(ZSTR_LEN(method_name), 0);
2632 zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
2633
2634 if ((fbc = zend_hash_find_ptr(&pdo_row_ce->function_table, lc_method_name)) == NULL) {
2635 zend_string_release(lc_method_name);
2636 return NULL;
2637 }
2638
2639 zend_string_release(lc_method_name);
2640
2641 return fbc;
2642 }
2643
row_call_method(zend_string * method,zend_object * object,INTERNAL_FUNCTION_PARAMETERS)2644 static int row_call_method(zend_string *method, zend_object *object, INTERNAL_FUNCTION_PARAMETERS)
2645 {
2646 return FAILURE;
2647 }
2648
row_get_ctor(zend_object * object)2649 static union _zend_function *row_get_ctor(zend_object *object)
2650 {
2651 static zend_internal_function ctor = {0};
2652
2653 ctor.type = ZEND_INTERNAL_FUNCTION;
2654 ctor.function_name = zend_string_init("__construct", sizeof("__construct") - 1, 0);
2655 ctor.scope = pdo_row_ce;
2656 ctor.handler = ZEND_FN(dbrow_constructor);
2657 ctor.fn_flags = ZEND_ACC_PUBLIC;
2658
2659 return (union _zend_function*)&ctor;
2660 }
2661
row_get_classname(const zend_object * object)2662 static zend_string *row_get_classname(const zend_object *object)
2663 {
2664 return zend_string_init("PDORow", sizeof("PDORow") - 1, 0);
2665 }
2666
row_compare(zval * object1,zval * object2)2667 static int row_compare(zval *object1, zval *object2)
2668 {
2669 return -1;
2670 }
2671
2672 zend_object_handlers pdo_row_object_handlers = {
2673 0,
2674 zend_objects_destroy_object,
2675 pdo_row_free_storage,
2676 NULL,
2677 row_prop_read,
2678 row_prop_write,
2679 row_dim_read,
2680 row_dim_write,
2681 NULL,
2682 NULL,
2683 NULL,
2684 row_prop_exists,
2685 row_prop_delete,
2686 row_dim_exists,
2687 row_dim_delete,
2688 row_get_properties,
2689 row_method_get,
2690 row_call_method,
2691 row_get_ctor,
2692 row_get_classname,
2693 row_compare,
2694 NULL, /* cast */
2695 NULL
2696 };
2697
pdo_row_free_storage(zend_object * std)2698 void pdo_row_free_storage(zend_object *std)
2699 {
2700 pdo_row_t *row = (pdo_row_t *)std;
2701 if (row->stmt) {
2702 ZVAL_UNDEF(&row->stmt->lazy_object_ref);
2703 OBJ_RELEASE(&row->stmt->std);
2704 }
2705 }
2706
pdo_row_new(zend_class_entry * ce)2707 zend_object *pdo_row_new(zend_class_entry *ce)
2708 {
2709 pdo_row_t *row = ecalloc(1, sizeof(pdo_row_t));
2710 zend_object_std_init(&row->std, ce);
2711 row->std.handlers = &pdo_row_object_handlers;
2712
2713 return &row->std;
2714 }
2715
pdo_row_serialize(zval * object,unsigned char ** buffer,size_t * buf_len,zend_serialize_data * data)2716 static int pdo_row_serialize(zval *object, unsigned char **buffer, size_t *buf_len, zend_serialize_data *data)
2717 {
2718 php_error_docref(NULL, E_WARNING, "PDORow instances may not be serialized");
2719 return FAILURE;
2720 }
2721 /* }}} */
2722
2723 /*
2724 * Local variables:
2725 * tab-width: 4
2726 * c-basic-offset: 4
2727 * End:
2728 * vim600: noet sw=4 ts=4 fdm=marker
2729 * vim<600: noet sw=4 ts=4
2730 */
2731