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 +----------------------------------------------------------------------+
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 = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); \
112 if (!stmt->dbh) { \
113 RETURN_FALSE; \
114 } \
115
116 static PHP_FUNCTION(dbstmt_constructor) /* {{{ */
117 {
118 php_error_docref(NULL TSRMLS_CC, E_ERROR, "You should not create a PDOStatement manually");
119 }
120 /* }}} */
121
rewrite_name_to_position(pdo_stmt_t * stmt,struct pdo_bound_param_data * param TSRMLS_DC)122 static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
123 {
124 if (stmt->bound_param_map) {
125 /* rewriting :name to ? style.
126 * We need to fixup the parameter numbers on the parameters.
127 * If we find that a given named parameter has been used twice,
128 * we will raise an error, as we can't be sure that it is safe
129 * to bind multiple parameters onto the same zval in the underlying
130 * driver */
131 char *name;
132 int position = 0;
133
134 if (stmt->named_rewrite_template) {
135 /* this is not an error here */
136 return 1;
137 }
138 if (!param->name) {
139 /* do the reverse; map the parameter number to the name */
140 if (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;
144 }
145 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
146 return 0;
147 }
148
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;
155 }
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;
159 }
160 param->paramno = position;
161 return 1;
162 }
163 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
164 return 0;
165 }
166 return 1;
167 }
168 /* }}} */
169
170 /* trigger callback hook for parameters */
dispatch_param_event(pdo_stmt_t * stmt,enum pdo_param_event event_type TSRMLS_DC)171 static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
172 {
173 int ret = 1, is_param = 1;
174 struct pdo_bound_param_data *param;
175 HashTable *ht;
176
177 if (!stmt->methods->param_hook) {
178 return 1;
179 }
180
181 ht = stmt->bound_params;
182
183 iterate:
184 if (ht) {
185 zend_hash_internal_pointer_reset(ht);
186 while (SUCCESS == zend_hash_get_current_data(ht, (void**)¶m)) {
187 if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
188 ret = 0;
189 break;
190 }
191
192 zend_hash_move_forward(ht);
193 }
194 }
195 if (ret && is_param) {
196 ht = stmt->bound_columns;
197 is_param = 0;
198 goto iterate;
199 }
200
201 return ret;
202 }
203 /* }}} */
204
pdo_stmt_describe_columns(pdo_stmt_t * stmt TSRMLS_DC)205 int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
206 {
207 int col;
208
209 stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
210
211 for (col = 0; col < stmt->column_count; col++) {
212 if (!stmt->methods->describer(stmt, col TSRMLS_CC)) {
213 return 0;
214 }
215
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;
219
220 switch (stmt->dbh->desired_case) {
221 case PDO_CASE_UPPER:
222 while (*s != '\0') {
223 *s = toupper(*s);
224 s++;
225 }
226 break;
227 case PDO_CASE_LOWER:
228 while (*s != '\0') {
229 *s = tolower(*s);
230 s++;
231 }
232 break;
233 default:
234 ;
235 }
236 }
237
238 #if 0
239 /* update the column index on named bound parameters */
240 if (stmt->bound_params) {
241 struct pdo_bound_param_data *param;
242
243 if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
244 stmt->columns[col].namelen, (void**)¶m)) {
245 param->paramno = col;
246 }
247 }
248 #endif
249 if (stmt->bound_columns) {
250 struct pdo_bound_param_data *param;
251
252 if (SUCCESS == zend_hash_find(stmt->bound_columns, stmt->columns[col].name,
253 stmt->columns[col].namelen, (void**)¶m)) {
254 param->paramno = col;
255 }
256 }
257
258 }
259 return 1;
260 }
261 /* }}} */
262
get_lazy_object(pdo_stmt_t * stmt,zval * return_value TSRMLS_DC)263 static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC) /* {{{ */
264 {
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++;
270 }
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);
275 }
276 /* }}} */
277
param_dtor(void * data)278 static void param_dtor(void *data) /* {{{ */
279 {
280 struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
281 TSRMLS_FETCH();
282
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);
286 }
287
288 if (param->name) {
289 efree(param->name);
290 }
291
292 if (param->parameter) {
293 zval_ptr_dtor(&(param->parameter));
294 param->parameter = NULL;
295 }
296 if (param->driver_params) {
297 zval_ptr_dtor(&(param->driver_params));
298 }
299 }
300 /* }}} */
301
really_register_bound_param(struct pdo_bound_param_data * param,pdo_stmt_t * stmt,int is_param TSRMLS_DC)302 static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC) /* {{{ */
303 {
304 HashTable *hash;
305 struct pdo_bound_param_data *pparam = NULL;
306
307 hash = is_param ? stmt->bound_params : stmt->bound_columns;
308
309 if (!hash) {
310 ALLOC_HASHTABLE(hash);
311 zend_hash_init(hash, 13, NULL, param_dtor, 0);
312
313 if (is_param) {
314 stmt->bound_params = hash;
315 } else {
316 stmt->bound_columns = hash;
317 }
318 }
319
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);
327 }
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);
332 }
333
334 param->stmt = stmt;
335 param->is_param = is_param;
336
337 if (param->driver_params) {
338 Z_ADDREF_P(param->driver_params);
339 }
340
341 if (!is_param && param->name && stmt->columns) {
342 /* try to map the name to the column */
343 int i;
344
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;
349 }
350 }
351
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);
359 }
360 }
361
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);
370 }
371 }
372
373 if (is_param && !rewrite_name_to_position(stmt, param TSRMLS_CC)) {
374 if (param->name) {
375 efree(param->name);
376 param->name = NULL;
377 }
378 return 0;
379 }
380
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;
391 }
392 return 0;
393 }
394 }
395
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);
401 }
402
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);
410 }
411
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);
422 }
423 /* param->parameter is freed by hash dtor */
424 param->parameter = NULL;
425 return 0;
426 }
427 }
428 return 1;
429 }
430 /* }}} */
431
432 /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
433 Execute a prepared statement, optionally binding parameters */
PHP_METHOD(PDOStatement,execute)434 static PHP_METHOD(PDOStatement, execute)
435 {
436 zval *input_params = NULL;
437 int ret = 1;
438 PHP_STMT_GET_OBJ;
439
440 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
441 RETURN_FALSE;
442 }
443
444 PDO_STMT_CLEAR_ERR();
445
446 if (input_params) {
447 struct pdo_bound_param_data param;
448 zval **tmp;
449 uint str_length;
450 ulong num_index;
451
452 if (stmt->bound_params) {
453 zend_hash_destroy(stmt->bound_params);
454 FREE_HASHTABLE(stmt->bound_params);
455 stmt->bound_params = NULL;
456 }
457
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(¶m, 0, sizeof(param));
461
462 if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(input_params),
463 ¶m.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;
472 }
473 param.paramno = num_index;
474 }
475
476 param.param_type = PDO_PARAM_STR;
477 MAKE_STD_ZVAL(param.parameter);
478 MAKE_COPY_ZVAL(tmp, param.parameter);
479
480 if (!really_register_bound_param(¶m, stmt, 1 TSRMLS_CC)) {
481 if (param.parameter) {
482 zval_ptr_dtor(¶m.parameter);
483 }
484 RETURN_FALSE;
485 }
486
487 zend_hash_move_forward(Z_ARRVAL_P(input_params));
488 }
489 }
490
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.
495 */
496
497 ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
498 &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
499
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;
509 }
510 } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
511 PDO_HANDLE_STMT_ERR();
512 RETURN_FALSE;
513 }
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);
517 }
518 stmt->active_query_string = NULL;
519 if (!stmt->executed) {
520 /* this is the first execute */
521
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);
526 }
527
528 stmt->executed = 1;
529 }
530
531 if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
532 RETURN_FALSE;
533 }
534
535 RETURN_BOOL(ret);
536 }
537 if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
538 efree(stmt->active_query_string);
539 }
540 stmt->active_query_string = NULL;
541 PDO_HANDLE_STMT_ERR();
542 RETURN_FALSE;
543 }
544 /* }}} */
545
fetch_value(pdo_stmt_t * stmt,zval * dest,int colno,int * type_override TSRMLS_DC)546 static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override TSRMLS_DC) /* {{{ */
547 {
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;
553
554 col = &stmt->columns[colno];
555 type = PDO_PARAM_TYPE(col->param_type);
556 new_type = type_override ? PDO_PARAM_TYPE(*type_override) : type;
557
558 value = NULL;
559 value_len = 0;
560
561 stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
562
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);
571 }
572
573 if (Z_TYPE_P(dest) == IS_NULL) {
574 type = new_type;
575 }
576 break;
577
578 case PDO_PARAM_INT:
579 if (value && value_len == sizeof(long)) {
580 ZVAL_LONG(dest, *(long*)value);
581 break;
582 }
583 ZVAL_NULL(dest);
584 break;
585
586 case PDO_PARAM_BOOL:
587 if (value && value_len == sizeof(zend_bool)) {
588 ZVAL_BOOL(dest, *(zend_bool*)value);
589 break;
590 }
591 ZVAL_NULL(dest);
592 break;
593
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);
607 }
608 php_stream_close((php_stream*)value);
609 } else {
610 php_stream_to_zval((php_stream*)value, dest);
611 }
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;
620 }
621 } else
622 #endif
623 {
624 stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
625 }
626 if (stm) {
627 php_stream_to_zval(stm, dest);
628 } else {
629 ZVAL_NULL(dest);
630 }
631 } else {
632 ZVAL_STRINGL(dest, value, value_len, !caller_frees);
633 if (caller_frees) {
634 caller_frees = 0;
635 }
636 }
637 break;
638
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;
644 }
645 break;
646 }
647 default:
648 ZVAL_NULL(dest);
649 }
650
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:
666 ;
667 }
668 }
669
670 if (caller_frees && value) {
671 efree(value);
672 }
673
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;
680 }
681 }
682
683 if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
684 ZVAL_EMPTY_STRING(dest);
685 }
686 }
687 /* }}} */
688
do_fetch_common(pdo_stmt_t * stmt,enum pdo_fetch_orientation ori,long offset,int do_bind TSRMLS_DC)689 static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
690 long offset, int do_bind TSRMLS_DC) /* {{{ */
691 {
692 if (!stmt->executed) {
693 return 0;
694 }
695
696 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
697 return 0;
698 }
699
700 if (!stmt->methods->fetcher(stmt, ori, offset TSRMLS_CC)) {
701 return 0;
702 }
703
704 /* some drivers might need to describe the columns now */
705 if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
706 return 0;
707 }
708
709 if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
710 return 0;
711 }
712
713 if (do_bind && stmt->bound_columns) {
714 /* update those bound column variables now */
715 struct pdo_bound_param_data *param;
716
717 zend_hash_internal_pointer_reset(stmt->bound_columns);
718 while (SUCCESS == zend_hash_get_current_data(stmt->bound_columns, (void**)¶m)) {
719 if (param->paramno >= 0) {
720 convert_to_string(param->parameter);
721
722 /* delete old value */
723 zval_dtor(param->parameter);
724
725 /* set new value */
726 fetch_value(stmt, param->parameter, param->paramno, (int *)¶m->param_type TSRMLS_CC);
727
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 */
732 }
733
734 zend_hash_move_forward(stmt->bound_columns);
735 }
736 }
737
738 return 1;
739 }
740 /* }}} */
741
do_fetch_class_prepare(pdo_stmt_t * stmt TSRMLS_DC)742 static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
743 {
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;
747
748 fci->size = sizeof(zend_fcall_info);
749
750 if (!ce) {
751 stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
752 ce = ZEND_STANDARD_CLASS_DEF_PTR;
753 }
754
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;
763
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;
770 }
771 } else {
772 fci->param_count = 0;
773 fci->params = NULL;
774 }
775 fci->no_separation = 1;
776
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 */
787 }
788 }
789 /* }}} */
790
make_callable_ex(pdo_stmt_t * stmt,zval * callable,zend_fcall_info * fci,zend_fcall_info_cache * fcc,int num_args TSRMLS_DC)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) /* {{{ */
792 {
793 char *is_callable_error = NULL;
794
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);
801 }
802 return 0;
803 }
804 if (is_callable_error) {
805 /* Possible E_STRICT error message */
806 efree(is_callable_error);
807 }
808
809 fci->param_count = num_args; /* probably less */
810 fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
811
812 return 1;
813 }
814 /* }}} */
815
do_fetch_func_prepare(pdo_stmt_t * stmt TSRMLS_DC)816 static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
817 {
818 zend_fcall_info * fci = &stmt->fetch.cls.fci;
819 zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
820
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;
826 }
827 }
828 /* }}} */
829
do_fetch_opt_finish(pdo_stmt_t * stmt,int free_ctor_agrs TSRMLS_DC)830 static int do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC) /* {{{ */
831 {
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;
836 }
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;
842 }
843 if (stmt->fetch.func.values) {
844 efree(stmt->fetch.func.values);
845 stmt->fetch.func.values = NULL;
846 }
847 return 1;
848 }
849 /* }}} */
850
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. */
do_fetch(pdo_stmt_t * stmt,int do_bind,zval * return_value,enum pdo_fetch_type how,enum pdo_fetch_orientation ori,long offset,zval * return_all TSRMLS_DC)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) /* {{{ */
855 {
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;
860
861 if (how == PDO_FETCH_USE_DEFAULT) {
862 how = stmt->default_fetch_type;
863 }
864 flags = how & PDO_FETCH_FLAGS;
865 how = how & ~PDO_FETCH_FLAGS;
866
867 if (!do_fetch_common(stmt, ori, offset, do_bind TSRMLS_CC)) {
868 return 0;
869 }
870
871 if (how == PDO_FETCH_BOUND) {
872 RETVAL_TRUE;
873 return 1;
874 }
875
876 if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
877 colno = 1;
878 } else {
879 colno = stmt->fetch.column;
880 }
881
882 if (return_value) {
883 int i = 0;
884
885 if (how == PDO_FETCH_LAZY) {
886 get_lazy_object(stmt, return_value TSRMLS_CC);
887 return 1;
888 }
889
890 RETVAL_FALSE;
891
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);
904 }
905 break;
906
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;
911 }
912 if (!return_all) {
913 array_init(return_value);
914 }
915 break;
916
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);
925 }
926 if (!return_all) {
927 return 1;
928 } else {
929 break;
930 }
931 } else {
932 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index" TSRMLS_CC);
933 }
934 return 0;
935
936 case PDO_FETCH_OBJ:
937 object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
938 break;
939
940 case PDO_FETCH_CLASS:
941 if (flags & PDO_FETCH_CLASSTYPE) {
942 zval val;
943 zend_class_entry **cep;
944
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);
949
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;
958 }
959 }
960
961 do_fetch_class_prepare(stmt TSRMLS_CC);
962 zval_dtor(&val);
963 }
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;
968 }
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))
973 {
974 return 0;
975 }
976 }
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);
986 }
987 }
988 }
989 }
990 break;
991
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;
997 }
998
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);
1003
1004 if (zend_get_class_entry(return_value TSRMLS_CC) == ZEND_STANDARD_CLASS_DEF_PTR) {
1005 how = PDO_FETCH_OBJ;
1006 }
1007 break;
1008
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;
1013 }
1014 if (!stmt->fetch.func.fci.size) {
1015 if (!do_fetch_func_prepare(stmt TSRMLS_CC))
1016 {
1017 return 0;
1018 }
1019 }
1020 break;
1021
1022
1023 default:
1024 /* shouldn't happen */
1025 return 0;
1026 }
1027
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);
1034 }
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++;
1040 }
1041 }
1042
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);
1047
1048 switch (how) {
1049 case PDO_FETCH_ASSOC:
1050 add_assoc_zval(return_value, stmt->columns[i].name, val);
1051 break;
1052
1053 case PDO_FETCH_KEY_PAIR:
1054 {
1055 zval *tmp;
1056 MAKE_STD_ZVAL(tmp);
1057 fetch_value(stmt, tmp, ++i, NULL TSRMLS_CC);
1058
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);
1064 }
1065 zval_ptr_dtor(&val);
1066 return 1;
1067 }
1068 break;
1069
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;
1076
1077 case PDO_FETCH_NAMED:
1078 /* already have an item with this name? */
1079 {
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]);
1093 * }
1094 * */
1095 zval *cur;
1096
1097 MAKE_STD_ZVAL(arr);
1098 array_init(arr);
1099
1100 cur = *curr_val;
1101 *curr_val = arr;
1102
1103 add_next_index_zval(arr, cur);
1104 } else {
1105 arr = *curr_val;
1106 }
1107 add_next_index_zval(arr, val);
1108 } else {
1109 add_assoc_zval(return_value, stmt->columns[i].name, val);
1110 }
1111 }
1112 break;
1113
1114 case PDO_FETCH_NUM:
1115 add_next_index_zval(return_value, val);
1116 break;
1117
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;
1125
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;
1135
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;
1141 }
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);
1157 }
1158 #endif
1159 }
1160 break;
1161
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;
1166
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;
1172 }
1173 }
1174
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);
1186 }
1187 }
1188 }
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;
1194 }
1195 break;
1196
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);
1210 }
1211 }
1212 while(idx--) {
1213 zval_ptr_dtor(&stmt->fetch.func.values[idx]);
1214 }
1215 break;
1216
1217 default:
1218 break;
1219 }
1220
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;
1231 }
1232 add_next_index_zval(grp, return_value);
1233 }
1234 zval_dtor(&grp_val);
1235 }
1236
1237 }
1238
1239 return 1;
1240 }
1241 /* }}} */
1242
pdo_stmt_verify_mode(pdo_stmt_t * stmt,long mode,int fetch_all TSRMLS_DC)1243 static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRMLS_DC) /* {{{ */
1244 {
1245 int flags = mode & PDO_FETCH_FLAGS;
1246
1247 mode = mode & ~PDO_FETCH_FLAGS;
1248
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;
1252 }
1253
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;
1257 }
1258
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;
1263 }
1264 #endif
1265
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;
1271 }
1272 return 1;
1273
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;
1278 }
1279 /* fall through */
1280
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;
1285 }
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;
1289 }
1290 if (mode >= PDO_FETCH__MAX) {
1291 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1292 return 0;
1293 }
1294 /* no break; */
1295
1296 case PDO_FETCH_CLASS:
1297 return 1;
1298 }
1299 }
1300 /* }}} */
1301
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 */
PHP_METHOD(PDOStatement,fetch)1304 static PHP_METHOD(PDOStatement, fetch)
1305 {
1306 long how = PDO_FETCH_USE_DEFAULT;
1307 long ori = PDO_FETCH_ORI_NEXT;
1308 long off = 0;
1309 PHP_STMT_GET_OBJ;
1310
1311 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
1312 &ori, &off)) {
1313 RETURN_FALSE;
1314 }
1315
1316 PDO_STMT_CLEAR_ERR();
1317
1318 if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1319 RETURN_FALSE;
1320 }
1321
1322 if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1323 PDO_HANDLE_STMT_ERR();
1324 RETURN_FALSE;
1325 }
1326 }
1327 /* }}} */
1328
1329 /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
1330 Fetches the next row and returns it as an object. */
PHP_METHOD(PDOStatement,fetchObject)1331 static PHP_METHOD(PDOStatement, fetchObject)
1332 {
1333 long how = PDO_FETCH_CLASS;
1334 long ori = PDO_FETCH_ORI_NEXT;
1335 long off = 0;
1336 char *class_name;
1337 int class_name_len;
1338 zend_class_entry *old_ce;
1339 zval *old_ctor_args, *ctor_args;
1340 int error = 0, old_arg_count;
1341
1342 PHP_STMT_GET_OBJ;
1343
1344 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sz",
1345 &class_name, &class_name_len, &ctor_args)) {
1346 RETURN_FALSE;
1347 }
1348
1349 PDO_STMT_CLEAR_ERR();
1350
1351 if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1352 RETURN_FALSE;
1353 }
1354
1355 old_ce = stmt->fetch.cls.ce;
1356 old_ctor_args = stmt->fetch.cls.ctor_args;
1357 old_arg_count = stmt->fetch.cls.fci.param_count;
1358
1359 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1360
1361 switch(ZEND_NUM_ARGS()) {
1362 case 0:
1363 stmt->fetch.cls.ce = zend_standard_class_def;
1364 break;
1365 case 2:
1366 if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1367 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1368 error = 1;
1369 break;
1370 }
1371 if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1372 ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1373 *stmt->fetch.cls.ctor_args = *ctor_args;
1374 zval_copy_ctor(stmt->fetch.cls.ctor_args);
1375 } else {
1376 stmt->fetch.cls.ctor_args = NULL;
1377 }
1378 /* no break */
1379 case 1:
1380 stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1381
1382 if (!stmt->fetch.cls.ce) {
1383 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
1384 error = 1;
1385 break;
1386 }
1387 }
1388
1389 if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1390 error = 1;
1391 }
1392 if (error) {
1393 PDO_HANDLE_STMT_ERR();
1394 }
1395 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1396
1397 stmt->fetch.cls.ce = old_ce;
1398 stmt->fetch.cls.ctor_args = old_ctor_args;
1399 stmt->fetch.cls.fci.param_count = old_arg_count;
1400 if (error) {
1401 RETURN_FALSE;
1402 }
1403 }
1404 /* }}} */
1405
1406 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1407 Returns a data of the specified column in the result set. */
PHP_METHOD(PDOStatement,fetchColumn)1408 static PHP_METHOD(PDOStatement, fetchColumn)
1409 {
1410 long col_n = 0;
1411 PHP_STMT_GET_OBJ;
1412
1413 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
1414 RETURN_FALSE;
1415 }
1416
1417 PDO_STMT_CLEAR_ERR();
1418
1419 if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
1420 PDO_HANDLE_STMT_ERR();
1421 RETURN_FALSE;
1422 }
1423
1424 fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
1425 }
1426 /* }}} */
1427
1428 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1429 Returns an array of all of the results. */
PHP_METHOD(PDOStatement,fetchAll)1430 static PHP_METHOD(PDOStatement, fetchAll)
1431 {
1432 long how = PDO_FETCH_USE_DEFAULT;
1433 zval *data, *return_all;
1434 zval *arg2;
1435 zend_class_entry *old_ce;
1436 zval *old_ctor_args, *ctor_args = NULL;
1437 int error = 0, flags, old_arg_count;
1438 PHP_STMT_GET_OBJ;
1439
1440 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
1441 RETURN_FALSE;
1442 }
1443
1444 if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
1445 RETURN_FALSE;
1446 }
1447
1448 old_ce = stmt->fetch.cls.ce;
1449 old_ctor_args = stmt->fetch.cls.ctor_args;
1450 old_arg_count = stmt->fetch.cls.fci.param_count;
1451
1452 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1453
1454 switch(how & ~PDO_FETCH_FLAGS) {
1455 case PDO_FETCH_CLASS:
1456 switch(ZEND_NUM_ARGS()) {
1457 case 0:
1458 case 1:
1459 stmt->fetch.cls.ce = zend_standard_class_def;
1460 break;
1461 case 3:
1462 if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1463 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1464 error = 1;
1465 break;
1466 }
1467 if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1468 ctor_args = NULL;
1469 }
1470 /* no break */
1471 case 2:
1472 stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
1473 if (Z_TYPE_P(arg2) != IS_STRING) {
1474 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
1475 error = 1;
1476 break;
1477 } else {
1478 stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1479 if (!stmt->fetch.cls.ce) {
1480 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
1481 error = 1;
1482 break;
1483 }
1484 }
1485 }
1486 if (!error) {
1487 do_fetch_class_prepare(stmt TSRMLS_CC);
1488 }
1489 break;
1490
1491 case PDO_FETCH_FUNC:
1492 switch(ZEND_NUM_ARGS()) {
1493 case 0:
1494 case 1:
1495 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
1496 error = 1;
1497 break;
1498 case 3:
1499 case 2:
1500 stmt->fetch.func.function = arg2;
1501 if (do_fetch_func_prepare(stmt TSRMLS_CC) == 0) {
1502 error = 1;
1503 }
1504 break;
1505 }
1506 break;
1507
1508 case PDO_FETCH_COLUMN:
1509 switch(ZEND_NUM_ARGS()) {
1510 case 0:
1511 case 1:
1512 stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1513 break;
1514 case 2:
1515 convert_to_long(arg2);
1516 stmt->fetch.column = Z_LVAL_P(arg2);
1517 break;
1518 case 3:
1519 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
1520 error = 1;
1521 }
1522 break;
1523
1524 default:
1525 if (ZEND_NUM_ARGS() > 1) {
1526 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
1527 error = 1;
1528 }
1529 }
1530
1531 flags = how & PDO_FETCH_FLAGS;
1532
1533 if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1534 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1535 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1536 }
1537
1538 if (!error) {
1539 PDO_STMT_CLEAR_ERR();
1540 MAKE_STD_ZVAL(data);
1541 if ( (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1542 (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1543 ) {
1544 array_init(return_value);
1545 return_all = return_value;
1546 } else {
1547 return_all = 0;
1548 }
1549 if (!do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
1550 FREE_ZVAL(data);
1551 error = 2;
1552 }
1553 }
1554 if (!error) {
1555 if ((how & PDO_FETCH_GROUP)) {
1556 do {
1557 MAKE_STD_ZVAL(data);
1558 } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1559 } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1560 while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1561 } else {
1562 array_init(return_value);
1563 do {
1564 add_next_index_zval(return_value, data);
1565 MAKE_STD_ZVAL(data);
1566 } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
1567 }
1568 FREE_ZVAL(data);
1569 }
1570
1571 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1572
1573 stmt->fetch.cls.ce = old_ce;
1574 stmt->fetch.cls.ctor_args = old_ctor_args;
1575 stmt->fetch.cls.fci.param_count = old_arg_count;
1576
1577 if (error) {
1578 PDO_HANDLE_STMT_ERR();
1579 if (error != 2) {
1580 RETURN_FALSE;
1581 } else { /* on no results, return an empty array */
1582 if (Z_TYPE_P(return_value) != IS_ARRAY) {
1583 array_init(return_value);
1584 }
1585 return;
1586 }
1587 }
1588 }
1589 /* }}} */
1590
register_bound_param(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int is_param)1591 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1592 {
1593 struct pdo_bound_param_data param = {0};
1594 long param_type = PDO_PARAM_STR;
1595
1596 param.paramno = -1;
1597
1598 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1599 "lz|llz!", ¶m.paramno, ¶m.parameter, ¶m_type, ¶m.max_value_len,
1600 ¶m.driver_params)) {
1601 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", ¶m.name,
1602 ¶m.namelen, ¶m.parameter, ¶m_type, ¶m.max_value_len,
1603 ¶m.driver_params)) {
1604 return 0;
1605 }
1606 }
1607
1608 param.param_type = (int) param_type;
1609
1610 if (param.paramno > 0) {
1611 --param.paramno; /* make it zero-based internally */
1612 } else if (!param.name) {
1613 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1614 return 0;
1615 }
1616
1617 Z_ADDREF_P(param.parameter);
1618 if (!really_register_bound_param(¶m, stmt, is_param TSRMLS_CC)) {
1619 if (param.parameter) {
1620 zval_ptr_dtor(&(param.parameter));
1621 param.parameter = NULL;
1622 }
1623 return 0;
1624 }
1625 return 1;
1626 } /* }}} */
1627
1628 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1629 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)1630 static PHP_METHOD(PDOStatement, bindValue)
1631 {
1632 struct pdo_bound_param_data param = {0};
1633 long param_type = PDO_PARAM_STR;
1634 PHP_STMT_GET_OBJ;
1635
1636 param.paramno = -1;
1637
1638 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1639 "lz/|l", ¶m.paramno, ¶m.parameter, ¶m_type)) {
1640 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", ¶m.name,
1641 ¶m.namelen, ¶m.parameter, ¶m_type)) {
1642 RETURN_FALSE;
1643 }
1644 }
1645
1646 param.param_type = (int) param_type;
1647
1648 if (param.paramno > 0) {
1649 --param.paramno; /* make it zero-based internally */
1650 } else if (!param.name) {
1651 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1652 RETURN_FALSE;
1653 }
1654
1655 Z_ADDREF_P(param.parameter);
1656 if (!really_register_bound_param(¶m, stmt, TRUE TSRMLS_CC)) {
1657 if (param.parameter) {
1658 zval_ptr_dtor(&(param.parameter));
1659 param.parameter = NULL;
1660 }
1661 RETURN_FALSE;
1662 }
1663 RETURN_TRUE;
1664 }
1665 /* }}} */
1666
1667
1668 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1669 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)1670 static PHP_METHOD(PDOStatement, bindParam)
1671 {
1672 PHP_STMT_GET_OBJ;
1673 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1674 }
1675 /* }}} */
1676
1677 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1678 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)1679 static PHP_METHOD(PDOStatement, bindColumn)
1680 {
1681 PHP_STMT_GET_OBJ;
1682 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
1683 }
1684 /* }}} */
1685
1686 /* {{{ proto int PDOStatement::rowCount()
1687 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)1688 static PHP_METHOD(PDOStatement, rowCount)
1689 {
1690 PHP_STMT_GET_OBJ;
1691
1692 RETURN_LONG(stmt->row_count);
1693 }
1694 /* }}} */
1695
1696 /* {{{ proto string PDOStatement::errorCode()
1697 Fetch the error code associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorCode)1698 static PHP_METHOD(PDOStatement, errorCode)
1699 {
1700 PHP_STMT_GET_OBJ;
1701
1702 if (zend_parse_parameters_none() == FAILURE) {
1703 return;
1704 }
1705
1706 if (stmt->error_code[0] == '\0') {
1707 RETURN_NULL();
1708 }
1709
1710 RETURN_STRING(stmt->error_code, 1);
1711 }
1712 /* }}} */
1713
1714 /* {{{ proto array PDOStatement::errorInfo()
1715 Fetch extended error information associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorInfo)1716 static PHP_METHOD(PDOStatement, errorInfo)
1717 {
1718 int error_count;
1719 int error_count_diff = 0;
1720 int error_expected_count = 3;
1721
1722 PHP_STMT_GET_OBJ;
1723
1724 if (zend_parse_parameters_none() == FAILURE) {
1725 return;
1726 }
1727
1728 array_init(return_value);
1729 add_next_index_string(return_value, stmt->error_code, 1);
1730
1731 if (stmt->dbh->methods->fetch_err) {
1732 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
1733 }
1734
1735 error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1736
1737 if (error_expected_count > error_count) {
1738 int current_index;
1739
1740 error_count_diff = error_expected_count - error_count;
1741 for (current_index = 0; current_index < error_count_diff; current_index++) {
1742 add_next_index_null(return_value);
1743 }
1744 }
1745 }
1746 /* }}} */
1747
1748 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1749 Set an attribute */
PHP_METHOD(PDOStatement,setAttribute)1750 static PHP_METHOD(PDOStatement, setAttribute)
1751 {
1752 long attr;
1753 zval *value = NULL;
1754 PHP_STMT_GET_OBJ;
1755
1756 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
1757 RETURN_FALSE;
1758 }
1759
1760 if (!stmt->methods->set_attribute) {
1761 goto fail;
1762 }
1763
1764 PDO_STMT_CLEAR_ERR();
1765 if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
1766 RETURN_TRUE;
1767 }
1768
1769 fail:
1770 if (!stmt->methods->set_attribute) {
1771 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
1772 } else {
1773 PDO_HANDLE_STMT_ERR();
1774 }
1775 RETURN_FALSE;
1776 }
1777 /* }}} */
1778
1779 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1780 Get an attribute */
1781
generic_stmt_attr_get(pdo_stmt_t * stmt,zval * return_value,long attr)1782 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr)
1783 {
1784 switch (attr) {
1785 case PDO_ATTR_EMULATE_PREPARES:
1786 RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1787 return 1;
1788 }
1789 return 0;
1790 }
1791
PHP_METHOD(PDOStatement,getAttribute)1792 static PHP_METHOD(PDOStatement, getAttribute)
1793 {
1794 long attr;
1795 PHP_STMT_GET_OBJ;
1796
1797 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
1798 RETURN_FALSE;
1799 }
1800
1801 if (!stmt->methods->get_attribute) {
1802 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1803 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1804 "This driver doesn't support getting attributes" TSRMLS_CC);
1805 RETURN_FALSE;
1806 }
1807 return;
1808 }
1809
1810 PDO_STMT_CLEAR_ERR();
1811 switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
1812 case -1:
1813 PDO_HANDLE_STMT_ERR();
1814 RETURN_FALSE;
1815
1816 case 0:
1817 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1818 /* XXX: should do something better here */
1819 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1820 "driver doesn't support getting that attribute" TSRMLS_CC);
1821 RETURN_FALSE;
1822 }
1823 return;
1824
1825 default:
1826 return;
1827 }
1828 }
1829 /* }}} */
1830
1831 /* {{{ proto int PDOStatement::columnCount()
1832 Returns the number of columns in the result set */
PHP_METHOD(PDOStatement,columnCount)1833 static PHP_METHOD(PDOStatement, columnCount)
1834 {
1835 PHP_STMT_GET_OBJ;
1836 if (zend_parse_parameters_none() == FAILURE) {
1837 return;
1838 }
1839 RETURN_LONG(stmt->column_count);
1840 }
1841 /* }}} */
1842
1843 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1844 Returns meta data for a numbered column */
PHP_METHOD(PDOStatement,getColumnMeta)1845 static PHP_METHOD(PDOStatement, getColumnMeta)
1846 {
1847 long colno;
1848 struct pdo_column_data *col;
1849 PHP_STMT_GET_OBJ;
1850
1851 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
1852 RETURN_FALSE;
1853 }
1854 if(colno < 0) {
1855 pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
1856 RETURN_FALSE;
1857 }
1858
1859 if (!stmt->methods->get_column_meta) {
1860 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
1861 RETURN_FALSE;
1862 }
1863
1864 PDO_STMT_CLEAR_ERR();
1865 if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
1866 PDO_HANDLE_STMT_ERR();
1867 RETURN_FALSE;
1868 }
1869
1870 /* add stock items */
1871 col = &stmt->columns[colno];
1872 add_assoc_string(return_value, "name", col->name, 1);
1873 add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1874 add_assoc_long(return_value, "precision", col->precision);
1875 if (col->param_type != PDO_PARAM_ZVAL) {
1876 /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1877 add_assoc_long(return_value, "pdo_type", col->param_type);
1878 }
1879 }
1880 /* }}} */
1881
1882 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1883 Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1884
pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int skip)1885 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1886 {
1887 long mode = PDO_FETCH_BOTH;
1888 int flags, argc = ZEND_NUM_ARGS() - skip;
1889 zval ***args;
1890 zend_class_entry **cep;
1891 int retval;
1892
1893 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1894
1895 switch (stmt->default_fetch_type) {
1896 case PDO_FETCH_INTO:
1897 if (stmt->fetch.into) {
1898 zval_ptr_dtor(&stmt->fetch.into);
1899 stmt->fetch.into = NULL;
1900 }
1901 break;
1902 default:
1903 ;
1904 }
1905
1906 stmt->default_fetch_type = PDO_FETCH_BOTH;
1907
1908 if (argc == 0) {
1909 return SUCCESS;
1910 }
1911
1912 args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
1913
1914 retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1915
1916 if (SUCCESS == retval) {
1917 if (Z_TYPE_PP(args[skip]) != IS_LONG) {
1918 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
1919 retval = FAILURE;
1920 } else {
1921 mode = Z_LVAL_PP(args[skip]);
1922 flags = mode & PDO_FETCH_FLAGS;
1923
1924 retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
1925 }
1926 }
1927
1928 if (FAILURE == retval) {
1929 PDO_STMT_CLEAR_ERR();
1930 efree(args);
1931 return FAILURE;
1932 }
1933
1934 retval = FAILURE;
1935 switch (mode & ~PDO_FETCH_FLAGS) {
1936 case PDO_FETCH_USE_DEFAULT:
1937 case PDO_FETCH_LAZY:
1938 case PDO_FETCH_ASSOC:
1939 case PDO_FETCH_NUM:
1940 case PDO_FETCH_BOTH:
1941 case PDO_FETCH_OBJ:
1942 case PDO_FETCH_BOUND:
1943 case PDO_FETCH_NAMED:
1944 case PDO_FETCH_KEY_PAIR:
1945 if (argc != 1) {
1946 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1947 } else {
1948 retval = SUCCESS;
1949 }
1950 break;
1951
1952 case PDO_FETCH_COLUMN:
1953 if (argc != 2) {
1954 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument" TSRMLS_CC);
1955 } else if (Z_TYPE_PP(args[skip+1]) != IS_LONG) {
1956 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer" TSRMLS_CC);
1957 } else {
1958 stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
1959 retval = SUCCESS;
1960 }
1961 break;
1962
1963 case PDO_FETCH_CLASS:
1964 /* Gets its class name from 1st column */
1965 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1966 if (argc != 1) {
1967 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1968 } else {
1969 stmt->fetch.cls.ce = NULL;
1970 retval = SUCCESS;
1971 }
1972 } else {
1973 if (argc < 2) {
1974 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument" TSRMLS_CC);
1975 } else if (argc > 3) {
1976 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments" TSRMLS_CC);
1977 } else if (Z_TYPE_PP(args[skip+1]) != IS_STRING) {
1978 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string" TSRMLS_CC);
1979 } else {
1980 retval = zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
1981 Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC);
1982
1983 if (SUCCESS == retval && cep && *cep) {
1984 stmt->fetch.cls.ce = *cep;
1985 }
1986 }
1987 }
1988
1989 if (SUCCESS == retval) {
1990 stmt->fetch.cls.ctor_args = NULL;
1991 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
1992 if (stmt->dbh->is_persistent) {
1993 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");
1994 }
1995 #endif
1996 if (argc == 3) {
1997 if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
1998 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1999 retval = FAILURE;
2000 } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
2001 ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
2002 *stmt->fetch.cls.ctor_args = **args[skip+2];
2003 zval_copy_ctor(stmt->fetch.cls.ctor_args);
2004 }
2005 }
2006
2007 if (SUCCESS == retval) {
2008 do_fetch_class_prepare(stmt TSRMLS_CC);
2009 }
2010 }
2011
2012 break;
2013
2014 case PDO_FETCH_INTO:
2015 if (argc != 2) {
2016 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter" TSRMLS_CC);
2017 } else if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
2018 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object" TSRMLS_CC);
2019 } else {
2020 retval = SUCCESS;
2021 }
2022
2023 if (SUCCESS == retval) {
2024 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
2025 if (stmt->dbh->is_persistent) {
2026 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");
2027 }
2028 #endif
2029 MAKE_STD_ZVAL(stmt->fetch.into);
2030
2031 Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
2032 Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
2033 Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
2034 zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
2035 }
2036
2037 break;
2038
2039 default:
2040 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
2041 }
2042
2043 if (SUCCESS == retval) {
2044 stmt->default_fetch_type = mode;
2045 }
2046
2047 /*
2048 * PDO error (if any) has already been raised at this point.
2049 *
2050 * The error_code is cleared, otherwise the caller will read the
2051 * last error message from the driver.
2052 *
2053 */
2054 PDO_STMT_CLEAR_ERR();
2055
2056 efree(args);
2057
2058 return retval;
2059 }
2060
PHP_METHOD(PDOStatement,setFetchMode)2061 static PHP_METHOD(PDOStatement, setFetchMode)
2062 {
2063 PHP_STMT_GET_OBJ;
2064
2065 RETVAL_BOOL(
2066 pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2067 stmt, 0) == SUCCESS ? 1 : 0
2068 );
2069 }
2070 /* }}} */
2071
2072 /* {{{ proto bool PDOStatement::nextRowset()
2073 Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
2074
pdo_stmt_do_next_rowset(pdo_stmt_t * stmt TSRMLS_DC)2075 static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
2076 {
2077 /* un-describe */
2078 if (stmt->columns) {
2079 int i;
2080 struct pdo_column_data *cols = stmt->columns;
2081
2082 for (i = 0; i < stmt->column_count; i++) {
2083 efree(cols[i].name);
2084 }
2085 efree(stmt->columns);
2086 stmt->columns = NULL;
2087 stmt->column_count = 0;
2088 }
2089
2090 if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
2091 /* Set the executed flag to 0 to reallocate columns on next execute */
2092 stmt->executed = 0;
2093 return 0;
2094 }
2095
2096 pdo_stmt_describe_columns(stmt TSRMLS_CC);
2097
2098 return 1;
2099 }
2100
PHP_METHOD(PDOStatement,nextRowset)2101 static PHP_METHOD(PDOStatement, nextRowset)
2102 {
2103 PHP_STMT_GET_OBJ;
2104
2105 if (!stmt->methods->next_rowset) {
2106 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
2107 RETURN_FALSE;
2108 }
2109
2110 PDO_STMT_CLEAR_ERR();
2111
2112 if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2113 PDO_HANDLE_STMT_ERR();
2114 RETURN_FALSE;
2115 }
2116
2117 RETURN_TRUE;
2118 }
2119 /* }}} */
2120
2121 /* {{{ proto bool PDOStatement::closeCursor()
2122 Closes the cursor, leaving the statement ready for re-execution. */
PHP_METHOD(PDOStatement,closeCursor)2123 static PHP_METHOD(PDOStatement, closeCursor)
2124 {
2125 PHP_STMT_GET_OBJ;
2126
2127 if (!stmt->methods->cursor_closer) {
2128 /* emulate it by fetching and discarding rows */
2129 do {
2130 while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
2131 ;
2132 if (!stmt->methods->next_rowset) {
2133 break;
2134 }
2135
2136 if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2137 break;
2138 }
2139
2140 } while (1);
2141 stmt->executed = 0;
2142 RETURN_TRUE;
2143 }
2144
2145 PDO_STMT_CLEAR_ERR();
2146
2147 if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
2148 PDO_HANDLE_STMT_ERR();
2149 RETURN_FALSE;
2150 }
2151 stmt->executed = 0;
2152 RETURN_TRUE;
2153 }
2154 /* }}} */
2155
2156 /* {{{ proto void PDOStatement::debugDumpParams()
2157 A utility for internals hackers to debug parameter internals */
PHP_METHOD(PDOStatement,debugDumpParams)2158 static PHP_METHOD(PDOStatement, debugDumpParams)
2159 {
2160 php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
2161 HashPosition pos;
2162 struct pdo_bound_param_data *param;
2163 PHP_STMT_GET_OBJ;
2164
2165 if (out == NULL) {
2166 RETURN_FALSE;
2167 }
2168
2169 php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
2170 stmt->query_stringlen,
2171 stmt->query_stringlen, stmt->query_string);
2172
2173 php_stream_printf(out TSRMLS_CC, "Params: %d\n",
2174 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2175
2176 if (stmt->bound_params) {
2177 zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
2178 while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
2179 (void**)¶m, &pos)) {
2180 char *str;
2181 uint len;
2182 ulong num;
2183 int res;
2184
2185 res = zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos);
2186 if (res == HASH_KEY_IS_LONG) {
2187 php_stream_printf(out TSRMLS_CC, "Key: Position #%ld:\n", num);
2188 } else if (res == HASH_KEY_IS_STRING) {
2189 php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
2190 }
2191
2192 php_stream_printf(out TSRMLS_CC, "paramno=%ld\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
2193 param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
2194 param->is_param,
2195 param->param_type);
2196
2197 zend_hash_move_forward_ex(stmt->bound_params, &pos);
2198 }
2199 }
2200
2201 php_stream_close(out);
2202 }
2203 /* }}} */
2204
2205 /* {{{ proto int PDOStatement::__wakeup()
2206 Prevents use of a PDOStatement instance that has been unserialized */
PHP_METHOD(PDOStatement,__wakeup)2207 static PHP_METHOD(PDOStatement, __wakeup)
2208 {
2209 zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2210 }
2211 /* }}} */
2212
2213 /* {{{ proto int PDOStatement::__sleep()
2214 Prevents serialization of a PDOStatement instance */
PHP_METHOD(PDOStatement,__sleep)2215 static PHP_METHOD(PDOStatement, __sleep)
2216 {
2217 zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2218 }
2219 /* }}} */
2220
2221 const zend_function_entry pdo_dbstmt_functions[] = {
2222 PHP_ME(PDOStatement, execute, arginfo_pdostatement_execute, ZEND_ACC_PUBLIC)
2223 PHP_ME(PDOStatement, fetch, arginfo_pdostatement_fetch, ZEND_ACC_PUBLIC)
2224 PHP_ME(PDOStatement, bindParam, arginfo_pdostatement_bindparam, ZEND_ACC_PUBLIC)
2225 PHP_ME(PDOStatement, bindColumn, arginfo_pdostatement_bindcolumn, ZEND_ACC_PUBLIC)
2226 PHP_ME(PDOStatement, bindValue, arginfo_pdostatement_bindvalue, ZEND_ACC_PUBLIC)
2227 PHP_ME(PDOStatement, rowCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2228 PHP_ME(PDOStatement, fetchColumn, arginfo_pdostatement_fetchcolumn, ZEND_ACC_PUBLIC)
2229 PHP_ME(PDOStatement, fetchAll, arginfo_pdostatement_fetchall, ZEND_ACC_PUBLIC)
2230 PHP_ME(PDOStatement, fetchObject, arginfo_pdostatement_fetchobject, ZEND_ACC_PUBLIC)
2231 PHP_ME(PDOStatement, errorCode, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2232 PHP_ME(PDOStatement, errorInfo, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2233 PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
2234 PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
2235 PHP_ME(PDOStatement, columnCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2236 PHP_ME(PDOStatement, getColumnMeta, arginfo_pdostatement_getcolumnmeta, ZEND_ACC_PUBLIC)
2237 PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
2238 PHP_ME(PDOStatement, nextRowset, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2239 PHP_ME(PDOStatement, closeCursor, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2240 PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2241 PHP_ME(PDOStatement, __wakeup, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2242 PHP_ME(PDOStatement, __sleep, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2243 {NULL, NULL, NULL}
2244 };
2245
2246 /* {{{ overloaded handlers for PDOStatement class */
dbstmt_prop_write(zval * object,zval * member,zval * value TSRMLS_DC)2247 static void dbstmt_prop_write(zval *object, zval *member, zval *value TSRMLS_DC)
2248 {
2249 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2250
2251 convert_to_string(member);
2252
2253 if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2254 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2255 } else {
2256 std_object_handlers.write_property(object, member, value TSRMLS_CC);
2257 }
2258 }
2259
dbstmt_prop_delete(zval * object,zval * member TSRMLS_DC)2260 static void dbstmt_prop_delete(zval *object, zval *member TSRMLS_DC)
2261 {
2262 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2263
2264 convert_to_string(member);
2265
2266 if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2267 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2268 } else {
2269 std_object_handlers.unset_property(object, member TSRMLS_CC);
2270 }
2271 }
2272
dbstmt_method_get(zval ** object_pp,char * method_name,int method_len TSRMLS_DC)2273 static union _zend_function *dbstmt_method_get(
2274 #if PHP_API_VERSION >= 20041225
2275 zval **object_pp,
2276 #else
2277 zval *object,
2278 #endif
2279 char *method_name, int method_len TSRMLS_DC)
2280 {
2281 zend_function *fbc = NULL;
2282 char *lc_method_name;
2283 #if PHP_API_VERSION >= 20041225
2284 zval *object = *object_pp;
2285 #endif
2286
2287 lc_method_name = emalloc(method_len + 1);
2288 zend_str_tolower_copy(lc_method_name, method_name, method_len);
2289
2290 if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
2291 method_len+1, (void**)&fbc) == FAILURE) {
2292 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2293 /* instance not created by PDO object */
2294 if (!stmt->dbh) {
2295 goto out;
2296 }
2297 /* not a pre-defined method, nor a user-defined method; check
2298 * the driver specific methods */
2299 if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2300 if (!pdo_hash_methods(stmt->dbh,
2301 PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
2302 || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2303 goto out;
2304 }
2305 }
2306
2307 if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
2308 lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2309 fbc = NULL;
2310 goto out;
2311 }
2312 /* got it */
2313 }
2314
2315 out:
2316 efree(lc_method_name);
2317 return fbc;
2318 }
2319
dbstmt_compare(zval * object1,zval * object2 TSRMLS_DC)2320 static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
2321 {
2322 return -1;
2323 }
2324
dbstmt_clone_obj(zval * zobject TSRMLS_DC)2325 static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
2326 {
2327 zend_object_value retval;
2328 zval *tmp;
2329 pdo_stmt_t *stmt;
2330 pdo_stmt_t *old_stmt;
2331 zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
2332
2333 stmt = ecalloc(1, sizeof(*stmt));
2334 stmt->ce = Z_OBJCE_P(zobject);
2335 stmt->refcount = 1;
2336 ALLOC_HASHTABLE(stmt->properties);
2337 zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2338 zend_hash_copy(stmt->properties, &stmt->ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2339
2340 old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
2341
2342 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);
2343 retval.handlers = Z_OBJ_HT_P(zobject);
2344
2345 zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
2346
2347 zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
2348 stmt->database_object_handle = old_stmt->database_object_handle;
2349
2350 return retval;
2351 }
2352
2353 zend_object_handlers pdo_dbstmt_object_handlers;
2354 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
2355
pdo_stmt_init(TSRMLS_D)2356 void pdo_stmt_init(TSRMLS_D)
2357 {
2358 zend_class_entry ce;
2359
2360 INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2361 pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
2362 pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2363 pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2364 zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
2365 zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
2366
2367 memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2368 pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2369 pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2370 pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2371 pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2372 pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
2373
2374 INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2375 pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
2376 pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
2377 pdo_row_ce->create_object = pdo_row_new;
2378 pdo_row_ce->serialize = pdo_row_serialize;
2379 }
2380
free_statement(pdo_stmt_t * stmt TSRMLS_DC)2381 static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
2382 {
2383 if (stmt->properties) {
2384 zend_hash_destroy(stmt->properties);
2385 efree(stmt->properties);
2386 stmt->properties = NULL;
2387 }
2388
2389 if (stmt->bound_params) {
2390 zend_hash_destroy(stmt->bound_params);
2391 FREE_HASHTABLE(stmt->bound_params);
2392 stmt->bound_params = NULL;
2393 }
2394 if (stmt->bound_param_map) {
2395 zend_hash_destroy(stmt->bound_param_map);
2396 FREE_HASHTABLE(stmt->bound_param_map);
2397 stmt->bound_param_map = NULL;
2398 }
2399 if (stmt->bound_columns) {
2400 zend_hash_destroy(stmt->bound_columns);
2401 FREE_HASHTABLE(stmt->bound_columns);
2402 stmt->bound_columns = NULL;
2403 }
2404
2405 if (stmt->methods && stmt->methods->dtor) {
2406 stmt->methods->dtor(stmt TSRMLS_CC);
2407 }
2408 if (stmt->query_string) {
2409 efree(stmt->query_string);
2410 }
2411
2412 if (stmt->columns) {
2413 int i;
2414 struct pdo_column_data *cols = stmt->columns;
2415
2416 for (i = 0; i < stmt->column_count; i++) {
2417 if (cols[i].name) {
2418 efree(cols[i].name);
2419 cols[i].name = NULL;
2420 }
2421 }
2422 efree(stmt->columns);
2423 stmt->columns = NULL;
2424 }
2425
2426 if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
2427 FREE_ZVAL(stmt->fetch.into);
2428 stmt->fetch.into = NULL;
2429 }
2430
2431 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
2432
2433 zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
2434 if (stmt->dbh) {
2435 php_pdo_dbh_delref(stmt->dbh TSRMLS_CC);
2436 }
2437 efree(stmt);
2438 }
2439
php_pdo_stmt_addref(pdo_stmt_t * stmt TSRMLS_DC)2440 PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
2441 {
2442 stmt->refcount++;
2443 }
2444
php_pdo_stmt_delref(pdo_stmt_t * stmt TSRMLS_DC)2445 PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
2446 {
2447 if (--stmt->refcount == 0) {
2448 free_statement(stmt TSRMLS_CC);
2449 }
2450 }
2451
pdo_dbstmt_free_storage(pdo_stmt_t * stmt TSRMLS_DC)2452 void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2453 {
2454 php_pdo_stmt_delref(stmt TSRMLS_CC);
2455 }
2456
pdo_dbstmt_new(zend_class_entry * ce TSRMLS_DC)2457 zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
2458 {
2459 zend_object_value retval;
2460 zval *tmp;
2461
2462 pdo_stmt_t *stmt;
2463 stmt = emalloc(sizeof(*stmt));
2464 memset(stmt, 0, sizeof(*stmt));
2465 stmt->ce = ce;
2466 stmt->refcount = 1;
2467 ALLOC_HASHTABLE(stmt->properties);
2468 zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2469 zend_hash_copy(stmt->properties, &ce->default_properties, (copy_ctor_func_t) zval_property_ctor, (void *) &tmp, sizeof(zval *));
2470
2471 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);
2472 retval.handlers = &pdo_dbstmt_object_handlers;
2473
2474 return retval;
2475 }
2476 /* }}} */
2477
2478 /* {{{ statement iterator */
2479
2480 struct php_pdo_iterator {
2481 zend_object_iterator iter;
2482 pdo_stmt_t *stmt;
2483 ulong key;
2484 zval *fetch_ahead;
2485 };
2486
pdo_stmt_iter_dtor(zend_object_iterator * iter TSRMLS_DC)2487 static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
2488 {
2489 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2490
2491 if (--I->stmt->refcount == 0) {
2492 free_statement(I->stmt TSRMLS_CC);
2493 }
2494
2495 if (I->fetch_ahead) {
2496 zval_ptr_dtor(&I->fetch_ahead);
2497 }
2498
2499 efree(I);
2500 }
2501
pdo_stmt_iter_valid(zend_object_iterator * iter TSRMLS_DC)2502 static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
2503 {
2504 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2505
2506 return I->fetch_ahead ? SUCCESS : FAILURE;
2507 }
2508
pdo_stmt_iter_get_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2509 static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
2510 {
2511 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2512
2513 /* sanity */
2514 if (!I->fetch_ahead) {
2515 *data = NULL;
2516 return;
2517 }
2518
2519 *data = &I->fetch_ahead;
2520 }
2521
pdo_stmt_iter_get_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)2522 static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
2523 ulong *int_key TSRMLS_DC)
2524 {
2525 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2526
2527 if (I->key == (ulong)-1) {
2528 return HASH_KEY_NON_EXISTANT;
2529 }
2530 *int_key = I->key;
2531 return HASH_KEY_IS_LONG;
2532 }
2533
pdo_stmt_iter_move_forwards(zend_object_iterator * iter TSRMLS_DC)2534 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
2535 {
2536 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2537
2538 if (I->fetch_ahead) {
2539 zval_ptr_dtor(&I->fetch_ahead);
2540 I->fetch_ahead = NULL;
2541 }
2542
2543 MAKE_STD_ZVAL(I->fetch_ahead);
2544
2545 if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2546 PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2547 pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
2548
2549 PDO_HANDLE_STMT_ERR();
2550 I->key = (ulong)-1;
2551 FREE_ZVAL(I->fetch_ahead);
2552 I->fetch_ahead = NULL;
2553
2554 return;
2555 }
2556
2557 I->key++;
2558 }
2559
2560 static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2561 pdo_stmt_iter_dtor,
2562 pdo_stmt_iter_valid,
2563 pdo_stmt_iter_get_data,
2564 pdo_stmt_iter_get_key,
2565 pdo_stmt_iter_move_forwards,
2566 NULL
2567 };
2568
pdo_stmt_iter_get(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2569 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
2570 {
2571 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2572 struct php_pdo_iterator *I;
2573
2574 if (by_ref) {
2575 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2576 }
2577
2578 I = ecalloc(1, sizeof(*I));
2579 I->iter.funcs = &pdo_stmt_iter_funcs;
2580 I->iter.data = I;
2581 I->stmt = stmt;
2582 stmt->refcount++;
2583
2584 MAKE_STD_ZVAL(I->fetch_ahead);
2585 if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2586 PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2587 PDO_HANDLE_STMT_ERR();
2588 I->key = (ulong)-1;
2589 FREE_ZVAL(I->fetch_ahead);
2590 I->fetch_ahead = NULL;
2591 }
2592
2593 return &I->iter;
2594 }
2595
2596 /* }}} */
2597
2598 /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2599
2600 const zend_function_entry pdo_row_functions[] = {
2601 {NULL, NULL, NULL}
2602 };
2603
row_prop_or_dim_read(zval * object,zval * member,int type TSRMLS_DC)2604 static zval *row_prop_or_dim_read(zval *object, zval *member, int type TSRMLS_DC)
2605 {
2606 zval *return_value;
2607 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2608 int colno = -1;
2609
2610 MAKE_STD_ZVAL(return_value);
2611 RETVAL_NULL();
2612
2613 if (stmt) {
2614 if (Z_TYPE_P(member) == IS_LONG) {
2615 if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
2616 fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
2617 }
2618 } else {
2619 convert_to_string(member);
2620 /* TODO: replace this with a hash of available column names to column
2621 * numbers */
2622 for (colno = 0; colno < stmt->column_count; colno++) {
2623 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2624 fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
2625 Z_SET_REFCOUNT_P(return_value, 0);
2626 Z_UNSET_ISREF_P(return_value);
2627 return return_value;
2628 }
2629 }
2630 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2631 zval_ptr_dtor(&return_value);
2632 return std_object_handlers.read_property(object, member, type TSRMLS_CC);
2633 }
2634 }
2635 }
2636
2637 Z_SET_REFCOUNT_P(return_value, 0);
2638 Z_UNSET_ISREF_P(return_value);
2639
2640 return return_value;
2641 }
2642
row_prop_or_dim_write(zval * object,zval * member,zval * value TSRMLS_DC)2643 static void row_prop_or_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
2644 {
2645 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2646 }
2647
row_prop_or_dim_exists(zval * object,zval * member,int check_empty TSRMLS_DC)2648 static int row_prop_or_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
2649 {
2650 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2651 int colno = -1;
2652
2653 if (stmt) {
2654 if (Z_TYPE_P(member) == IS_LONG) {
2655 return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
2656 } else {
2657 convert_to_string(member);
2658
2659 /* TODO: replace this with a hash of available column names to column
2660 * numbers */
2661 for (colno = 0; colno < stmt->column_count; colno++) {
2662 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2663 return 1;
2664 }
2665 }
2666 }
2667 }
2668
2669 return 0;
2670 }
2671
row_prop_or_dim_delete(zval * object,zval * offset TSRMLS_DC)2672 static void row_prop_or_dim_delete(zval *object, zval *offset TSRMLS_DC)
2673 {
2674 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2675 }
2676
row_get_properties(zval * object TSRMLS_DC)2677 static HashTable *row_get_properties(zval *object TSRMLS_DC)
2678 {
2679 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2680 int i;
2681
2682 if (stmt == NULL) {
2683 return NULL;
2684 }
2685
2686 for (i = 0; i < stmt->column_count; i++) {
2687 zval *val;
2688 MAKE_STD_ZVAL(val);
2689 fetch_value(stmt, val, i, NULL TSRMLS_CC);
2690
2691 zend_hash_update(stmt->properties, stmt->columns[i].name, stmt->columns[i].namelen + 1, (void *)&val, sizeof(zval *), NULL);
2692 }
2693
2694 return stmt->properties;
2695 }
2696
row_method_get(zval ** object_pp,char * method_name,int method_len TSRMLS_DC)2697 static union _zend_function *row_method_get(
2698 #if PHP_API_VERSION >= 20041225
2699 zval **object_pp,
2700 #else
2701 zval *object,
2702 #endif
2703 char *method_name, int method_len TSRMLS_DC)
2704 {
2705 zend_function *fbc;
2706 char *lc_method_name;
2707
2708 lc_method_name = emalloc(method_len + 1);
2709 zend_str_tolower_copy(lc_method_name, method_name, method_len);
2710
2711 if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2712 efree(lc_method_name);
2713 return NULL;
2714 }
2715
2716 efree(lc_method_name);
2717 return fbc;
2718 }
2719
row_call_method(char * method,INTERNAL_FUNCTION_PARAMETERS)2720 static int row_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
2721 {
2722 return FAILURE;
2723 }
2724
row_get_ctor(zval * object TSRMLS_DC)2725 static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
2726 {
2727 static zend_internal_function ctor = {0};
2728
2729 ctor.type = ZEND_INTERNAL_FUNCTION;
2730 ctor.function_name = "__construct";
2731 ctor.scope = pdo_row_ce;
2732 ctor.handler = ZEND_FN(dbstmt_constructor);
2733
2734 return (union _zend_function*)&ctor;
2735 }
2736
row_get_ce(const zval * object TSRMLS_DC)2737 static zend_class_entry *row_get_ce(const zval *object TSRMLS_DC)
2738 {
2739 return pdo_row_ce;
2740 }
2741
row_get_classname(const zval * object,char ** class_name,zend_uint * class_name_len,int parent TSRMLS_DC)2742 static int row_get_classname(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
2743 {
2744 if (parent) {
2745 return FAILURE;
2746 } else {
2747 *class_name = estrndup("PDORow", sizeof("PDORow")-1);
2748 *class_name_len = sizeof("PDORow")-1;
2749 return SUCCESS;
2750 }
2751 }
2752
row_compare(zval * object1,zval * object2 TSRMLS_DC)2753 static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
2754 {
2755 return -1;
2756 }
2757
2758 zend_object_handlers pdo_row_object_handlers = {
2759 ZEND_OBJECTS_STORE_HANDLERS,
2760 row_prop_or_dim_read,
2761 row_prop_or_dim_write,
2762 row_prop_or_dim_read,
2763 row_prop_or_dim_write,
2764 NULL,
2765 NULL,
2766 NULL,
2767 row_prop_or_dim_exists,
2768 row_prop_or_dim_delete,
2769 row_prop_or_dim_exists,
2770 row_prop_or_dim_delete,
2771 row_get_properties,
2772 row_method_get,
2773 row_call_method,
2774 row_get_ctor,
2775 row_get_ce,
2776 row_get_classname,
2777 row_compare,
2778 NULL, /* cast */
2779 NULL
2780 };
2781
pdo_row_free_storage(pdo_stmt_t * stmt TSRMLS_DC)2782 void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2783 {
2784 if (stmt) {
2785 ZVAL_NULL(&stmt->lazy_object_ref);
2786
2787 if (--stmt->refcount == 0) {
2788 free_statement(stmt TSRMLS_CC);
2789 }
2790 }
2791 }
2792
pdo_row_new(zend_class_entry * ce TSRMLS_DC)2793 zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
2794 {
2795 zend_object_value retval;
2796
2797 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);
2798 retval.handlers = &pdo_row_object_handlers;
2799
2800 return retval;
2801 }
2802
pdo_row_serialize(zval * object,unsigned char ** buffer,zend_uint * buf_len,zend_serialize_data * data TSRMLS_DC)2803 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
2804 {
2805 php_error_docref(NULL TSRMLS_CC, E_WARNING, "PDORow instances may not be serialized");
2806 return FAILURE;
2807 }
2808 /* }}} */
2809
2810 /*
2811 * Local variables:
2812 * tab-width: 4
2813 * c-basic-offset: 4
2814 * End:
2815 * vim600: noet sw=4 ts=4 fdm=marker
2816 * vim<600: noet sw=4 ts=4
2817 */
2818