Busybox: Upgrade to 1.21.1 (stable). lsof active.
[tomato.git] / release / src / router / php / ext / pdo / pdo_stmt.c
bloba469d09fc2e349b7533212243807e5c927898199
1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2013 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 +----------------------------------------------------------------------+
21 /* $Id$ */
23 /* The PDO Statement Handle Class */
25 #ifdef HAVE_CONFIG_H
26 #include "config.h"
27 #endif
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"
40 /* {{{ arginfo */
41 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement__void, 0)
42 ZEND_END_ARG_INFO()
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()
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()
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()
59 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchcolumn, 0, 0, 0)
60 ZEND_ARG_INFO(0, column_number)
61 ZEND_END_ARG_INFO()
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()
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()
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()
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()
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()
96 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getattribute, 0)
97 ZEND_ARG_INFO(0, attribute)
98 ZEND_END_ARG_INFO()
100 ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getcolumnmeta, 0)
101 ZEND_ARG_INFO(0, column)
102 ZEND_END_ARG_INFO()
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 /* }}} */
110 #define PHP_STMT_GET_OBJ \
111 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); \
112 if (!stmt->dbh) { \
113 RETURN_FALSE; \
116 static PHP_FUNCTION(dbstmt_constructor) /* {{{ */
118 php_error_docref(NULL TSRMLS_CC, E_ERROR, "You should not create a PDOStatement manually");
120 /* }}} */
122 static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
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;
134 if (stmt->named_rewrite_template) {
135 /* this is not an error here */
136 return 1;
138 if (!param->name) {
139 /* do the reverse; map the parameter number to the name */
140 if (SUCCESS == zend_hash_index_find(stmt->bound_param_map, param->paramno, (void**)&name)) {
141 param->name = estrdup(name);
142 param->namelen = strlen(param->name);
143 return 1;
145 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
146 return 0;
149 zend_hash_internal_pointer_reset(stmt->bound_param_map);
150 while (SUCCESS == zend_hash_get_current_data(stmt->bound_param_map, (void**)&name)) {
151 if (strcmp(name, param->name)) {
152 position++;
153 zend_hash_move_forward(stmt->bound_param_map);
154 continue;
156 if (param->paramno >= 0) {
157 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" TSRMLS_CC);
158 return -1;
160 param->paramno = position;
161 return 1;
163 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
164 return 0;
166 return 1;
168 /* }}} */
170 /* trigger callback hook for parameters */
171 static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
173 int ret = 1, is_param = 1;
174 struct pdo_bound_param_data *param;
175 HashTable *ht;
177 if (!stmt->methods->param_hook) {
178 return 1;
181 ht = stmt->bound_params;
183 iterate:
184 if (ht) {
185 zend_hash_internal_pointer_reset(ht);
186 while (SUCCESS == zend_hash_get_current_data(ht, (void**)&param)) {
187 if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
188 ret = 0;
189 break;
192 zend_hash_move_forward(ht);
195 if (ret && is_param) {
196 ht = stmt->bound_columns;
197 is_param = 0;
198 goto iterate;
201 return ret;
203 /* }}} */
205 int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
207 int col;
209 stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
211 for (col = 0; col < stmt->column_count; col++) {
212 if (!stmt->methods->describer(stmt, col TSRMLS_CC)) {
213 return 0;
216 /* if we are applying case conversions on column names, do so now */
217 if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
218 char *s = stmt->columns[col].name;
220 switch (stmt->dbh->desired_case) {
221 case PDO_CASE_UPPER:
222 while (*s != '\0') {
223 *s = toupper(*s);
224 s++;
226 break;
227 case PDO_CASE_LOWER:
228 while (*s != '\0') {
229 *s = tolower(*s);
230 s++;
232 break;
233 default:
238 #if 0
239 /* update the column index on named bound parameters */
240 if (stmt->bound_params) {
241 struct pdo_bound_param_data *param;
243 if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
244 stmt->columns[col].namelen, (void**)&param)) {
245 param->paramno = col;
248 #endif
249 if (stmt->bound_columns) {
250 struct pdo_bound_param_data *param;
252 if (SUCCESS == zend_hash_find(stmt->bound_columns, stmt->columns[col].name,
253 stmt->columns[col].namelen, (void**)&param)) {
254 param->paramno = col;
259 return 1;
261 /* }}} */
263 static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC) /* {{{ */
265 if (Z_TYPE(stmt->lazy_object_ref) == IS_NULL) {
266 Z_TYPE(stmt->lazy_object_ref) = IS_OBJECT;
267 Z_OBJ_HANDLE(stmt->lazy_object_ref) = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_row_free_storage, NULL TSRMLS_CC);
268 Z_OBJ_HT(stmt->lazy_object_ref) = &pdo_row_object_handlers;
269 stmt->refcount++;
271 Z_TYPE_P(return_value) = IS_OBJECT;
272 Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE(stmt->lazy_object_ref);
273 Z_OBJ_HT_P(return_value) = Z_OBJ_HT(stmt->lazy_object_ref);
274 zend_objects_store_add_ref(return_value TSRMLS_CC);
276 /* }}} */
278 static void param_dtor(void *data) /* {{{ */
280 struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
281 TSRMLS_FETCH();
283 /* tell the driver that it is going away */
284 if (param->stmt->methods->param_hook) {
285 param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE TSRMLS_CC);
288 if (param->name) {
289 efree(param->name);
292 if (param->parameter) {
293 zval_ptr_dtor(&(param->parameter));
294 param->parameter = NULL;
296 if (param->driver_params) {
297 zval_ptr_dtor(&(param->driver_params));
300 /* }}} */
302 static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC) /* {{{ */
304 HashTable *hash;
305 struct pdo_bound_param_data *pparam = NULL;
307 hash = is_param ? stmt->bound_params : stmt->bound_columns;
309 if (!hash) {
310 ALLOC_HASHTABLE(hash);
311 zend_hash_init(hash, 13, NULL, param_dtor, 0);
313 if (is_param) {
314 stmt->bound_params = hash;
315 } else {
316 stmt->bound_columns = hash;
320 if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
321 if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
322 char *p;
323 int len = spprintf(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(param->parameter));
324 ZVAL_STRINGL(param->parameter, p, len, 0);
325 } else {
326 convert_to_string(param->parameter);
328 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
329 convert_to_long(param->parameter);
330 } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
331 convert_to_boolean(param->parameter);
334 param->stmt = stmt;
335 param->is_param = is_param;
337 if (param->driver_params) {
338 Z_ADDREF_P(param->driver_params);
341 if (!is_param && param->name && stmt->columns) {
342 /* try to map the name to the column */
343 int i;
345 for (i = 0; i < stmt->column_count; i++) {
346 if (strcmp(stmt->columns[i].name, param->name) == 0) {
347 param->paramno = i;
348 break;
352 /* if you prepare and then execute passing an array of params keyed by names,
353 * then this will trigger, and we don't want that */
354 if (param->paramno == -1) {
355 char *tmp;
356 spprintf(&tmp, 0, "Did not find column name '%s' in the defined columns; it will not be bound", param->name);
357 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", tmp TSRMLS_CC);
358 efree(tmp);
362 if (param->name) {
363 if (is_param && param->name[0] != ':') {
364 char *temp = emalloc(++param->namelen + 1);
365 temp[0] = ':';
366 memmove(temp+1, param->name, param->namelen);
367 param->name = temp;
368 } else {
369 param->name = estrndup(param->name, param->namelen);
373 if (is_param && !rewrite_name_to_position(stmt, param TSRMLS_CC)) {
374 if (param->name) {
375 efree(param->name);
376 param->name = NULL;
378 return 0;
381 /* ask the driver to perform any normalization it needs on the
382 * parameter name. Note that it is illegal for the driver to take
383 * a reference to param, as it resides in transient storage only
384 * at this time. */
385 if (stmt->methods->param_hook) {
386 if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE
387 TSRMLS_CC)) {
388 if (param->name) {
389 efree(param->name);
390 param->name = NULL;
392 return 0;
396 /* delete any other parameter registered with this number.
397 * If the parameter is named, it will be removed and correctly
398 * disposed of by the hash_update call that follows */
399 if (param->paramno >= 0) {
400 zend_hash_index_del(hash, param->paramno);
403 /* allocate storage for the parameter, keyed by its "canonical" name */
404 if (param->name) {
405 zend_hash_update(hash, param->name, param->namelen, param,
406 sizeof(*param), (void**)&pparam);
407 } else {
408 zend_hash_index_update(hash, param->paramno, param, sizeof(*param),
409 (void**)&pparam);
412 /* tell the driver we just created a parameter */
413 if (stmt->methods->param_hook) {
414 if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC
415 TSRMLS_CC)) {
416 /* undo storage allocation; the hash will free the parameter
417 * name if required */
418 if (pparam->name) {
419 zend_hash_del(hash, pparam->name, pparam->namelen);
420 } else {
421 zend_hash_index_del(hash, pparam->paramno);
423 /* param->parameter is freed by hash dtor */
424 param->parameter = NULL;
425 return 0;
428 return 1;
430 /* }}} */
432 /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
433 Execute a prepared statement, optionally binding parameters */
434 static PHP_METHOD(PDOStatement, execute)
436 zval *input_params = NULL;
437 int ret = 1;
438 PHP_STMT_GET_OBJ;
440 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
441 RETURN_FALSE;
444 PDO_STMT_CLEAR_ERR();
446 if (input_params) {
447 struct pdo_bound_param_data param;
448 zval **tmp;
449 uint str_length;
450 ulong num_index;
452 if (stmt->bound_params) {
453 zend_hash_destroy(stmt->bound_params);
454 FREE_HASHTABLE(stmt->bound_params);
455 stmt->bound_params = NULL;
458 zend_hash_internal_pointer_reset(Z_ARRVAL_P(input_params));
459 while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(input_params), (void*)&tmp)) {
460 memset(&param, 0, sizeof(param));
462 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(input_params),
463 &param.name, &str_length, &num_index, 0, NULL)) {
464 /* yes this is correct. we don't want to count the null byte. ask wez */
465 param.namelen = str_length - 1;
466 param.paramno = -1;
467 } else {
468 /* we're okay to be zero based here */
469 if (num_index < 0) {
470 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL TSRMLS_CC);
471 RETURN_FALSE;
473 param.paramno = num_index;
476 param.param_type = PDO_PARAM_STR;
477 MAKE_STD_ZVAL(param.parameter);
478 MAKE_COPY_ZVAL(tmp, param.parameter);
480 if (!really_register_bound_param(&param, stmt, 1 TSRMLS_CC)) {
481 if (param.parameter) {
482 zval_ptr_dtor(&param.parameter);
484 RETURN_FALSE;
487 zend_hash_move_forward(Z_ARRVAL_P(input_params));
491 if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
492 /* handle the emulated parameter binding,
493 * stmt->active_query_string holds the query with binds expanded and
494 * quoted.
497 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
498 &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
500 if (ret == 0) {
501 /* no changes were made */
502 stmt->active_query_string = stmt->query_string;
503 stmt->active_query_stringlen = stmt->query_stringlen;
504 ret = 1;
505 } else if (ret == -1) {
506 /* something broke */
507 PDO_HANDLE_STMT_ERR();
508 RETURN_FALSE;
510 } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
511 PDO_HANDLE_STMT_ERR();
512 RETURN_FALSE;
514 if (stmt->methods->executer(stmt TSRMLS_CC)) {
515 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
516 efree(stmt->active_query_string);
518 stmt->active_query_string = NULL;
519 if (!stmt->executed) {
520 /* this is the first execute */
522 if (stmt->dbh->alloc_own_columns && !stmt->columns) {
523 /* for "big boy" drivers, we need to allocate memory to fetch
524 * the results into, so lets do that now */
525 ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
528 stmt->executed = 1;
531 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
532 RETURN_FALSE;
535 RETURN_BOOL(ret);
537 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
538 efree(stmt->active_query_string);
540 stmt->active_query_string = NULL;
541 PDO_HANDLE_STMT_ERR();
542 RETURN_FALSE;
544 /* }}} */
546 static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override TSRMLS_DC) /* {{{ */
548 struct pdo_column_data *col;
549 char *value = NULL;
550 unsigned long value_len = 0;
551 int caller_frees = 0;
552 int type, new_type;
554 col = &stmt->columns[colno];
555 type = PDO_PARAM_TYPE(col->param_type);
556 new_type = type_override ? PDO_PARAM_TYPE(*type_override) : type;
558 value = NULL;
559 value_len = 0;
561 stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
563 switch (type) {
564 case PDO_PARAM_ZVAL:
565 if (value && value_len == sizeof(zval)) {
566 int need_copy = (new_type != PDO_PARAM_ZVAL || stmt->dbh->stringify) ? 1 : 0;
567 zval *zv = *(zval**)value;
568 ZVAL_ZVAL(dest, zv, need_copy, 1);
569 } else {
570 ZVAL_NULL(dest);
573 if (Z_TYPE_P(dest) == IS_NULL) {
574 type = new_type;
576 break;
578 case PDO_PARAM_INT:
579 if (value && value_len == sizeof(long)) {
580 ZVAL_LONG(dest, *(long*)value);
581 break;
583 ZVAL_NULL(dest);
584 break;
586 case PDO_PARAM_BOOL:
587 if (value && value_len == sizeof(zend_bool)) {
588 ZVAL_BOOL(dest, *(zend_bool*)value);
589 break;
591 ZVAL_NULL(dest);
592 break;
594 case PDO_PARAM_LOB:
595 if (value == NULL) {
596 ZVAL_NULL(dest);
597 } else if (value_len == 0) {
598 /* Warning, empty strings need to be passed as stream */
599 if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
600 char *buf = NULL;
601 size_t len;
602 len = php_stream_copy_to_mem((php_stream*)value, &buf, PHP_STREAM_COPY_ALL, 0);
603 if(buf == NULL) {
604 ZVAL_EMPTY_STRING(dest);
605 } else {
606 ZVAL_STRINGL(dest, buf, len, 0);
608 php_stream_close((php_stream*)value);
609 } else {
610 php_stream_to_zval((php_stream*)value, dest);
612 } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
613 /* they gave us a string, but LOBs are represented as streams in PDO */
614 php_stream *stm;
615 #ifdef TEMP_STREAM_TAKE_BUFFER
616 if (caller_frees) {
617 stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
618 if (stm) {
619 caller_frees = 0;
621 } else
622 #endif
624 stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
626 if (stm) {
627 php_stream_to_zval(stm, dest);
628 } else {
629 ZVAL_NULL(dest);
631 } else {
632 ZVAL_STRINGL(dest, value, value_len, !caller_frees);
633 if (caller_frees) {
634 caller_frees = 0;
637 break;
639 case PDO_PARAM_STR:
640 if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
641 ZVAL_STRINGL(dest, value, value_len, !caller_frees);
642 if (caller_frees) {
643 caller_frees = 0;
645 break;
647 default:
648 ZVAL_NULL(dest);
651 if (type != new_type) {
652 switch (new_type) {
653 case PDO_PARAM_INT:
654 convert_to_long_ex(&dest);
655 break;
656 case PDO_PARAM_BOOL:
657 convert_to_boolean_ex(&dest);
658 break;
659 case PDO_PARAM_STR:
660 convert_to_string_ex(&dest);
661 break;
662 case PDO_PARAM_NULL:
663 convert_to_null_ex(&dest);
664 break;
665 default:
670 if (caller_frees && value) {
671 efree(value);
674 if (stmt->dbh->stringify) {
675 switch (Z_TYPE_P(dest)) {
676 case IS_LONG:
677 case IS_DOUBLE:
678 convert_to_string(dest);
679 break;
683 if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
684 ZVAL_EMPTY_STRING(dest);
687 /* }}} */
689 static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
690 long offset, int do_bind TSRMLS_DC) /* {{{ */
692 if (!stmt->executed) {
693 return 0;
696 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
697 return 0;
700 if (!stmt->methods->fetcher(stmt, ori, offset TSRMLS_CC)) {
701 return 0;
704 /* some drivers might need to describe the columns now */
705 if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
706 return 0;
709 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
710 return 0;
713 if (do_bind && stmt->bound_columns) {
714 /* update those bound column variables now */
715 struct pdo_bound_param_data *param;
717 zend_hash_internal_pointer_reset(stmt->bound_columns);
718 while (SUCCESS == zend_hash_get_current_data(stmt->bound_columns, (void**)&param)) {
719 if (param->paramno >= 0) {
720 convert_to_string(param->parameter);
722 /* delete old value */
723 zval_dtor(param->parameter);
725 /* set new value */
726 fetch_value(stmt, param->parameter, param->paramno, (int *)&param->param_type TSRMLS_CC);
728 /* TODO: some smart thing that avoids duplicating the value in the
729 * general loop below. For now, if you're binding output columns,
730 * it's better to use LAZY or BOUND fetches if you want to shave
731 * off those cycles */
734 zend_hash_move_forward(stmt->bound_columns);
738 return 1;
740 /* }}} */
742 static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
744 zend_class_entry * ce = stmt->fetch.cls.ce;
745 zend_fcall_info * fci = &stmt->fetch.cls.fci;
746 zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
748 fci->size = sizeof(zend_fcall_info);
750 if (!ce) {
751 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
752 ce = ZEND_STANDARD_CLASS_DEF_PTR;
755 if (ce->constructor) {
756 fci->function_table = &ce->function_table;
757 fci->function_name = NULL;
758 fci->symbol_table = NULL;
759 fci->retval_ptr_ptr = &stmt->fetch.cls.retval_ptr;
760 if (stmt->fetch.cls.ctor_args) {
761 HashTable *ht = Z_ARRVAL_P(stmt->fetch.cls.ctor_args);
762 Bucket *p;
764 fci->param_count = 0;
765 fci->params = safe_emalloc(sizeof(zval**), ht->nNumOfElements, 0);
766 p = ht->pListHead;
767 while (p != NULL) {
768 fci->params[fci->param_count++] = (zval**)p->pData;
769 p = p->pListNext;
771 } else {
772 fci->param_count = 0;
773 fci->params = NULL;
775 fci->no_separation = 1;
777 fcc->initialized = 1;
778 fcc->function_handler = ce->constructor;
779 fcc->calling_scope = EG(scope);
780 fcc->called_scope = ce;
781 return 1;
782 } else if (stmt->fetch.cls.ctor_args) {
783 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" TSRMLS_CC);
784 return 0;
785 } else {
786 return 1; /* no ctor no args is also ok */
789 /* }}} */
791 static int make_callable_ex(pdo_stmt_t *stmt, zval *callable, zend_fcall_info * fci, zend_fcall_info_cache * fcc, int num_args TSRMLS_DC) /* {{{ */
793 char *is_callable_error = NULL;
795 if (zend_fcall_info_init(callable, 0, fci, fcc, NULL, &is_callable_error TSRMLS_CC) == FAILURE) {
796 if (is_callable_error) {
797 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", is_callable_error TSRMLS_CC);
798 efree(is_callable_error);
799 } else {
800 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC);
802 return 0;
804 if (is_callable_error) {
805 /* Possible E_STRICT error message */
806 efree(is_callable_error);
809 fci->param_count = num_args; /* probably less */
810 fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
812 return 1;
814 /* }}} */
816 static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
818 zend_fcall_info * fci = &stmt->fetch.cls.fci;
819 zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
821 if (!make_callable_ex(stmt, stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) {
822 return 0;
823 } else {
824 stmt->fetch.func.values = safe_emalloc(sizeof(zval*), stmt->column_count, 0);
825 return 1;
828 /* }}} */
830 static int do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC) /* {{{ */
832 /* fci.size is used to check if it is valid */
833 if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
834 efree(stmt->fetch.cls.fci.params);
835 stmt->fetch.cls.fci.params = NULL;
837 stmt->fetch.cls.fci.size = 0;
838 if (stmt->fetch.cls.ctor_args && free_ctor_agrs) {
839 zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
840 stmt->fetch.cls.ctor_args = NULL;
841 stmt->fetch.cls.fci.param_count = 0;
843 if (stmt->fetch.func.values) {
844 efree(stmt->fetch.func.values);
845 stmt->fetch.func.values = NULL;
847 return 1;
849 /* }}} */
851 /* perform a fetch. If do_bind is true, update any bound columns.
852 * If return_value is not null, store values into it according to HOW. */
853 static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
854 enum pdo_fetch_type how, enum pdo_fetch_orientation ori, long offset, zval *return_all TSRMLS_DC) /* {{{ */
856 int flags, idx, old_arg_count = 0;
857 zend_class_entry *ce = NULL, *old_ce = NULL;
858 zval grp_val, *grp, **pgrp, *retval, *old_ctor_args = NULL;
859 int colno;
861 if (how == PDO_FETCH_USE_DEFAULT) {
862 how = stmt->default_fetch_type;
864 flags = how & PDO_FETCH_FLAGS;
865 how = how & ~PDO_FETCH_FLAGS;
867 if (!do_fetch_common(stmt, ori, offset, do_bind TSRMLS_CC)) {
868 return 0;
871 if (how == PDO_FETCH_BOUND) {
872 RETVAL_TRUE;
873 return 1;
876 if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
877 colno = 1;
878 } else {
879 colno = stmt->fetch.column;
882 if (return_value) {
883 int i = 0;
885 if (how == PDO_FETCH_LAZY) {
886 get_lazy_object(stmt, return_value TSRMLS_CC);
887 return 1;
890 RETVAL_FALSE;
892 switch (how) {
893 case PDO_FETCH_USE_DEFAULT:
894 case PDO_FETCH_ASSOC:
895 case PDO_FETCH_BOTH:
896 case PDO_FETCH_NUM:
897 case PDO_FETCH_NAMED:
898 if (!return_all) {
899 ALLOC_HASHTABLE(return_value->value.ht);
900 zend_hash_init(return_value->value.ht, stmt->column_count, NULL, ZVAL_PTR_DTOR, 0);
901 Z_TYPE_P(return_value) = IS_ARRAY;
902 } else {
903 array_init(return_value);
905 break;
907 case PDO_FETCH_KEY_PAIR:
908 if (stmt->column_count != 2) {
909 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_KEY_PAIR fetch mode requires the result set to contain extactly 2 columns." TSRMLS_CC);
910 return 0;
912 if (!return_all) {
913 array_init(return_value);
915 break;
917 case PDO_FETCH_COLUMN:
918 if (colno >= 0 && colno < stmt->column_count) {
919 if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
920 fetch_value(stmt, return_value, 1, NULL TSRMLS_CC);
921 } else if (flags == PDO_FETCH_GROUP && colno) {
922 fetch_value(stmt, return_value, 0, NULL TSRMLS_CC);
923 } else {
924 fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
926 if (!return_all) {
927 return 1;
928 } else {
929 break;
931 } else {
932 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index" TSRMLS_CC);
934 return 0;
936 case PDO_FETCH_OBJ:
937 object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
938 break;
940 case PDO_FETCH_CLASS:
941 if (flags & PDO_FETCH_CLASSTYPE) {
942 zval val;
943 zend_class_entry **cep;
945 old_ce = stmt->fetch.cls.ce;
946 old_ctor_args = stmt->fetch.cls.ctor_args;
947 old_arg_count = stmt->fetch.cls.fci.param_count;
948 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
950 INIT_PZVAL(&val);
951 fetch_value(stmt, &val, i++, NULL TSRMLS_CC);
952 if (Z_TYPE(val) != IS_NULL) {
953 convert_to_string(&val);
954 if (zend_lookup_class(Z_STRVAL(val), Z_STRLEN(val), &cep TSRMLS_CC) == FAILURE) {
955 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
956 } else {
957 stmt->fetch.cls.ce = *cep;
961 do_fetch_class_prepare(stmt TSRMLS_CC);
962 zval_dtor(&val);
964 ce = stmt->fetch.cls.ce;
965 if (!ce) {
966 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified" TSRMLS_CC);
967 return 0;
969 if ((flags & PDO_FETCH_SERIALIZE) == 0) {
970 object_init_ex(return_value, ce);
971 if (!stmt->fetch.cls.fci.size) {
972 if (!do_fetch_class_prepare(stmt TSRMLS_CC))
974 return 0;
977 if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
978 stmt->fetch.cls.fci.object_ptr = return_value;
979 stmt->fetch.cls.fcc.object_ptr = return_value;
980 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
981 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
982 return 0;
983 } else {
984 if (stmt->fetch.cls.retval_ptr) {
985 zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
990 break;
992 case PDO_FETCH_INTO:
993 if (!stmt->fetch.into) {
994 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified." TSRMLS_CC);
995 return 0;
996 break;
999 Z_TYPE_P(return_value) = IS_OBJECT;
1000 Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE_P(stmt->fetch.into);
1001 Z_OBJ_HT_P(return_value) = Z_OBJ_HT_P(stmt->fetch.into);
1002 zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
1004 if (zend_get_class_entry(return_value TSRMLS_CC) == ZEND_STANDARD_CLASS_DEF_PTR) {
1005 how = PDO_FETCH_OBJ;
1007 break;
1009 case PDO_FETCH_FUNC:
1010 if (!stmt->fetch.func.function) {
1011 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified" TSRMLS_CC);
1012 return 0;
1014 if (!stmt->fetch.func.fci.size) {
1015 if (!do_fetch_func_prepare(stmt TSRMLS_CC))
1017 return 0;
1020 break;
1023 default:
1024 /* shouldn't happen */
1025 return 0;
1028 if (return_all && how != PDO_FETCH_KEY_PAIR) {
1029 INIT_PZVAL(&grp_val);
1030 if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
1031 fetch_value(stmt, &grp_val, colno, NULL TSRMLS_CC);
1032 } else {
1033 fetch_value(stmt, &grp_val, i, NULL TSRMLS_CC);
1035 convert_to_string(&grp_val);
1036 if (how == PDO_FETCH_COLUMN) {
1037 i = stmt->column_count; /* no more data to fetch */
1038 } else {
1039 i++;
1043 for (idx = 0; i < stmt->column_count; i++, idx++) {
1044 zval *val;
1045 MAKE_STD_ZVAL(val);
1046 fetch_value(stmt, val, i, NULL TSRMLS_CC);
1048 switch (how) {
1049 case PDO_FETCH_ASSOC:
1050 add_assoc_zval(return_value, stmt->columns[i].name, val);
1051 break;
1053 case PDO_FETCH_KEY_PAIR:
1055 zval *tmp;
1056 MAKE_STD_ZVAL(tmp);
1057 fetch_value(stmt, tmp, ++i, NULL TSRMLS_CC);
1059 if (Z_TYPE_P(val) == IS_LONG) {
1060 zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL_P(val), &tmp, sizeof(zval *), NULL);
1061 } else {
1062 convert_to_string(val);
1063 zend_symtable_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_STRVAL_P(val), Z_STRLEN_P(val) + 1, &tmp, sizeof(zval *), NULL);
1065 zval_ptr_dtor(&val);
1066 return 1;
1068 break;
1070 case PDO_FETCH_USE_DEFAULT:
1071 case PDO_FETCH_BOTH:
1072 add_assoc_zval(return_value, stmt->columns[i].name, val);
1073 Z_ADDREF_P(val);
1074 add_next_index_zval(return_value, val);
1075 break;
1077 case PDO_FETCH_NAMED:
1078 /* already have an item with this name? */
1080 zval **curr_val = NULL;
1081 if (zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name,
1082 strlen(stmt->columns[i].name)+1,
1083 (void**)&curr_val) == SUCCESS) {
1084 zval *arr;
1085 if (Z_TYPE_PP(curr_val) != IS_ARRAY) {
1086 /* a little bit of black magic here:
1087 * we're creating a new array and swapping it for the
1088 * zval that's already stored in the hash under the name
1089 * we want. We then add that zval to the array.
1090 * This is effectively the same thing as:
1091 * if (!is_array($hash[$name])) {
1092 * $hash[$name] = array($hash[$name]);
1094 * */
1095 zval *cur;
1097 MAKE_STD_ZVAL(arr);
1098 array_init(arr);
1100 cur = *curr_val;
1101 *curr_val = arr;
1103 add_next_index_zval(arr, cur);
1104 } else {
1105 arr = *curr_val;
1107 add_next_index_zval(arr, val);
1108 } else {
1109 add_assoc_zval(return_value, stmt->columns[i].name, val);
1112 break;
1114 case PDO_FETCH_NUM:
1115 add_next_index_zval(return_value, val);
1116 break;
1118 case PDO_FETCH_OBJ:
1119 case PDO_FETCH_INTO:
1120 zend_update_property(NULL, return_value,
1121 stmt->columns[i].name, stmt->columns[i].namelen,
1122 val TSRMLS_CC);
1123 zval_ptr_dtor(&val);
1124 break;
1126 case PDO_FETCH_CLASS:
1127 if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
1128 zend_update_property(ce, return_value,
1129 stmt->columns[i].name, stmt->columns[i].namelen,
1130 val TSRMLS_CC);
1131 zval_ptr_dtor(&val);
1132 } else {
1133 #ifdef MBO_0
1134 php_unserialize_data_t var_hash;
1136 PHP_VAR_UNSERIALIZE_INIT(var_hash);
1137 if (php_var_unserialize(&return_value, (const unsigned char**)&Z_STRVAL_P(val), Z_STRVAL_P(val)+Z_STRLEN_P(val), NULL TSRMLS_CC) == FAILURE) {
1138 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data" TSRMLS_CC);
1139 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1140 return 0;
1142 PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1143 #endif
1144 #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
1145 if (!ce->unserialize) {
1146 zval_ptr_dtor(&val);
1147 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
1148 return 0;
1149 } else if (ce->unserialize(&return_value, ce, Z_TYPE_P(val) == IS_STRING ? Z_STRVAL_P(val) : "", Z_TYPE_P(val) == IS_STRING ? Z_STRLEN_P(val) : 0, NULL TSRMLS_CC) == FAILURE) {
1150 zval_ptr_dtor(&val);
1151 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
1152 zval_dtor(return_value);
1153 ZVAL_NULL(return_value);
1154 return 0;
1155 } else {
1156 zval_ptr_dtor(&val);
1158 #endif
1160 break;
1162 case PDO_FETCH_FUNC:
1163 stmt->fetch.func.values[idx] = val;
1164 stmt->fetch.cls.fci.params[idx] = &stmt->fetch.func.values[idx];
1165 break;
1167 default:
1168 zval_ptr_dtor(&val);
1169 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
1170 return 0;
1171 break;
1175 switch (how) {
1176 case PDO_FETCH_CLASS:
1177 if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
1178 stmt->fetch.cls.fci.object_ptr = return_value;
1179 stmt->fetch.cls.fcc.object_ptr = return_value;
1180 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
1181 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
1182 return 0;
1183 } else {
1184 if (stmt->fetch.cls.retval_ptr) {
1185 zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
1189 if (flags & PDO_FETCH_CLASSTYPE) {
1190 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1191 stmt->fetch.cls.ce = old_ce;
1192 stmt->fetch.cls.ctor_args = old_ctor_args;
1193 stmt->fetch.cls.fci.param_count = old_arg_count;
1195 break;
1197 case PDO_FETCH_FUNC:
1198 stmt->fetch.func.fci.param_count = idx;
1199 stmt->fetch.func.fci.retval_ptr_ptr = &retval;
1200 if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) {
1201 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function" TSRMLS_CC);
1202 return 0;
1203 } else {
1204 if (return_all) {
1205 zval_ptr_dtor(&return_value); /* we don't need that */
1206 return_value = retval;
1207 } else if (retval) {
1208 MAKE_COPY_ZVAL(&retval, return_value);
1209 zval_ptr_dtor(&retval);
1212 while(idx--) {
1213 zval_ptr_dtor(&stmt->fetch.func.values[idx]);
1215 break;
1217 default:
1218 break;
1221 if (return_all) {
1222 if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
1223 add_assoc_zval(return_all, Z_STRVAL(grp_val), return_value);
1224 } else {
1225 if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(grp_val), Z_STRLEN(grp_val)+1, (void**)&pgrp) == FAILURE) {
1226 MAKE_STD_ZVAL(grp);
1227 array_init(grp);
1228 add_assoc_zval(return_all, Z_STRVAL(grp_val), grp);
1229 } else {
1230 grp = *pgrp;
1232 add_next_index_zval(grp, return_value);
1234 zval_dtor(&grp_val);
1239 return 1;
1241 /* }}} */
1243 static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRMLS_DC) /* {{{ */
1245 int flags = mode & PDO_FETCH_FLAGS;
1247 mode = mode & ~PDO_FETCH_FLAGS;
1249 if (mode < 0 || mode > PDO_FETCH__MAX) {
1250 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1251 return 0;
1254 if (mode == PDO_FETCH_USE_DEFAULT) {
1255 flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
1256 mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1259 #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1
1260 if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1261 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO::FETCH_SERIALIZE is not supported in this PHP version" TSRMLS_CC);
1262 return 0;
1264 #endif
1266 switch(mode) {
1267 case PDO_FETCH_FUNC:
1268 if (!fetch_all) {
1269 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()" TSRMLS_CC);
1270 return 0;
1272 return 1;
1274 case PDO_FETCH_LAZY:
1275 if (fetch_all) {
1276 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()" TSRMLS_CC);
1277 return 0;
1279 /* fall through */
1281 default:
1282 if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1283 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
1284 return 0;
1286 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1287 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
1288 return 0;
1290 if (mode >= PDO_FETCH__MAX) {
1291 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1292 return 0;
1294 /* no break; */
1296 case PDO_FETCH_CLASS:
1297 return 1;
1300 /* }}} */
1302 /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
1303 Fetches the next row and returns it, or false if there are no more rows */
1304 static PHP_METHOD(PDOStatement, fetch)
1306 long how = PDO_FETCH_USE_DEFAULT;
1307 long ori = PDO_FETCH_ORI_NEXT;
1308 long off = 0;
1309 PHP_STMT_GET_OBJ;
1311 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
1312 &ori, &off)) {
1313 RETURN_FALSE;
1316 PDO_STMT_CLEAR_ERR();
1318 if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1319 RETURN_FALSE;
1322 if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1323 PDO_HANDLE_STMT_ERR();
1324 RETURN_FALSE;
1327 /* }}} */
1329 /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
1330 Fetches the next row and returns it as an object. */
1331 static PHP_METHOD(PDOStatement, fetchObject)
1333 long how = PDO_FETCH_CLASS;
1334 long ori = PDO_FETCH_ORI_NEXT;
1335 long off = 0;
1336 char *class_name = NULL;
1337 int class_name_len;
1338 zend_class_entry *old_ce;
1339 zval *old_ctor_args, *ctor_args = NULL;
1340 int error = 0, old_arg_count;
1342 PHP_STMT_GET_OBJ;
1344 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!a", &class_name, &class_name_len, &ctor_args)) {
1345 RETURN_FALSE;
1348 PDO_STMT_CLEAR_ERR();
1350 if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1351 RETURN_FALSE;
1354 old_ce = stmt->fetch.cls.ce;
1355 old_ctor_args = stmt->fetch.cls.ctor_args;
1356 old_arg_count = stmt->fetch.cls.fci.param_count;
1358 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1360 if (ctor_args) {
1361 if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1362 ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1363 *stmt->fetch.cls.ctor_args = *ctor_args;
1364 zval_copy_ctor(stmt->fetch.cls.ctor_args);
1365 } else {
1366 stmt->fetch.cls.ctor_args = NULL;
1369 if (class_name && !error) {
1370 stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1372 if (!stmt->fetch.cls.ce) {
1373 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
1374 error = 1;
1376 } else if (!error) {
1377 stmt->fetch.cls.ce = zend_standard_class_def;
1380 if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1381 error = 1;
1383 if (error) {
1384 PDO_HANDLE_STMT_ERR();
1386 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1388 stmt->fetch.cls.ce = old_ce;
1389 stmt->fetch.cls.ctor_args = old_ctor_args;
1390 stmt->fetch.cls.fci.param_count = old_arg_count;
1391 if (error) {
1392 RETURN_FALSE;
1395 /* }}} */
1397 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1398 Returns a data of the specified column in the result set. */
1399 static PHP_METHOD(PDOStatement, fetchColumn)
1401 long col_n = 0;
1402 PHP_STMT_GET_OBJ;
1404 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
1405 RETURN_FALSE;
1408 PDO_STMT_CLEAR_ERR();
1410 if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
1411 PDO_HANDLE_STMT_ERR();
1412 RETURN_FALSE;
1415 fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
1417 /* }}} */
1419 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1420 Returns an array of all of the results. */
1421 static PHP_METHOD(PDOStatement, fetchAll)
1423 long how = PDO_FETCH_USE_DEFAULT;
1424 zval *data, *return_all;
1425 zval *arg2;
1426 zend_class_entry *old_ce;
1427 zval *old_ctor_args, *ctor_args = NULL;
1428 int error = 0, flags, old_arg_count;
1429 PHP_STMT_GET_OBJ;
1431 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
1432 RETURN_FALSE;
1435 if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
1436 RETURN_FALSE;
1439 old_ce = stmt->fetch.cls.ce;
1440 old_ctor_args = stmt->fetch.cls.ctor_args;
1441 old_arg_count = stmt->fetch.cls.fci.param_count;
1443 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1445 switch(how & ~PDO_FETCH_FLAGS) {
1446 case PDO_FETCH_CLASS:
1447 switch(ZEND_NUM_ARGS()) {
1448 case 0:
1449 case 1:
1450 stmt->fetch.cls.ce = zend_standard_class_def;
1451 break;
1452 case 3:
1453 if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1454 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1455 error = 1;
1456 break;
1458 if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1459 ctor_args = NULL;
1461 /* no break */
1462 case 2:
1463 stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
1464 if (Z_TYPE_P(arg2) != IS_STRING) {
1465 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
1466 error = 1;
1467 break;
1468 } else {
1469 stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1470 if (!stmt->fetch.cls.ce) {
1471 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
1472 error = 1;
1473 break;
1477 if (!error) {
1478 do_fetch_class_prepare(stmt TSRMLS_CC);
1480 break;
1482 case PDO_FETCH_FUNC:
1483 switch(ZEND_NUM_ARGS()) {
1484 case 0:
1485 case 1:
1486 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
1487 error = 1;
1488 break;
1489 case 3:
1490 case 2:
1491 stmt->fetch.func.function = arg2;
1492 if (do_fetch_func_prepare(stmt TSRMLS_CC) == 0) {
1493 error = 1;
1495 break;
1497 break;
1499 case PDO_FETCH_COLUMN:
1500 switch(ZEND_NUM_ARGS()) {
1501 case 0:
1502 case 1:
1503 stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1504 break;
1505 case 2:
1506 convert_to_long(arg2);
1507 stmt->fetch.column = Z_LVAL_P(arg2);
1508 break;
1509 case 3:
1510 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
1511 error = 1;
1513 break;
1515 default:
1516 if (ZEND_NUM_ARGS() > 1) {
1517 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
1518 error = 1;
1522 flags = how & PDO_FETCH_FLAGS;
1524 if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1525 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1526 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1529 if (!error) {
1530 PDO_STMT_CLEAR_ERR();
1531 MAKE_STD_ZVAL(data);
1532 if ( (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1533 (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1535 array_init(return_value);
1536 return_all = return_value;
1537 } else {
1538 return_all = 0;
1540 if (!do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
1541 FREE_ZVAL(data);
1542 error = 2;
1545 if (!error) {
1546 if ((how & PDO_FETCH_GROUP)) {
1547 do {
1548 MAKE_STD_ZVAL(data);
1549 } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1550 } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1551 while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1552 } else {
1553 array_init(return_value);
1554 do {
1555 add_next_index_zval(return_value, data);
1556 MAKE_STD_ZVAL(data);
1557 } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
1559 FREE_ZVAL(data);
1562 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1564 stmt->fetch.cls.ce = old_ce;
1565 stmt->fetch.cls.ctor_args = old_ctor_args;
1566 stmt->fetch.cls.fci.param_count = old_arg_count;
1568 if (error) {
1569 PDO_HANDLE_STMT_ERR();
1570 if (error != 2) {
1571 RETURN_FALSE;
1572 } else { /* on no results, return an empty array */
1573 if (Z_TYPE_P(return_value) != IS_ARRAY) {
1574 array_init(return_value);
1576 return;
1580 /* }}} */
1582 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1584 struct pdo_bound_param_data param = {0};
1585 long param_type = PDO_PARAM_STR;
1587 param.paramno = -1;
1589 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1590 "lz|llz!", &param.paramno, &param.parameter, &param_type, &param.max_value_len,
1591 &param.driver_params)) {
1592 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", &param.name,
1593 &param.namelen, &param.parameter, &param_type, &param.max_value_len,
1594 &param.driver_params)) {
1595 return 0;
1599 param.param_type = (int) param_type;
1601 if (param.paramno > 0) {
1602 --param.paramno; /* make it zero-based internally */
1603 } else if (!param.name) {
1604 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1605 return 0;
1608 Z_ADDREF_P(param.parameter);
1609 if (!really_register_bound_param(&param, stmt, is_param TSRMLS_CC)) {
1610 if (param.parameter) {
1611 zval_ptr_dtor(&(param.parameter));
1612 param.parameter = NULL;
1614 return 0;
1616 return 1;
1617 } /* }}} */
1619 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1620 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(). */
1621 static PHP_METHOD(PDOStatement, bindValue)
1623 struct pdo_bound_param_data param = {0};
1624 long param_type = PDO_PARAM_STR;
1625 PHP_STMT_GET_OBJ;
1627 param.paramno = -1;
1629 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1630 "lz/|l", &param.paramno, &param.parameter, &param_type)) {
1631 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", &param.name,
1632 &param.namelen, &param.parameter, &param_type)) {
1633 RETURN_FALSE;
1637 param.param_type = (int) param_type;
1639 if (param.paramno > 0) {
1640 --param.paramno; /* make it zero-based internally */
1641 } else if (!param.name) {
1642 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1643 RETURN_FALSE;
1646 Z_ADDREF_P(param.parameter);
1647 if (!really_register_bound_param(&param, stmt, TRUE TSRMLS_CC)) {
1648 if (param.parameter) {
1649 zval_ptr_dtor(&(param.parameter));
1650 param.parameter = NULL;
1652 RETURN_FALSE;
1654 RETURN_TRUE;
1656 /* }}} */
1659 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1660 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(). */
1661 static PHP_METHOD(PDOStatement, bindParam)
1663 PHP_STMT_GET_OBJ;
1664 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1666 /* }}} */
1668 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1669 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(). */
1670 static PHP_METHOD(PDOStatement, bindColumn)
1672 PHP_STMT_GET_OBJ;
1673 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
1675 /* }}} */
1677 /* {{{ proto int PDOStatement::rowCount()
1678 Returns the number of rows in a result set, or the number of rows affected by the last execute(). It is not always meaningful. */
1679 static PHP_METHOD(PDOStatement, rowCount)
1681 PHP_STMT_GET_OBJ;
1683 RETURN_LONG(stmt->row_count);
1685 /* }}} */
1687 /* {{{ proto string PDOStatement::errorCode()
1688 Fetch the error code associated with the last operation on the statement handle */
1689 static PHP_METHOD(PDOStatement, errorCode)
1691 PHP_STMT_GET_OBJ;
1693 if (zend_parse_parameters_none() == FAILURE) {
1694 return;
1697 if (stmt->error_code[0] == '\0') {
1698 RETURN_NULL();
1701 RETURN_STRING(stmt->error_code, 1);
1703 /* }}} */
1705 /* {{{ proto array PDOStatement::errorInfo()
1706 Fetch extended error information associated with the last operation on the statement handle */
1707 static PHP_METHOD(PDOStatement, errorInfo)
1709 int error_count;
1710 int error_count_diff = 0;
1711 int error_expected_count = 3;
1713 PHP_STMT_GET_OBJ;
1715 if (zend_parse_parameters_none() == FAILURE) {
1716 return;
1719 array_init(return_value);
1720 add_next_index_string(return_value, stmt->error_code, 1);
1722 if (stmt->dbh->methods->fetch_err) {
1723 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
1726 error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1728 if (error_expected_count > error_count) {
1729 int current_index;
1731 error_count_diff = error_expected_count - error_count;
1732 for (current_index = 0; current_index < error_count_diff; current_index++) {
1733 add_next_index_null(return_value);
1737 /* }}} */
1739 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1740 Set an attribute */
1741 static PHP_METHOD(PDOStatement, setAttribute)
1743 long attr;
1744 zval *value = NULL;
1745 PHP_STMT_GET_OBJ;
1747 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
1748 RETURN_FALSE;
1751 if (!stmt->methods->set_attribute) {
1752 goto fail;
1755 PDO_STMT_CLEAR_ERR();
1756 if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
1757 RETURN_TRUE;
1760 fail:
1761 if (!stmt->methods->set_attribute) {
1762 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
1763 } else {
1764 PDO_HANDLE_STMT_ERR();
1766 RETURN_FALSE;
1768 /* }}} */
1770 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1771 Get an attribute */
1773 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr)
1775 switch (attr) {
1776 case PDO_ATTR_EMULATE_PREPARES:
1777 RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1778 return 1;
1780 return 0;
1783 static PHP_METHOD(PDOStatement, getAttribute)
1785 long attr;
1786 PHP_STMT_GET_OBJ;
1788 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
1789 RETURN_FALSE;
1792 if (!stmt->methods->get_attribute) {
1793 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1794 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1795 "This driver doesn't support getting attributes" TSRMLS_CC);
1796 RETURN_FALSE;
1798 return;
1801 PDO_STMT_CLEAR_ERR();
1802 switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
1803 case -1:
1804 PDO_HANDLE_STMT_ERR();
1805 RETURN_FALSE;
1807 case 0:
1808 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1809 /* XXX: should do something better here */
1810 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1811 "driver doesn't support getting that attribute" TSRMLS_CC);
1812 RETURN_FALSE;
1814 return;
1816 default:
1817 return;
1820 /* }}} */
1822 /* {{{ proto int PDOStatement::columnCount()
1823 Returns the number of columns in the result set */
1824 static PHP_METHOD(PDOStatement, columnCount)
1826 PHP_STMT_GET_OBJ;
1827 if (zend_parse_parameters_none() == FAILURE) {
1828 return;
1830 RETURN_LONG(stmt->column_count);
1832 /* }}} */
1834 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1835 Returns meta data for a numbered column */
1836 static PHP_METHOD(PDOStatement, getColumnMeta)
1838 long colno;
1839 struct pdo_column_data *col;
1840 PHP_STMT_GET_OBJ;
1842 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
1843 RETURN_FALSE;
1845 if(colno < 0) {
1846 pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
1847 RETURN_FALSE;
1850 if (!stmt->methods->get_column_meta) {
1851 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
1852 RETURN_FALSE;
1855 PDO_STMT_CLEAR_ERR();
1856 if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
1857 PDO_HANDLE_STMT_ERR();
1858 RETURN_FALSE;
1861 /* add stock items */
1862 col = &stmt->columns[colno];
1863 add_assoc_string(return_value, "name", col->name, 1);
1864 add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1865 add_assoc_long(return_value, "precision", col->precision);
1866 if (col->param_type != PDO_PARAM_ZVAL) {
1867 /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1868 add_assoc_long(return_value, "pdo_type", col->param_type);
1871 /* }}} */
1873 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1874 Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1876 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1878 long mode = PDO_FETCH_BOTH;
1879 int flags, argc = ZEND_NUM_ARGS() - skip;
1880 zval ***args;
1881 zend_class_entry **cep;
1882 int retval;
1884 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1886 switch (stmt->default_fetch_type) {
1887 case PDO_FETCH_INTO:
1888 if (stmt->fetch.into) {
1889 zval_ptr_dtor(&stmt->fetch.into);
1890 stmt->fetch.into = NULL;
1892 break;
1893 default:
1897 stmt->default_fetch_type = PDO_FETCH_BOTH;
1899 if (argc == 0) {
1900 return SUCCESS;
1903 args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
1905 retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1907 if (SUCCESS == retval) {
1908 if (Z_TYPE_PP(args[skip]) != IS_LONG) {
1909 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
1910 retval = FAILURE;
1911 } else {
1912 mode = Z_LVAL_PP(args[skip]);
1913 flags = mode & PDO_FETCH_FLAGS;
1915 retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
1919 if (FAILURE == retval) {
1920 PDO_STMT_CLEAR_ERR();
1921 efree(args);
1922 return FAILURE;
1925 retval = FAILURE;
1926 switch (mode & ~PDO_FETCH_FLAGS) {
1927 case PDO_FETCH_USE_DEFAULT:
1928 case PDO_FETCH_LAZY:
1929 case PDO_FETCH_ASSOC:
1930 case PDO_FETCH_NUM:
1931 case PDO_FETCH_BOTH:
1932 case PDO_FETCH_OBJ:
1933 case PDO_FETCH_BOUND:
1934 case PDO_FETCH_NAMED:
1935 case PDO_FETCH_KEY_PAIR:
1936 if (argc != 1) {
1937 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1938 } else {
1939 retval = SUCCESS;
1941 break;
1943 case PDO_FETCH_COLUMN:
1944 if (argc != 2) {
1945 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument" TSRMLS_CC);
1946 } else if (Z_TYPE_PP(args[skip+1]) != IS_LONG) {
1947 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer" TSRMLS_CC);
1948 } else {
1949 stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
1950 retval = SUCCESS;
1952 break;
1954 case PDO_FETCH_CLASS:
1955 /* Gets its class name from 1st column */
1956 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1957 if (argc != 1) {
1958 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1959 } else {
1960 stmt->fetch.cls.ce = NULL;
1961 retval = SUCCESS;
1963 } else {
1964 if (argc < 2) {
1965 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument" TSRMLS_CC);
1966 } else if (argc > 3) {
1967 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments" TSRMLS_CC);
1968 } else if (Z_TYPE_PP(args[skip+1]) != IS_STRING) {
1969 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string" TSRMLS_CC);
1970 } else {
1971 retval = zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
1972 Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC);
1974 if (SUCCESS == retval && cep && *cep) {
1975 stmt->fetch.cls.ce = *cep;
1980 if (SUCCESS == retval) {
1981 stmt->fetch.cls.ctor_args = NULL;
1982 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
1983 if (stmt->dbh->is_persistent) {
1984 php_error_docref(NULL TSRMLS_CC, 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");
1986 #endif
1987 if (argc == 3) {
1988 if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
1989 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1990 retval = FAILURE;
1991 } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
1992 ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1993 *stmt->fetch.cls.ctor_args = **args[skip+2];
1994 zval_copy_ctor(stmt->fetch.cls.ctor_args);
1998 if (SUCCESS == retval) {
1999 do_fetch_class_prepare(stmt TSRMLS_CC);
2003 break;
2005 case PDO_FETCH_INTO:
2006 if (argc != 2) {
2007 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter" TSRMLS_CC);
2008 } else if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
2009 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object" TSRMLS_CC);
2010 } else {
2011 retval = SUCCESS;
2014 if (SUCCESS == retval) {
2015 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
2016 if (stmt->dbh->is_persistent) {
2017 php_error_docref(NULL TSRMLS_CC, 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");
2019 #endif
2020 MAKE_STD_ZVAL(stmt->fetch.into);
2022 Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
2023 Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
2024 Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
2025 zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
2028 break;
2030 default:
2031 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
2034 if (SUCCESS == retval) {
2035 stmt->default_fetch_type = mode;
2039 * PDO error (if any) has already been raised at this point.
2041 * The error_code is cleared, otherwise the caller will read the
2042 * last error message from the driver.
2045 PDO_STMT_CLEAR_ERR();
2047 efree(args);
2049 return retval;
2052 static PHP_METHOD(PDOStatement, setFetchMode)
2054 PHP_STMT_GET_OBJ;
2056 RETVAL_BOOL(
2057 pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2058 stmt, 0) == SUCCESS ? 1 : 0
2061 /* }}} */
2063 /* {{{ proto bool PDOStatement::nextRowset()
2064 Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
2066 static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
2068 /* un-describe */
2069 if (stmt->columns) {
2070 int i;
2071 struct pdo_column_data *cols = stmt->columns;
2073 for (i = 0; i < stmt->column_count; i++) {
2074 efree(cols[i].name);
2076 efree(stmt->columns);
2077 stmt->columns = NULL;
2078 stmt->column_count = 0;
2081 if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
2082 /* Set the executed flag to 0 to reallocate columns on next execute */
2083 stmt->executed = 0;
2084 return 0;
2087 pdo_stmt_describe_columns(stmt TSRMLS_CC);
2089 return 1;
2092 static PHP_METHOD(PDOStatement, nextRowset)
2094 PHP_STMT_GET_OBJ;
2096 if (!stmt->methods->next_rowset) {
2097 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
2098 RETURN_FALSE;
2101 PDO_STMT_CLEAR_ERR();
2103 if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2104 PDO_HANDLE_STMT_ERR();
2105 RETURN_FALSE;
2108 RETURN_TRUE;
2110 /* }}} */
2112 /* {{{ proto bool PDOStatement::closeCursor()
2113 Closes the cursor, leaving the statement ready for re-execution. */
2114 static PHP_METHOD(PDOStatement, closeCursor)
2116 PHP_STMT_GET_OBJ;
2118 if (!stmt->methods->cursor_closer) {
2119 /* emulate it by fetching and discarding rows */
2120 do {
2121 while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
2123 if (!stmt->methods->next_rowset) {
2124 break;
2127 if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2128 break;
2131 } while (1);
2132 stmt->executed = 0;
2133 RETURN_TRUE;
2136 PDO_STMT_CLEAR_ERR();
2138 if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
2139 PDO_HANDLE_STMT_ERR();
2140 RETURN_FALSE;
2142 stmt->executed = 0;
2143 RETURN_TRUE;
2145 /* }}} */
2147 /* {{{ proto void PDOStatement::debugDumpParams()
2148 A utility for internals hackers to debug parameter internals */
2149 static PHP_METHOD(PDOStatement, debugDumpParams)
2151 php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
2152 HashPosition pos;
2153 struct pdo_bound_param_data *param;
2154 PHP_STMT_GET_OBJ;
2156 if (out == NULL) {
2157 RETURN_FALSE;
2160 php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
2161 stmt->query_stringlen,
2162 stmt->query_stringlen, stmt->query_string);
2164 php_stream_printf(out TSRMLS_CC, "Params: %d\n",
2165 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2167 if (stmt->bound_params) {
2168 zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
2169 while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
2170 (void**)&param, &pos)) {
2171 char *str;
2172 uint len;
2173 ulong num;
2174 int res;
2176 res = zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos);
2177 if (res == HASH_KEY_IS_LONG) {
2178 php_stream_printf(out TSRMLS_CC, "Key: Position #%ld:\n", num);
2179 } else if (res == HASH_KEY_IS_STRING) {
2180 php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
2183 php_stream_printf(out TSRMLS_CC, "paramno=%ld\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
2184 param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
2185 param->is_param,
2186 param->param_type);
2188 zend_hash_move_forward_ex(stmt->bound_params, &pos);
2192 php_stream_close(out);
2194 /* }}} */
2196 /* {{{ proto int PDOStatement::__wakeup()
2197 Prevents use of a PDOStatement instance that has been unserialized */
2198 static PHP_METHOD(PDOStatement, __wakeup)
2200 zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2202 /* }}} */
2204 /* {{{ proto int PDOStatement::__sleep()
2205 Prevents serialization of a PDOStatement instance */
2206 static PHP_METHOD(PDOStatement, __sleep)
2208 zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2210 /* }}} */
2212 const zend_function_entry pdo_dbstmt_functions[] = {
2213 PHP_ME(PDOStatement, execute, arginfo_pdostatement_execute, ZEND_ACC_PUBLIC)
2214 PHP_ME(PDOStatement, fetch, arginfo_pdostatement_fetch, ZEND_ACC_PUBLIC)
2215 PHP_ME(PDOStatement, bindParam, arginfo_pdostatement_bindparam, ZEND_ACC_PUBLIC)
2216 PHP_ME(PDOStatement, bindColumn, arginfo_pdostatement_bindcolumn, ZEND_ACC_PUBLIC)
2217 PHP_ME(PDOStatement, bindValue, arginfo_pdostatement_bindvalue, ZEND_ACC_PUBLIC)
2218 PHP_ME(PDOStatement, rowCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2219 PHP_ME(PDOStatement, fetchColumn, arginfo_pdostatement_fetchcolumn, ZEND_ACC_PUBLIC)
2220 PHP_ME(PDOStatement, fetchAll, arginfo_pdostatement_fetchall, ZEND_ACC_PUBLIC)
2221 PHP_ME(PDOStatement, fetchObject, arginfo_pdostatement_fetchobject, ZEND_ACC_PUBLIC)
2222 PHP_ME(PDOStatement, errorCode, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2223 PHP_ME(PDOStatement, errorInfo, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2224 PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
2225 PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
2226 PHP_ME(PDOStatement, columnCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2227 PHP_ME(PDOStatement, getColumnMeta, arginfo_pdostatement_getcolumnmeta, ZEND_ACC_PUBLIC)
2228 PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
2229 PHP_ME(PDOStatement, nextRowset, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2230 PHP_ME(PDOStatement, closeCursor, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2231 PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2232 PHP_ME(PDOStatement, __wakeup, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2233 PHP_ME(PDOStatement, __sleep, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2234 {NULL, NULL, NULL}
2237 /* {{{ overloaded handlers for PDOStatement class */
2238 static void dbstmt_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
2240 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2242 convert_to_string(member);
2244 if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2245 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2246 } else {
2247 std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
2251 static void dbstmt_prop_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
2253 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2255 convert_to_string(member);
2257 if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2258 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2259 } else {
2260 std_object_handlers.unset_property(object, member, key TSRMLS_CC);
2264 static union _zend_function *dbstmt_method_get(
2265 #if PHP_API_VERSION >= 20041225
2266 zval **object_pp,
2267 #else
2268 zval *object,
2269 #endif
2270 char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
2272 zend_function *fbc = NULL;
2273 char *lc_method_name;
2274 #if PHP_API_VERSION >= 20041225
2275 zval *object = *object_pp;
2276 #endif
2278 lc_method_name = emalloc(method_len + 1);
2279 zend_str_tolower_copy(lc_method_name, method_name, method_len);
2281 if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
2282 method_len+1, (void**)&fbc) == FAILURE) {
2283 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2284 /* instance not created by PDO object */
2285 if (!stmt->dbh) {
2286 goto out;
2288 /* not a pre-defined method, nor a user-defined method; check
2289 * the driver specific methods */
2290 if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2291 if (!pdo_hash_methods(stmt->dbh,
2292 PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
2293 || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2294 goto out;
2298 if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
2299 lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2300 fbc = NULL;
2301 goto out;
2303 /* got it */
2306 out:
2307 efree(lc_method_name);
2308 return fbc;
2311 static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
2313 return -1;
2316 static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
2318 zend_object_value retval;
2319 pdo_stmt_t *stmt;
2320 pdo_stmt_t *old_stmt;
2321 zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
2323 stmt = ecalloc(1, sizeof(*stmt));
2324 zend_object_std_init(&stmt->std, Z_OBJCE_P(zobject) TSRMLS_CC);
2325 object_properties_init(&stmt->std, Z_OBJCE_P(zobject));
2326 stmt->refcount = 1;
2328 old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
2330 retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, (zend_objects_store_clone_t)dbstmt_clone_obj TSRMLS_CC);
2331 retval.handlers = Z_OBJ_HT_P(zobject);
2333 zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
2335 zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
2336 stmt->database_object_handle = old_stmt->database_object_handle;
2338 return retval;
2341 zend_object_handlers pdo_dbstmt_object_handlers;
2342 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
2344 void pdo_stmt_init(TSRMLS_D)
2346 zend_class_entry ce;
2348 INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2349 pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
2350 pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2351 pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2352 zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
2353 zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
2355 memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2356 pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2357 pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2358 pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2359 pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2360 pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
2362 INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2363 pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
2364 pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
2365 pdo_row_ce->create_object = pdo_row_new;
2366 pdo_row_ce->serialize = pdo_row_serialize;
2369 static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
2371 if (stmt->bound_params) {
2372 zend_hash_destroy(stmt->bound_params);
2373 FREE_HASHTABLE(stmt->bound_params);
2374 stmt->bound_params = NULL;
2376 if (stmt->bound_param_map) {
2377 zend_hash_destroy(stmt->bound_param_map);
2378 FREE_HASHTABLE(stmt->bound_param_map);
2379 stmt->bound_param_map = NULL;
2381 if (stmt->bound_columns) {
2382 zend_hash_destroy(stmt->bound_columns);
2383 FREE_HASHTABLE(stmt->bound_columns);
2384 stmt->bound_columns = NULL;
2387 if (stmt->methods && stmt->methods->dtor) {
2388 stmt->methods->dtor(stmt TSRMLS_CC);
2390 if (stmt->query_string) {
2391 efree(stmt->query_string);
2394 if (stmt->columns) {
2395 int i;
2396 struct pdo_column_data *cols = stmt->columns;
2398 for (i = 0; i < stmt->column_count; i++) {
2399 if (cols[i].name) {
2400 efree(cols[i].name);
2401 cols[i].name = NULL;
2404 efree(stmt->columns);
2405 stmt->columns = NULL;
2408 if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
2409 FREE_ZVAL(stmt->fetch.into);
2410 stmt->fetch.into = NULL;
2413 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
2415 zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
2416 if (stmt->dbh) {
2417 php_pdo_dbh_delref(stmt->dbh TSRMLS_CC);
2419 zend_object_std_dtor(&stmt->std TSRMLS_CC);
2420 efree(stmt);
2423 PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
2425 stmt->refcount++;
2428 PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
2430 if (--stmt->refcount == 0) {
2431 free_statement(stmt TSRMLS_CC);
2435 void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2437 php_pdo_stmt_delref(stmt TSRMLS_CC);
2440 zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
2442 zend_object_value retval;
2444 pdo_stmt_t *stmt;
2445 stmt = emalloc(sizeof(*stmt));
2446 memset(stmt, 0, sizeof(*stmt));
2447 zend_object_std_init(&stmt->std, ce TSRMLS_CC);
2448 object_properties_init(&stmt->std, ce);
2449 stmt->refcount = 1;
2451 retval.handle = zend_objects_store_put(stmt, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_dbstmt_free_storage, (zend_objects_store_clone_t)dbstmt_clone_obj TSRMLS_CC);
2452 retval.handlers = &pdo_dbstmt_object_handlers;
2454 return retval;
2456 /* }}} */
2458 /* {{{ statement iterator */
2460 struct php_pdo_iterator {
2461 zend_object_iterator iter;
2462 pdo_stmt_t *stmt;
2463 ulong key;
2464 zval *fetch_ahead;
2467 static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
2469 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2471 if (--I->stmt->refcount == 0) {
2472 free_statement(I->stmt TSRMLS_CC);
2475 if (I->fetch_ahead) {
2476 zval_ptr_dtor(&I->fetch_ahead);
2479 efree(I);
2482 static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
2484 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2486 return I->fetch_ahead ? SUCCESS : FAILURE;
2489 static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
2491 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2493 /* sanity */
2494 if (!I->fetch_ahead) {
2495 *data = NULL;
2496 return;
2499 *data = &I->fetch_ahead;
2502 static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
2503 ulong *int_key TSRMLS_DC)
2505 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2507 if (I->key == (ulong)-1) {
2508 return HASH_KEY_NON_EXISTANT;
2510 *int_key = I->key;
2511 return HASH_KEY_IS_LONG;
2514 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
2516 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2518 if (I->fetch_ahead) {
2519 zval_ptr_dtor(&I->fetch_ahead);
2520 I->fetch_ahead = NULL;
2523 MAKE_STD_ZVAL(I->fetch_ahead);
2525 if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2526 PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2527 pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
2529 PDO_HANDLE_STMT_ERR();
2530 I->key = (ulong)-1;
2531 FREE_ZVAL(I->fetch_ahead);
2532 I->fetch_ahead = NULL;
2534 return;
2537 I->key++;
2540 static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2541 pdo_stmt_iter_dtor,
2542 pdo_stmt_iter_valid,
2543 pdo_stmt_iter_get_data,
2544 pdo_stmt_iter_get_key,
2545 pdo_stmt_iter_move_forwards,
2546 NULL
2549 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
2551 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2552 struct php_pdo_iterator *I;
2554 if (by_ref) {
2555 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2558 I = ecalloc(1, sizeof(*I));
2559 I->iter.funcs = &pdo_stmt_iter_funcs;
2560 I->iter.data = I;
2561 I->stmt = stmt;
2562 stmt->refcount++;
2564 MAKE_STD_ZVAL(I->fetch_ahead);
2565 if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2566 PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2567 PDO_HANDLE_STMT_ERR();
2568 I->key = (ulong)-1;
2569 FREE_ZVAL(I->fetch_ahead);
2570 I->fetch_ahead = NULL;
2573 return &I->iter;
2576 /* }}} */
2578 /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2580 const zend_function_entry pdo_row_functions[] = {
2581 {NULL, NULL, NULL}
2584 static zval *row_prop_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
2586 zval *return_value;
2587 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2588 int colno = -1;
2590 MAKE_STD_ZVAL(return_value);
2591 RETVAL_NULL();
2593 if (stmt) {
2594 if (Z_TYPE_P(member) == IS_LONG) {
2595 if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
2596 fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
2598 } else {
2599 convert_to_string(member);
2600 /* TODO: replace this with a hash of available column names to column
2601 * numbers */
2602 for (colno = 0; colno < stmt->column_count; colno++) {
2603 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2604 fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
2605 Z_SET_REFCOUNT_P(return_value, 0);
2606 Z_UNSET_ISREF_P(return_value);
2607 return return_value;
2610 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2611 zval_ptr_dtor(&return_value);
2612 return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
2617 Z_SET_REFCOUNT_P(return_value, 0);
2618 Z_UNSET_ISREF_P(return_value);
2620 return return_value;
2623 static zval *row_dim_read(zval *object, zval *member, int type TSRMLS_DC)
2625 return row_prop_read(object, member, type, NULL TSRMLS_CC);
2628 static void row_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
2630 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2633 static void row_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
2635 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2638 static int row_prop_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
2640 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2641 int colno = -1;
2643 if (stmt) {
2644 if (Z_TYPE_P(member) == IS_LONG) {
2645 return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
2646 } else {
2647 convert_to_string(member);
2649 /* TODO: replace this with a hash of available column names to column
2650 * numbers */
2651 for (colno = 0; colno < stmt->column_count; colno++) {
2652 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2653 return 1;
2659 return 0;
2662 static int row_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
2664 return row_prop_exists(object, member, check_empty, NULL TSRMLS_CC);
2667 static void row_prop_delete(zval *object, zval *offset, const zend_literal *key TSRMLS_DC)
2669 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2672 static void row_dim_delete(zval *object, zval *offset TSRMLS_DC)
2674 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2677 static HashTable *row_get_properties(zval *object TSRMLS_DC)
2679 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2680 int i;
2682 if (stmt == NULL) {
2683 return NULL;
2686 if (!stmt->std.properties) {
2687 rebuild_object_properties(&stmt->std);
2689 for (i = 0; i < stmt->column_count; i++) {
2690 zval *val;
2691 MAKE_STD_ZVAL(val);
2692 fetch_value(stmt, val, i, NULL TSRMLS_CC);
2694 zend_hash_update(stmt->std.properties, stmt->columns[i].name, stmt->columns[i].namelen + 1, (void *)&val, sizeof(zval *), NULL);
2697 return stmt->std.properties;
2700 static union _zend_function *row_method_get(
2701 #if PHP_API_VERSION >= 20041225
2702 zval **object_pp,
2703 #else
2704 zval *object,
2705 #endif
2706 char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
2708 zend_function *fbc;
2709 char *lc_method_name;
2711 lc_method_name = emalloc(method_len + 1);
2712 zend_str_tolower_copy(lc_method_name, method_name, method_len);
2714 if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2715 efree(lc_method_name);
2716 return NULL;
2719 efree(lc_method_name);
2720 return fbc;
2723 static int row_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
2725 return FAILURE;
2728 static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
2730 static zend_internal_function ctor = {0};
2732 ctor.type = ZEND_INTERNAL_FUNCTION;
2733 ctor.function_name = "__construct";
2734 ctor.scope = pdo_row_ce;
2735 ctor.handler = ZEND_FN(dbstmt_constructor);
2737 return (union _zend_function*)&ctor;
2740 static zend_class_entry *row_get_ce(const zval *object TSRMLS_DC)
2742 return pdo_row_ce;
2745 static int row_get_classname(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
2747 if (parent) {
2748 return FAILURE;
2749 } else {
2750 *class_name = estrndup("PDORow", sizeof("PDORow")-1);
2751 *class_name_len = sizeof("PDORow")-1;
2752 return SUCCESS;
2756 static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
2758 return -1;
2761 zend_object_handlers pdo_row_object_handlers = {
2762 zend_objects_store_add_ref,
2763 zend_objects_store_del_ref,
2764 NULL,
2765 row_prop_read,
2766 row_prop_write,
2767 row_dim_read,
2768 row_dim_write,
2769 NULL,
2770 NULL,
2771 NULL,
2772 row_prop_exists,
2773 row_prop_delete,
2774 row_dim_exists,
2775 row_dim_delete,
2776 row_get_properties,
2777 row_method_get,
2778 row_call_method,
2779 row_get_ctor,
2780 row_get_ce,
2781 row_get_classname,
2782 row_compare,
2783 NULL, /* cast */
2784 NULL
2787 void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2789 if (stmt) {
2790 ZVAL_NULL(&stmt->lazy_object_ref);
2792 if (--stmt->refcount == 0) {
2793 free_statement(stmt TSRMLS_CC);
2798 zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
2800 zend_object_value retval;
2802 retval.handle = zend_objects_store_put(NULL, (zend_objects_store_dtor_t)zend_objects_destroy_object, (zend_objects_free_object_storage_t)pdo_row_free_storage, NULL TSRMLS_CC);
2803 retval.handlers = &pdo_row_object_handlers;
2805 return retval;
2808 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
2810 php_error_docref(NULL TSRMLS_CC, E_WARNING, "PDORow instances may not be serialized");
2811 return FAILURE;
2813 /* }}} */
2816 * Local variables:
2817 * tab-width: 4
2818 * c-basic-offset: 4
2819 * End:
2820 * vim600: noet sw=4 ts=4 fdm=marker
2821 * vim<600: noet sw=4 ts=4