1 /*
2 +----------------------------------------------------------------------+
3 | PHP Version 5 |
4 +----------------------------------------------------------------------+
5 | Copyright (c) 1997-2015 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 (!ce->unserialize) {
1145 zval_ptr_dtor(&val);
1146 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
1147 return 0;
1148 } else if (ce->unserialize(&return_value, ce, (unsigned char *)(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) {
1149 zval_ptr_dtor(&val);
1150 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
1151 zval_dtor(return_value);
1152 ZVAL_NULL(return_value);
1153 return 0;
1154 } else {
1155 zval_ptr_dtor(&val);
1156 }
1157 }
1158 break;
1159
1160 case PDO_FETCH_FUNC:
1161 stmt->fetch.func.values[idx] = val;
1162 stmt->fetch.cls.fci.params[idx] = &stmt->fetch.func.values[idx];
1163 break;
1164
1165 default:
1166 zval_ptr_dtor(&val);
1167 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
1168 return 0;
1169 break;
1170 }
1171 }
1172
1173 switch (how) {
1174 case PDO_FETCH_CLASS:
1175 if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
1176 stmt->fetch.cls.fci.object_ptr = return_value;
1177 stmt->fetch.cls.fcc.object_ptr = return_value;
1178 if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
1179 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
1180 return 0;
1181 } else {
1182 if (stmt->fetch.cls.retval_ptr) {
1183 zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
1184 }
1185 }
1186 }
1187 if (flags & PDO_FETCH_CLASSTYPE) {
1188 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1189 stmt->fetch.cls.ce = old_ce;
1190 stmt->fetch.cls.ctor_args = old_ctor_args;
1191 stmt->fetch.cls.fci.param_count = old_arg_count;
1192 }
1193 break;
1194
1195 case PDO_FETCH_FUNC:
1196 stmt->fetch.func.fci.param_count = idx;
1197 stmt->fetch.func.fci.retval_ptr_ptr = &retval;
1198 if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) {
1199 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function" TSRMLS_CC);
1200 return 0;
1201 } else {
1202 if (return_all) {
1203 zval_ptr_dtor(&return_value); /* we don't need that */
1204 return_value = retval;
1205 } else if (retval) {
1206 MAKE_COPY_ZVAL(&retval, return_value);
1207 zval_ptr_dtor(&retval);
1208 }
1209 }
1210 while(idx--) {
1211 zval_ptr_dtor(&stmt->fetch.func.values[idx]);
1212 }
1213 break;
1214
1215 default:
1216 break;
1217 }
1218
1219 if (return_all) {
1220 if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
1221 add_assoc_zval(return_all, Z_STRVAL(grp_val), return_value);
1222 } else {
1223 if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(grp_val), Z_STRLEN(grp_val)+1, (void**)&pgrp) == FAILURE) {
1224 MAKE_STD_ZVAL(grp);
1225 array_init(grp);
1226 add_assoc_zval(return_all, Z_STRVAL(grp_val), grp);
1227 } else {
1228 grp = *pgrp;
1229 }
1230 add_next_index_zval(grp, return_value);
1231 }
1232 zval_dtor(&grp_val);
1233 }
1234
1235 }
1236
1237 return 1;
1238 }
1239 /* }}} */
1240
pdo_stmt_verify_mode(pdo_stmt_t * stmt,long mode,int fetch_all TSRMLS_DC)1241 static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRMLS_DC) /* {{{ */
1242 {
1243 int flags = mode & PDO_FETCH_FLAGS;
1244
1245 mode = mode & ~PDO_FETCH_FLAGS;
1246
1247 if (mode < 0 || mode > PDO_FETCH__MAX) {
1248 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1249 return 0;
1250 }
1251
1252 if (mode == PDO_FETCH_USE_DEFAULT) {
1253 flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
1254 mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1255 }
1256
1257 switch(mode) {
1258 case PDO_FETCH_FUNC:
1259 if (!fetch_all) {
1260 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()" TSRMLS_CC);
1261 return 0;
1262 }
1263 return 1;
1264
1265 case PDO_FETCH_LAZY:
1266 if (fetch_all) {
1267 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()" TSRMLS_CC);
1268 return 0;
1269 }
1270 /* fall through */
1271
1272 default:
1273 if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1274 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
1275 return 0;
1276 }
1277 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1278 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
1279 return 0;
1280 }
1281 if (mode >= PDO_FETCH__MAX) {
1282 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1283 return 0;
1284 }
1285 /* no break; */
1286
1287 case PDO_FETCH_CLASS:
1288 return 1;
1289 }
1290 }
1291 /* }}} */
1292
1293 /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
1294 Fetches the next row and returns it, or false if there are no more rows */
PHP_METHOD(PDOStatement,fetch)1295 static PHP_METHOD(PDOStatement, fetch)
1296 {
1297 long how = PDO_FETCH_USE_DEFAULT;
1298 long ori = PDO_FETCH_ORI_NEXT;
1299 long off = 0;
1300 PHP_STMT_GET_OBJ;
1301
1302 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
1303 &ori, &off)) {
1304 RETURN_FALSE;
1305 }
1306
1307 PDO_STMT_CLEAR_ERR();
1308
1309 if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1310 RETURN_FALSE;
1311 }
1312
1313 if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1314 PDO_HANDLE_STMT_ERR();
1315 RETURN_FALSE;
1316 }
1317 }
1318 /* }}} */
1319
1320 /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
1321 Fetches the next row and returns it as an object. */
PHP_METHOD(PDOStatement,fetchObject)1322 static PHP_METHOD(PDOStatement, fetchObject)
1323 {
1324 long how = PDO_FETCH_CLASS;
1325 long ori = PDO_FETCH_ORI_NEXT;
1326 long off = 0;
1327 char *class_name = NULL;
1328 int class_name_len;
1329 zend_class_entry *old_ce;
1330 zval *old_ctor_args, *ctor_args = NULL;
1331 int error = 0, old_arg_count;
1332
1333 PHP_STMT_GET_OBJ;
1334
1335 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|s!a", &class_name, &class_name_len, &ctor_args)) {
1336 RETURN_FALSE;
1337 }
1338
1339 PDO_STMT_CLEAR_ERR();
1340
1341 if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1342 RETURN_FALSE;
1343 }
1344
1345 old_ce = stmt->fetch.cls.ce;
1346 old_ctor_args = stmt->fetch.cls.ctor_args;
1347 old_arg_count = stmt->fetch.cls.fci.param_count;
1348
1349 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1350
1351 if (ctor_args) {
1352 if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1353 ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1354 *stmt->fetch.cls.ctor_args = *ctor_args;
1355 zval_copy_ctor(stmt->fetch.cls.ctor_args);
1356 } else {
1357 stmt->fetch.cls.ctor_args = NULL;
1358 }
1359 }
1360 if (class_name && !error) {
1361 stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1362
1363 if (!stmt->fetch.cls.ce) {
1364 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
1365 error = 1;
1366 }
1367 } else if (!error) {
1368 stmt->fetch.cls.ce = zend_standard_class_def;
1369 }
1370
1371 if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1372 error = 1;
1373 }
1374 if (error) {
1375 PDO_HANDLE_STMT_ERR();
1376 }
1377 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1378
1379 stmt->fetch.cls.ce = old_ce;
1380 stmt->fetch.cls.ctor_args = old_ctor_args;
1381 stmt->fetch.cls.fci.param_count = old_arg_count;
1382 if (error) {
1383 RETURN_FALSE;
1384 }
1385 }
1386 /* }}} */
1387
1388 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1389 Returns a data of the specified column in the result set. */
PHP_METHOD(PDOStatement,fetchColumn)1390 static PHP_METHOD(PDOStatement, fetchColumn)
1391 {
1392 long col_n = 0;
1393 PHP_STMT_GET_OBJ;
1394
1395 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
1396 RETURN_FALSE;
1397 }
1398
1399 PDO_STMT_CLEAR_ERR();
1400
1401 if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
1402 PDO_HANDLE_STMT_ERR();
1403 RETURN_FALSE;
1404 }
1405
1406 fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
1407 }
1408 /* }}} */
1409
1410 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1411 Returns an array of all of the results. */
PHP_METHOD(PDOStatement,fetchAll)1412 static PHP_METHOD(PDOStatement, fetchAll)
1413 {
1414 long how = PDO_FETCH_USE_DEFAULT;
1415 zval *data, *return_all;
1416 zval *arg2;
1417 zend_class_entry *old_ce;
1418 zval *old_ctor_args, *ctor_args = NULL;
1419 int error = 0, flags, old_arg_count;
1420 PHP_STMT_GET_OBJ;
1421
1422 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
1423 RETURN_FALSE;
1424 }
1425
1426 if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
1427 RETURN_FALSE;
1428 }
1429
1430 old_ce = stmt->fetch.cls.ce;
1431 old_ctor_args = stmt->fetch.cls.ctor_args;
1432 old_arg_count = stmt->fetch.cls.fci.param_count;
1433
1434 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1435
1436 switch(how & ~PDO_FETCH_FLAGS) {
1437 case PDO_FETCH_CLASS:
1438 switch(ZEND_NUM_ARGS()) {
1439 case 0:
1440 case 1:
1441 stmt->fetch.cls.ce = zend_standard_class_def;
1442 break;
1443 case 3:
1444 if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1445 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1446 error = 1;
1447 break;
1448 }
1449 if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1450 ctor_args = NULL;
1451 }
1452 /* no break */
1453 case 2:
1454 stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
1455 if (Z_TYPE_P(arg2) != IS_STRING) {
1456 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
1457 error = 1;
1458 break;
1459 } else {
1460 stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1461 if (!stmt->fetch.cls.ce) {
1462 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
1463 error = 1;
1464 break;
1465 }
1466 }
1467 }
1468 if (!error) {
1469 do_fetch_class_prepare(stmt TSRMLS_CC);
1470 }
1471 break;
1472
1473 case PDO_FETCH_FUNC:
1474 switch(ZEND_NUM_ARGS()) {
1475 case 0:
1476 case 1:
1477 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
1478 error = 1;
1479 break;
1480 case 3:
1481 case 2:
1482 stmt->fetch.func.function = arg2;
1483 if (do_fetch_func_prepare(stmt TSRMLS_CC) == 0) {
1484 error = 1;
1485 }
1486 break;
1487 }
1488 break;
1489
1490 case PDO_FETCH_COLUMN:
1491 switch(ZEND_NUM_ARGS()) {
1492 case 0:
1493 case 1:
1494 stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1495 break;
1496 case 2:
1497 convert_to_long(arg2);
1498 stmt->fetch.column = Z_LVAL_P(arg2);
1499 break;
1500 case 3:
1501 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
1502 error = 1;
1503 }
1504 break;
1505
1506 default:
1507 if (ZEND_NUM_ARGS() > 1) {
1508 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
1509 error = 1;
1510 }
1511 }
1512
1513 flags = how & PDO_FETCH_FLAGS;
1514
1515 if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1516 flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1517 how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1518 }
1519
1520 if (!error) {
1521 PDO_STMT_CLEAR_ERR();
1522 MAKE_STD_ZVAL(data);
1523 if ( (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1524 (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1525 ) {
1526 array_init(return_value);
1527 return_all = return_value;
1528 } else {
1529 return_all = 0;
1530 }
1531 if (!do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
1532 FREE_ZVAL(data);
1533 error = 2;
1534 }
1535 }
1536 if (!error) {
1537 if ((how & PDO_FETCH_GROUP)) {
1538 do {
1539 MAKE_STD_ZVAL(data);
1540 } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1541 } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1542 while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1543 } else {
1544 array_init(return_value);
1545 do {
1546 add_next_index_zval(return_value, data);
1547 MAKE_STD_ZVAL(data);
1548 } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
1549 }
1550 FREE_ZVAL(data);
1551 }
1552
1553 do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1554
1555 stmt->fetch.cls.ce = old_ce;
1556 stmt->fetch.cls.ctor_args = old_ctor_args;
1557 stmt->fetch.cls.fci.param_count = old_arg_count;
1558
1559 if (error) {
1560 PDO_HANDLE_STMT_ERR();
1561 if (error != 2) {
1562 RETURN_FALSE;
1563 } else { /* on no results, return an empty array */
1564 if (Z_TYPE_P(return_value) != IS_ARRAY) {
1565 array_init(return_value);
1566 }
1567 return;
1568 }
1569 }
1570 }
1571 /* }}} */
1572
register_bound_param(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int is_param)1573 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1574 {
1575 struct pdo_bound_param_data param = {0};
1576 long param_type = PDO_PARAM_STR;
1577
1578 param.paramno = -1;
1579
1580 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1581 "lz|llz!", ¶m.paramno, ¶m.parameter, ¶m_type, ¶m.max_value_len,
1582 ¶m.driver_params)) {
1583 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", ¶m.name,
1584 ¶m.namelen, ¶m.parameter, ¶m_type, ¶m.max_value_len,
1585 ¶m.driver_params)) {
1586 return 0;
1587 }
1588 }
1589
1590 param.param_type = (int) param_type;
1591
1592 if (param.paramno > 0) {
1593 --param.paramno; /* make it zero-based internally */
1594 } else if (!param.name) {
1595 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1596 return 0;
1597 }
1598
1599 Z_ADDREF_P(param.parameter);
1600 if (!really_register_bound_param(¶m, stmt, is_param TSRMLS_CC)) {
1601 if (param.parameter) {
1602 zval_ptr_dtor(&(param.parameter));
1603 param.parameter = NULL;
1604 }
1605 return 0;
1606 }
1607 return 1;
1608 } /* }}} */
1609
1610 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1611 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)1612 static PHP_METHOD(PDOStatement, bindValue)
1613 {
1614 struct pdo_bound_param_data param = {0};
1615 long param_type = PDO_PARAM_STR;
1616 PHP_STMT_GET_OBJ;
1617
1618 param.paramno = -1;
1619
1620 if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1621 "lz/|l", ¶m.paramno, ¶m.parameter, ¶m_type)) {
1622 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", ¶m.name,
1623 ¶m.namelen, ¶m.parameter, ¶m_type)) {
1624 RETURN_FALSE;
1625 }
1626 }
1627
1628 param.param_type = (int) param_type;
1629
1630 if (param.paramno > 0) {
1631 --param.paramno; /* make it zero-based internally */
1632 } else if (!param.name) {
1633 pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1634 RETURN_FALSE;
1635 }
1636
1637 Z_ADDREF_P(param.parameter);
1638 if (!really_register_bound_param(¶m, stmt, TRUE TSRMLS_CC)) {
1639 if (param.parameter) {
1640 zval_ptr_dtor(&(param.parameter));
1641 param.parameter = NULL;
1642 }
1643 RETURN_FALSE;
1644 }
1645 RETURN_TRUE;
1646 }
1647 /* }}} */
1648
1649
1650 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1651 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)1652 static PHP_METHOD(PDOStatement, bindParam)
1653 {
1654 PHP_STMT_GET_OBJ;
1655 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1656 }
1657 /* }}} */
1658
1659 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1660 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)1661 static PHP_METHOD(PDOStatement, bindColumn)
1662 {
1663 PHP_STMT_GET_OBJ;
1664 RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
1665 }
1666 /* }}} */
1667
1668 /* {{{ proto int PDOStatement::rowCount()
1669 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)1670 static PHP_METHOD(PDOStatement, rowCount)
1671 {
1672 PHP_STMT_GET_OBJ;
1673
1674 RETURN_LONG(stmt->row_count);
1675 }
1676 /* }}} */
1677
1678 /* {{{ proto string PDOStatement::errorCode()
1679 Fetch the error code associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorCode)1680 static PHP_METHOD(PDOStatement, errorCode)
1681 {
1682 PHP_STMT_GET_OBJ;
1683
1684 if (zend_parse_parameters_none() == FAILURE) {
1685 return;
1686 }
1687
1688 if (stmt->error_code[0] == '\0') {
1689 RETURN_NULL();
1690 }
1691
1692 RETURN_STRING(stmt->error_code, 1);
1693 }
1694 /* }}} */
1695
1696 /* {{{ proto array PDOStatement::errorInfo()
1697 Fetch extended error information associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorInfo)1698 static PHP_METHOD(PDOStatement, errorInfo)
1699 {
1700 int error_count;
1701 int error_count_diff = 0;
1702 int error_expected_count = 3;
1703
1704 PHP_STMT_GET_OBJ;
1705
1706 if (zend_parse_parameters_none() == FAILURE) {
1707 return;
1708 }
1709
1710 array_init(return_value);
1711 add_next_index_string(return_value, stmt->error_code, 1);
1712
1713 if (stmt->dbh->methods->fetch_err) {
1714 stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
1715 }
1716
1717 error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1718
1719 if (error_expected_count > error_count) {
1720 int current_index;
1721
1722 error_count_diff = error_expected_count - error_count;
1723 for (current_index = 0; current_index < error_count_diff; current_index++) {
1724 add_next_index_null(return_value);
1725 }
1726 }
1727 }
1728 /* }}} */
1729
1730 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1731 Set an attribute */
PHP_METHOD(PDOStatement,setAttribute)1732 static PHP_METHOD(PDOStatement, setAttribute)
1733 {
1734 long attr;
1735 zval *value = NULL;
1736 PHP_STMT_GET_OBJ;
1737
1738 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
1739 RETURN_FALSE;
1740 }
1741
1742 if (!stmt->methods->set_attribute) {
1743 goto fail;
1744 }
1745
1746 PDO_STMT_CLEAR_ERR();
1747 if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
1748 RETURN_TRUE;
1749 }
1750
1751 fail:
1752 if (!stmt->methods->set_attribute) {
1753 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
1754 } else {
1755 PDO_HANDLE_STMT_ERR();
1756 }
1757 RETURN_FALSE;
1758 }
1759 /* }}} */
1760
1761 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1762 Get an attribute */
1763
generic_stmt_attr_get(pdo_stmt_t * stmt,zval * return_value,long attr)1764 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr)
1765 {
1766 switch (attr) {
1767 case PDO_ATTR_EMULATE_PREPARES:
1768 RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1769 return 1;
1770 }
1771 return 0;
1772 }
1773
PHP_METHOD(PDOStatement,getAttribute)1774 static PHP_METHOD(PDOStatement, getAttribute)
1775 {
1776 long attr;
1777 PHP_STMT_GET_OBJ;
1778
1779 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
1780 RETURN_FALSE;
1781 }
1782
1783 if (!stmt->methods->get_attribute) {
1784 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1785 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1786 "This driver doesn't support getting attributes" TSRMLS_CC);
1787 RETURN_FALSE;
1788 }
1789 return;
1790 }
1791
1792 PDO_STMT_CLEAR_ERR();
1793 switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
1794 case -1:
1795 PDO_HANDLE_STMT_ERR();
1796 RETURN_FALSE;
1797
1798 case 0:
1799 if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1800 /* XXX: should do something better here */
1801 pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1802 "driver doesn't support getting that attribute" TSRMLS_CC);
1803 RETURN_FALSE;
1804 }
1805 return;
1806
1807 default:
1808 return;
1809 }
1810 }
1811 /* }}} */
1812
1813 /* {{{ proto int PDOStatement::columnCount()
1814 Returns the number of columns in the result set */
PHP_METHOD(PDOStatement,columnCount)1815 static PHP_METHOD(PDOStatement, columnCount)
1816 {
1817 PHP_STMT_GET_OBJ;
1818 if (zend_parse_parameters_none() == FAILURE) {
1819 return;
1820 }
1821 RETURN_LONG(stmt->column_count);
1822 }
1823 /* }}} */
1824
1825 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1826 Returns meta data for a numbered column */
PHP_METHOD(PDOStatement,getColumnMeta)1827 static PHP_METHOD(PDOStatement, getColumnMeta)
1828 {
1829 long colno;
1830 struct pdo_column_data *col;
1831 PHP_STMT_GET_OBJ;
1832
1833 if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
1834 RETURN_FALSE;
1835 }
1836 if(colno < 0) {
1837 pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
1838 RETURN_FALSE;
1839 }
1840
1841 if (!stmt->methods->get_column_meta) {
1842 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
1843 RETURN_FALSE;
1844 }
1845
1846 PDO_STMT_CLEAR_ERR();
1847 if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
1848 PDO_HANDLE_STMT_ERR();
1849 RETURN_FALSE;
1850 }
1851
1852 /* add stock items */
1853 col = &stmt->columns[colno];
1854 add_assoc_string(return_value, "name", col->name, 1);
1855 add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1856 add_assoc_long(return_value, "precision", col->precision);
1857 if (col->param_type != PDO_PARAM_ZVAL) {
1858 /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1859 add_assoc_long(return_value, "pdo_type", col->param_type);
1860 }
1861 }
1862 /* }}} */
1863
1864 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1865 Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1866
pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int skip)1867 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1868 {
1869 long mode = PDO_FETCH_BOTH;
1870 int flags = 0, argc = ZEND_NUM_ARGS() - skip;
1871 zval ***args;
1872 zend_class_entry **cep;
1873 int retval;
1874
1875 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1876
1877 switch (stmt->default_fetch_type) {
1878 case PDO_FETCH_INTO:
1879 if (stmt->fetch.into) {
1880 zval_ptr_dtor(&stmt->fetch.into);
1881 stmt->fetch.into = NULL;
1882 }
1883 break;
1884 default:
1885 ;
1886 }
1887
1888 stmt->default_fetch_type = PDO_FETCH_BOTH;
1889
1890 if (argc == 0) {
1891 return SUCCESS;
1892 }
1893
1894 args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
1895
1896 retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1897
1898 if (SUCCESS == retval) {
1899 if (Z_TYPE_PP(args[skip]) != IS_LONG) {
1900 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
1901 retval = FAILURE;
1902 } else {
1903 mode = Z_LVAL_PP(args[skip]);
1904 flags = mode & PDO_FETCH_FLAGS;
1905
1906 retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
1907 }
1908 }
1909
1910 if (FAILURE == retval) {
1911 PDO_STMT_CLEAR_ERR();
1912 efree(args);
1913 return FAILURE;
1914 }
1915
1916 retval = FAILURE;
1917 switch (mode & ~PDO_FETCH_FLAGS) {
1918 case PDO_FETCH_USE_DEFAULT:
1919 case PDO_FETCH_LAZY:
1920 case PDO_FETCH_ASSOC:
1921 case PDO_FETCH_NUM:
1922 case PDO_FETCH_BOTH:
1923 case PDO_FETCH_OBJ:
1924 case PDO_FETCH_BOUND:
1925 case PDO_FETCH_NAMED:
1926 case PDO_FETCH_KEY_PAIR:
1927 if (argc != 1) {
1928 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1929 } else {
1930 retval = SUCCESS;
1931 }
1932 break;
1933
1934 case PDO_FETCH_COLUMN:
1935 if (argc != 2) {
1936 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument" TSRMLS_CC);
1937 } else if (Z_TYPE_PP(args[skip+1]) != IS_LONG) {
1938 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer" TSRMLS_CC);
1939 } else {
1940 stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
1941 retval = SUCCESS;
1942 }
1943 break;
1944
1945 case PDO_FETCH_CLASS:
1946 /* Gets its class name from 1st column */
1947 if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1948 if (argc != 1) {
1949 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1950 } else {
1951 stmt->fetch.cls.ce = NULL;
1952 retval = SUCCESS;
1953 }
1954 } else {
1955 if (argc < 2) {
1956 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument" TSRMLS_CC);
1957 } else if (argc > 3) {
1958 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments" TSRMLS_CC);
1959 } else if (Z_TYPE_PP(args[skip+1]) != IS_STRING) {
1960 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string" TSRMLS_CC);
1961 } else {
1962 retval = zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
1963 Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC);
1964
1965 if (SUCCESS == retval && cep && *cep) {
1966 stmt->fetch.cls.ce = *cep;
1967 }
1968 }
1969 }
1970
1971 if (SUCCESS == retval) {
1972 stmt->fetch.cls.ctor_args = NULL;
1973 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
1974 if (stmt->dbh->is_persistent) {
1975 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");
1976 }
1977 #endif
1978 if (argc == 3) {
1979 if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
1980 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1981 retval = FAILURE;
1982 } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
1983 ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1984 *stmt->fetch.cls.ctor_args = **args[skip+2];
1985 zval_copy_ctor(stmt->fetch.cls.ctor_args);
1986 }
1987 }
1988
1989 if (SUCCESS == retval) {
1990 do_fetch_class_prepare(stmt TSRMLS_CC);
1991 }
1992 }
1993
1994 break;
1995
1996 case PDO_FETCH_INTO:
1997 if (argc != 2) {
1998 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter" TSRMLS_CC);
1999 } else if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
2000 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object" TSRMLS_CC);
2001 } else {
2002 retval = SUCCESS;
2003 }
2004
2005 if (SUCCESS == retval) {
2006 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
2007 if (stmt->dbh->is_persistent) {
2008 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");
2009 }
2010 #endif
2011 MAKE_STD_ZVAL(stmt->fetch.into);
2012
2013 Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
2014 Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
2015 Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
2016 zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
2017 }
2018
2019 break;
2020
2021 default:
2022 pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
2023 }
2024
2025 if (SUCCESS == retval) {
2026 stmt->default_fetch_type = mode;
2027 }
2028
2029 /*
2030 * PDO error (if any) has already been raised at this point.
2031 *
2032 * The error_code is cleared, otherwise the caller will read the
2033 * last error message from the driver.
2034 *
2035 */
2036 PDO_STMT_CLEAR_ERR();
2037
2038 efree(args);
2039
2040 return retval;
2041 }
2042
PHP_METHOD(PDOStatement,setFetchMode)2043 static PHP_METHOD(PDOStatement, setFetchMode)
2044 {
2045 PHP_STMT_GET_OBJ;
2046
2047 RETVAL_BOOL(
2048 pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2049 stmt, 0) == SUCCESS ? 1 : 0
2050 );
2051 }
2052 /* }}} */
2053
2054 /* {{{ proto bool PDOStatement::nextRowset()
2055 Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
2056
pdo_stmt_do_next_rowset(pdo_stmt_t * stmt TSRMLS_DC)2057 static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
2058 {
2059 /* un-describe */
2060 if (stmt->columns) {
2061 int i;
2062 struct pdo_column_data *cols = stmt->columns;
2063
2064 for (i = 0; i < stmt->column_count; i++) {
2065 efree(cols[i].name);
2066 }
2067 efree(stmt->columns);
2068 stmt->columns = NULL;
2069 stmt->column_count = 0;
2070 }
2071
2072 if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
2073 /* Set the executed flag to 0 to reallocate columns on next execute */
2074 stmt->executed = 0;
2075 return 0;
2076 }
2077
2078 pdo_stmt_describe_columns(stmt TSRMLS_CC);
2079
2080 return 1;
2081 }
2082
PHP_METHOD(PDOStatement,nextRowset)2083 static PHP_METHOD(PDOStatement, nextRowset)
2084 {
2085 PHP_STMT_GET_OBJ;
2086
2087 if (!stmt->methods->next_rowset) {
2088 pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
2089 RETURN_FALSE;
2090 }
2091
2092 PDO_STMT_CLEAR_ERR();
2093
2094 if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2095 PDO_HANDLE_STMT_ERR();
2096 RETURN_FALSE;
2097 }
2098
2099 RETURN_TRUE;
2100 }
2101 /* }}} */
2102
2103 /* {{{ proto bool PDOStatement::closeCursor()
2104 Closes the cursor, leaving the statement ready for re-execution. */
PHP_METHOD(PDOStatement,closeCursor)2105 static PHP_METHOD(PDOStatement, closeCursor)
2106 {
2107 PHP_STMT_GET_OBJ;
2108
2109 if (!stmt->methods->cursor_closer) {
2110 /* emulate it by fetching and discarding rows */
2111 do {
2112 while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
2113 ;
2114 if (!stmt->methods->next_rowset) {
2115 break;
2116 }
2117
2118 if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2119 break;
2120 }
2121
2122 } while (1);
2123 stmt->executed = 0;
2124 RETURN_TRUE;
2125 }
2126
2127 PDO_STMT_CLEAR_ERR();
2128
2129 if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
2130 PDO_HANDLE_STMT_ERR();
2131 RETURN_FALSE;
2132 }
2133 stmt->executed = 0;
2134 RETURN_TRUE;
2135 }
2136 /* }}} */
2137
2138 /* {{{ proto void PDOStatement::debugDumpParams()
2139 A utility for internals hackers to debug parameter internals */
PHP_METHOD(PDOStatement,debugDumpParams)2140 static PHP_METHOD(PDOStatement, debugDumpParams)
2141 {
2142 php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
2143 HashPosition pos;
2144 struct pdo_bound_param_data *param;
2145 PHP_STMT_GET_OBJ;
2146
2147 if (out == NULL) {
2148 RETURN_FALSE;
2149 }
2150
2151 php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
2152 stmt->query_stringlen,
2153 stmt->query_stringlen, stmt->query_string);
2154
2155 php_stream_printf(out TSRMLS_CC, "Params: %d\n",
2156 stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2157
2158 if (stmt->bound_params) {
2159 zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
2160 while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
2161 (void**)¶m, &pos)) {
2162 char *str;
2163 uint len;
2164 ulong num;
2165 int res;
2166
2167 res = zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos);
2168 if (res == HASH_KEY_IS_LONG) {
2169 php_stream_printf(out TSRMLS_CC, "Key: Position #%ld:\n", num);
2170 } else if (res == HASH_KEY_IS_STRING) {
2171 php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
2172 }
2173
2174 php_stream_printf(out TSRMLS_CC, "paramno=%ld\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
2175 param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
2176 param->is_param,
2177 param->param_type);
2178
2179 zend_hash_move_forward_ex(stmt->bound_params, &pos);
2180 }
2181 }
2182
2183 php_stream_close(out);
2184 }
2185 /* }}} */
2186
2187 /* {{{ proto int PDOStatement::__wakeup()
2188 Prevents use of a PDOStatement instance that has been unserialized */
PHP_METHOD(PDOStatement,__wakeup)2189 static PHP_METHOD(PDOStatement, __wakeup)
2190 {
2191 zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2192 }
2193 /* }}} */
2194
2195 /* {{{ proto int PDOStatement::__sleep()
2196 Prevents serialization of a PDOStatement instance */
PHP_METHOD(PDOStatement,__sleep)2197 static PHP_METHOD(PDOStatement, __sleep)
2198 {
2199 zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2200 }
2201 /* }}} */
2202
2203 const zend_function_entry pdo_dbstmt_functions[] = {
2204 PHP_ME(PDOStatement, execute, arginfo_pdostatement_execute, ZEND_ACC_PUBLIC)
2205 PHP_ME(PDOStatement, fetch, arginfo_pdostatement_fetch, ZEND_ACC_PUBLIC)
2206 PHP_ME(PDOStatement, bindParam, arginfo_pdostatement_bindparam, ZEND_ACC_PUBLIC)
2207 PHP_ME(PDOStatement, bindColumn, arginfo_pdostatement_bindcolumn, ZEND_ACC_PUBLIC)
2208 PHP_ME(PDOStatement, bindValue, arginfo_pdostatement_bindvalue, ZEND_ACC_PUBLIC)
2209 PHP_ME(PDOStatement, rowCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2210 PHP_ME(PDOStatement, fetchColumn, arginfo_pdostatement_fetchcolumn, ZEND_ACC_PUBLIC)
2211 PHP_ME(PDOStatement, fetchAll, arginfo_pdostatement_fetchall, ZEND_ACC_PUBLIC)
2212 PHP_ME(PDOStatement, fetchObject, arginfo_pdostatement_fetchobject, ZEND_ACC_PUBLIC)
2213 PHP_ME(PDOStatement, errorCode, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2214 PHP_ME(PDOStatement, errorInfo, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2215 PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
2216 PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
2217 PHP_ME(PDOStatement, columnCount, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2218 PHP_ME(PDOStatement, getColumnMeta, arginfo_pdostatement_getcolumnmeta, ZEND_ACC_PUBLIC)
2219 PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
2220 PHP_ME(PDOStatement, nextRowset, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2221 PHP_ME(PDOStatement, closeCursor, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2222 PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void, ZEND_ACC_PUBLIC)
2223 PHP_ME(PDOStatement, __wakeup, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2224 PHP_ME(PDOStatement, __sleep, arginfo_pdostatement__void, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2225 {NULL, NULL, NULL}
2226 };
2227
2228 /* {{{ overloaded handlers for PDOStatement class */
dbstmt_prop_write(zval * object,zval * member,zval * value,const zend_literal * key TSRMLS_DC)2229 static void dbstmt_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
2230 {
2231 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2232
2233 convert_to_string(member);
2234
2235 if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2236 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2237 } else {
2238 std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
2239 }
2240 }
2241
dbstmt_prop_delete(zval * object,zval * member,const zend_literal * key TSRMLS_DC)2242 static void dbstmt_prop_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
2243 {
2244 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2245
2246 convert_to_string(member);
2247
2248 if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2249 pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2250 } else {
2251 std_object_handlers.unset_property(object, member, key TSRMLS_CC);
2252 }
2253 }
2254
dbstmt_method_get(zval ** object_pp,char * method_name,int method_len,const zend_literal * key TSRMLS_DC)2255 static union _zend_function *dbstmt_method_get(
2256 #if PHP_API_VERSION >= 20041225
2257 zval **object_pp,
2258 #else
2259 zval *object,
2260 #endif
2261 char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
2262 {
2263 zend_function *fbc = NULL;
2264 char *lc_method_name;
2265 #if PHP_API_VERSION >= 20041225
2266 zval *object = *object_pp;
2267 #endif
2268
2269 lc_method_name = emalloc(method_len + 1);
2270 zend_str_tolower_copy(lc_method_name, method_name, method_len);
2271
2272 if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
2273 method_len+1, (void**)&fbc) == FAILURE) {
2274 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2275 /* instance not created by PDO object */
2276 if (!stmt->dbh) {
2277 goto out;
2278 }
2279 /* not a pre-defined method, nor a user-defined method; check
2280 * the driver specific methods */
2281 if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2282 if (!pdo_hash_methods(stmt->dbh,
2283 PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
2284 || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2285 goto out;
2286 }
2287 }
2288
2289 if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
2290 lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2291 fbc = NULL;
2292 goto out;
2293 }
2294 /* got it */
2295 }
2296
2297 out:
2298 efree(lc_method_name);
2299 return fbc;
2300 }
2301
dbstmt_compare(zval * object1,zval * object2 TSRMLS_DC)2302 static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
2303 {
2304 return -1;
2305 }
2306
dbstmt_clone_obj(zval * zobject TSRMLS_DC)2307 static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
2308 {
2309 zend_object_value retval;
2310 pdo_stmt_t *stmt;
2311 pdo_stmt_t *old_stmt;
2312 zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
2313
2314 stmt = ecalloc(1, sizeof(*stmt));
2315 zend_object_std_init(&stmt->std, Z_OBJCE_P(zobject) TSRMLS_CC);
2316 object_properties_init(&stmt->std, Z_OBJCE_P(zobject));
2317 stmt->refcount = 1;
2318
2319 old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
2320
2321 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);
2322 retval.handlers = Z_OBJ_HT_P(zobject);
2323
2324 zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
2325
2326 zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
2327 stmt->database_object_handle = old_stmt->database_object_handle;
2328
2329 return retval;
2330 }
2331
2332 zend_object_handlers pdo_dbstmt_object_handlers;
2333 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
2334
pdo_stmt_init(TSRMLS_D)2335 void pdo_stmt_init(TSRMLS_D)
2336 {
2337 zend_class_entry ce;
2338
2339 INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2340 pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
2341 pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2342 pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2343 zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
2344 zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
2345
2346 memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2347 pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2348 pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2349 pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2350 pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2351 pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
2352
2353 INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2354 pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
2355 pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
2356 pdo_row_ce->create_object = pdo_row_new;
2357 pdo_row_ce->serialize = pdo_row_serialize;
2358 }
2359
free_statement(pdo_stmt_t * stmt TSRMLS_DC)2360 static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
2361 {
2362 if (stmt->bound_params) {
2363 zend_hash_destroy(stmt->bound_params);
2364 FREE_HASHTABLE(stmt->bound_params);
2365 stmt->bound_params = NULL;
2366 }
2367 if (stmt->bound_param_map) {
2368 zend_hash_destroy(stmt->bound_param_map);
2369 FREE_HASHTABLE(stmt->bound_param_map);
2370 stmt->bound_param_map = NULL;
2371 }
2372 if (stmt->bound_columns) {
2373 zend_hash_destroy(stmt->bound_columns);
2374 FREE_HASHTABLE(stmt->bound_columns);
2375 stmt->bound_columns = NULL;
2376 }
2377
2378 if (stmt->methods && stmt->methods->dtor) {
2379 stmt->methods->dtor(stmt TSRMLS_CC);
2380 }
2381 if (stmt->query_string) {
2382 efree(stmt->query_string);
2383 }
2384
2385 if (stmt->columns) {
2386 int i;
2387 struct pdo_column_data *cols = stmt->columns;
2388
2389 for (i = 0; i < stmt->column_count; i++) {
2390 if (cols[i].name) {
2391 efree(cols[i].name);
2392 cols[i].name = NULL;
2393 }
2394 }
2395 efree(stmt->columns);
2396 stmt->columns = NULL;
2397 }
2398
2399 if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
2400 FREE_ZVAL(stmt->fetch.into);
2401 stmt->fetch.into = NULL;
2402 }
2403
2404 do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
2405
2406 zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
2407 if (stmt->dbh) {
2408 php_pdo_dbh_delref(stmt->dbh TSRMLS_CC);
2409 }
2410 zend_object_std_dtor(&stmt->std TSRMLS_CC);
2411 efree(stmt);
2412 }
2413
php_pdo_stmt_addref(pdo_stmt_t * stmt TSRMLS_DC)2414 PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
2415 {
2416 stmt->refcount++;
2417 }
2418
php_pdo_stmt_delref(pdo_stmt_t * stmt TSRMLS_DC)2419 PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
2420 {
2421 if (--stmt->refcount == 0) {
2422 free_statement(stmt TSRMLS_CC);
2423 }
2424 }
2425
pdo_dbstmt_free_storage(pdo_stmt_t * stmt TSRMLS_DC)2426 void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2427 {
2428 php_pdo_stmt_delref(stmt TSRMLS_CC);
2429 }
2430
pdo_dbstmt_new(zend_class_entry * ce TSRMLS_DC)2431 zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
2432 {
2433 zend_object_value retval;
2434
2435 pdo_stmt_t *stmt;
2436 stmt = emalloc(sizeof(*stmt));
2437 memset(stmt, 0, sizeof(*stmt));
2438 zend_object_std_init(&stmt->std, ce TSRMLS_CC);
2439 object_properties_init(&stmt->std, ce);
2440 stmt->refcount = 1;
2441
2442 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);
2443 retval.handlers = &pdo_dbstmt_object_handlers;
2444
2445 return retval;
2446 }
2447 /* }}} */
2448
2449 /* {{{ statement iterator */
2450
2451 struct php_pdo_iterator {
2452 zend_object_iterator iter;
2453 pdo_stmt_t *stmt;
2454 ulong key;
2455 zval *fetch_ahead;
2456 };
2457
pdo_stmt_iter_dtor(zend_object_iterator * iter TSRMLS_DC)2458 static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
2459 {
2460 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2461
2462 if (--I->stmt->refcount == 0) {
2463 free_statement(I->stmt TSRMLS_CC);
2464 }
2465
2466 if (I->fetch_ahead) {
2467 zval_ptr_dtor(&I->fetch_ahead);
2468 }
2469
2470 efree(I);
2471 }
2472
pdo_stmt_iter_valid(zend_object_iterator * iter TSRMLS_DC)2473 static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
2474 {
2475 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2476
2477 return I->fetch_ahead ? SUCCESS : FAILURE;
2478 }
2479
pdo_stmt_iter_get_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2480 static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
2481 {
2482 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2483
2484 /* sanity */
2485 if (!I->fetch_ahead) {
2486 *data = NULL;
2487 return;
2488 }
2489
2490 *data = &I->fetch_ahead;
2491 }
2492
pdo_stmt_iter_get_key(zend_object_iterator * iter,zval * key TSRMLS_DC)2493 static void pdo_stmt_iter_get_key(zend_object_iterator *iter, zval *key TSRMLS_DC)
2494 {
2495 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2496
2497 if (I->key == (ulong)-1) {
2498 ZVAL_NULL(key);
2499 } else {
2500 ZVAL_LONG(key, I->key);
2501 }
2502 }
2503
pdo_stmt_iter_move_forwards(zend_object_iterator * iter TSRMLS_DC)2504 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
2505 {
2506 struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2507
2508 if (I->fetch_ahead) {
2509 zval_ptr_dtor(&I->fetch_ahead);
2510 I->fetch_ahead = NULL;
2511 }
2512
2513 MAKE_STD_ZVAL(I->fetch_ahead);
2514
2515 if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2516 PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2517 pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
2518
2519 PDO_HANDLE_STMT_ERR();
2520 I->key = (ulong)-1;
2521 FREE_ZVAL(I->fetch_ahead);
2522 I->fetch_ahead = NULL;
2523
2524 return;
2525 }
2526
2527 I->key++;
2528 }
2529
2530 static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2531 pdo_stmt_iter_dtor,
2532 pdo_stmt_iter_valid,
2533 pdo_stmt_iter_get_data,
2534 pdo_stmt_iter_get_key,
2535 pdo_stmt_iter_move_forwards,
2536 NULL
2537 };
2538
pdo_stmt_iter_get(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2539 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
2540 {
2541 pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2542 struct php_pdo_iterator *I;
2543
2544 if (by_ref) {
2545 zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2546 }
2547
2548 I = ecalloc(1, sizeof(*I));
2549 I->iter.funcs = &pdo_stmt_iter_funcs;
2550 I->iter.data = I;
2551 I->stmt = stmt;
2552 stmt->refcount++;
2553
2554 MAKE_STD_ZVAL(I->fetch_ahead);
2555 if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2556 PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2557 PDO_HANDLE_STMT_ERR();
2558 I->key = (ulong)-1;
2559 FREE_ZVAL(I->fetch_ahead);
2560 I->fetch_ahead = NULL;
2561 }
2562
2563 return &I->iter;
2564 }
2565
2566 /* }}} */
2567
2568 /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2569
2570 const zend_function_entry pdo_row_functions[] = {
2571 {NULL, NULL, NULL}
2572 };
2573
row_prop_read(zval * object,zval * member,int type,const zend_literal * key TSRMLS_DC)2574 static zval *row_prop_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
2575 {
2576 zval *return_value;
2577 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2578 int colno = -1;
2579
2580 MAKE_STD_ZVAL(return_value);
2581 RETVAL_NULL();
2582
2583 if (stmt) {
2584 if (Z_TYPE_P(member) == IS_LONG) {
2585 if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
2586 fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
2587 }
2588 } else {
2589 convert_to_string(member);
2590 /* TODO: replace this with a hash of available column names to column
2591 * numbers */
2592 for (colno = 0; colno < stmt->column_count; colno++) {
2593 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2594 fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
2595 Z_SET_REFCOUNT_P(return_value, 0);
2596 Z_UNSET_ISREF_P(return_value);
2597 return return_value;
2598 }
2599 }
2600 if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2601 zval_ptr_dtor(&return_value);
2602 return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
2603 }
2604 }
2605 }
2606
2607 Z_SET_REFCOUNT_P(return_value, 0);
2608 Z_UNSET_ISREF_P(return_value);
2609
2610 return return_value;
2611 }
2612
row_dim_read(zval * object,zval * member,int type TSRMLS_DC)2613 static zval *row_dim_read(zval *object, zval *member, int type TSRMLS_DC)
2614 {
2615 return row_prop_read(object, member, type, NULL TSRMLS_CC);
2616 }
2617
row_prop_write(zval * object,zval * member,zval * value,const zend_literal * key TSRMLS_DC)2618 static void row_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
2619 {
2620 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2621 }
2622
row_dim_write(zval * object,zval * member,zval * value TSRMLS_DC)2623 static void row_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
2624 {
2625 php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2626 }
2627
row_prop_exists(zval * object,zval * member,int check_empty,const zend_literal * key TSRMLS_DC)2628 static int row_prop_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
2629 {
2630 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2631 int colno = -1;
2632
2633 if (stmt) {
2634 if (Z_TYPE_P(member) == IS_LONG) {
2635 return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
2636 } else {
2637 convert_to_string(member);
2638
2639 /* TODO: replace this with a hash of available column names to column
2640 * numbers */
2641 for (colno = 0; colno < stmt->column_count; colno++) {
2642 if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2643 return 1;
2644 }
2645 }
2646 }
2647 }
2648
2649 return 0;
2650 }
2651
row_dim_exists(zval * object,zval * member,int check_empty TSRMLS_DC)2652 static int row_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
2653 {
2654 return row_prop_exists(object, member, check_empty, NULL TSRMLS_CC);
2655 }
2656
row_prop_delete(zval * object,zval * offset,const zend_literal * key TSRMLS_DC)2657 static void row_prop_delete(zval *object, zval *offset, const zend_literal *key TSRMLS_DC)
2658 {
2659 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2660 }
2661
row_dim_delete(zval * object,zval * offset TSRMLS_DC)2662 static void row_dim_delete(zval *object, zval *offset TSRMLS_DC)
2663 {
2664 php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2665 }
2666
row_get_properties(zval * object TSRMLS_DC)2667 static HashTable *row_get_properties(zval *object TSRMLS_DC)
2668 {
2669 pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2670 int i;
2671
2672 if (stmt == NULL) {
2673 return NULL;
2674 }
2675
2676 if (!stmt->std.properties) {
2677 rebuild_object_properties(&stmt->std);
2678 }
2679 for (i = 0; i < stmt->column_count; i++) {
2680 zval *val;
2681 MAKE_STD_ZVAL(val);
2682 fetch_value(stmt, val, i, NULL TSRMLS_CC);
2683
2684 zend_hash_update(stmt->std.properties, stmt->columns[i].name, stmt->columns[i].namelen + 1, (void *)&val, sizeof(zval *), NULL);
2685 }
2686
2687 return stmt->std.properties;
2688 }
2689
row_method_get(zval ** object_pp,char * method_name,int method_len,const zend_literal * key TSRMLS_DC)2690 static union _zend_function *row_method_get(
2691 #if PHP_API_VERSION >= 20041225
2692 zval **object_pp,
2693 #else
2694 zval *object,
2695 #endif
2696 char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
2697 {
2698 zend_function *fbc;
2699 char *lc_method_name;
2700
2701 lc_method_name = emalloc(method_len + 1);
2702 zend_str_tolower_copy(lc_method_name, method_name, method_len);
2703
2704 if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2705 efree(lc_method_name);
2706 return NULL;
2707 }
2708
2709 efree(lc_method_name);
2710 return fbc;
2711 }
2712
row_call_method(const char * method,INTERNAL_FUNCTION_PARAMETERS)2713 static int row_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
2714 {
2715 return FAILURE;
2716 }
2717
row_get_ctor(zval * object TSRMLS_DC)2718 static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
2719 {
2720 static zend_internal_function ctor = {0};
2721
2722 ctor.type = ZEND_INTERNAL_FUNCTION;
2723 ctor.function_name = "__construct";
2724 ctor.scope = pdo_row_ce;
2725 ctor.handler = ZEND_FN(dbstmt_constructor);
2726 ctor.fn_flags = ZEND_ACC_PUBLIC;
2727
2728 return (union _zend_function*)&ctor;
2729 }
2730
row_get_ce(const zval * object TSRMLS_DC)2731 static zend_class_entry *row_get_ce(const zval *object TSRMLS_DC)
2732 {
2733 return pdo_row_ce;
2734 }
2735
row_get_classname(const zval * object,const char ** class_name,zend_uint * class_name_len,int parent TSRMLS_DC)2736 static int row_get_classname(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
2737 {
2738 if (parent) {
2739 return FAILURE;
2740 } else {
2741 *class_name = estrndup("PDORow", sizeof("PDORow")-1);
2742 *class_name_len = sizeof("PDORow")-1;
2743 return SUCCESS;
2744 }
2745 }
2746
row_compare(zval * object1,zval * object2 TSRMLS_DC)2747 static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
2748 {
2749 return -1;
2750 }
2751
2752 zend_object_handlers pdo_row_object_handlers = {
2753 zend_objects_store_add_ref,
2754 zend_objects_store_del_ref,
2755 NULL,
2756 row_prop_read,
2757 row_prop_write,
2758 row_dim_read,
2759 row_dim_write,
2760 NULL,
2761 NULL,
2762 NULL,
2763 row_prop_exists,
2764 row_prop_delete,
2765 row_dim_exists,
2766 row_dim_delete,
2767 row_get_properties,
2768 row_method_get,
2769 row_call_method,
2770 row_get_ctor,
2771 row_get_ce,
2772 row_get_classname,
2773 row_compare,
2774 NULL, /* cast */
2775 NULL
2776 };
2777
pdo_row_free_storage(pdo_stmt_t * stmt TSRMLS_DC)2778 void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2779 {
2780 if (stmt) {
2781 ZVAL_NULL(&stmt->lazy_object_ref);
2782
2783 if (--stmt->refcount == 0) {
2784 free_statement(stmt TSRMLS_CC);
2785 }
2786 }
2787 }
2788
pdo_row_new(zend_class_entry * ce TSRMLS_DC)2789 zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
2790 {
2791 zend_object_value retval;
2792
2793 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);
2794 retval.handlers = &pdo_row_object_handlers;
2795
2796 return retval;
2797 }
2798
pdo_row_serialize(zval * object,unsigned char ** buffer,zend_uint * buf_len,zend_serialize_data * data TSRMLS_DC)2799 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
2800 {
2801 php_error_docref(NULL TSRMLS_CC, E_WARNING, "PDORow instances may not be serialized");
2802 return FAILURE;
2803 }
2804 /* }}} */
2805
2806 /*
2807 * Local variables:
2808 * tab-width: 4
2809 * c-basic-offset: 4
2810 * End:
2811 * vim600: noet sw=4 ts=4 fdm=marker
2812 * vim<600: noet sw=4 ts=4
2813 */
2814