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