1 : /*
2 : +----------------------------------------------------------------------+
3 : | PHP Version 5 |
4 : +----------------------------------------------------------------------+
5 : | Copyright (c) 1997-2009 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: pdo_stmt.c 290786 2009-11-15 16:20:37Z felipe $ */
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_EX(arginfo_pdostatement_execute, 0, 0, 0)
42 : ZEND_ARG_INFO(0, bound_input_params) /* array */
43 : ZEND_END_ARG_INFO()
44 :
45 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetch, 0, 0, 0)
46 : ZEND_ARG_INFO(0, how)
47 : ZEND_ARG_INFO(0, orientation)
48 : ZEND_ARG_INFO(0, offset)
49 : ZEND_END_ARG_INFO()
50 :
51 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchobject, 0, 0, 0)
52 : ZEND_ARG_INFO(0, class_name)
53 : ZEND_ARG_INFO(0, ctor_args) /* array */
54 : ZEND_END_ARG_INFO()
55 :
56 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchcolumn, 0, 0, 0)
57 : ZEND_ARG_INFO(0, column_number)
58 : ZEND_END_ARG_INFO()
59 :
60 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_fetchall, 0, 0, 0)
61 : ZEND_ARG_INFO(0, how)
62 : ZEND_ARG_INFO(0, class_name)
63 : ZEND_ARG_INFO(0, ctor_args) /* array */
64 : ZEND_END_ARG_INFO()
65 :
66 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindvalue, 0, 0, 2)
67 : ZEND_ARG_INFO(0, paramno)
68 : ZEND_ARG_INFO(0, param)
69 : ZEND_ARG_INFO(0, type)
70 : ZEND_END_ARG_INFO()
71 :
72 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindparam, 0, 0, 2)
73 : ZEND_ARG_INFO(0, paramno)
74 : ZEND_ARG_INFO(1, param)
75 : ZEND_ARG_INFO(0, type)
76 : ZEND_ARG_INFO(0, maxlen)
77 : ZEND_ARG_INFO(0, driverdata)
78 : ZEND_END_ARG_INFO()
79 :
80 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_bindcolumn, 0, 0, 2)
81 : ZEND_ARG_INFO(0, column)
82 : ZEND_ARG_INFO(1, param)
83 : ZEND_ARG_INFO(0, type)
84 : ZEND_ARG_INFO(0, maxlen)
85 : ZEND_ARG_INFO(0, driverdata)
86 : ZEND_END_ARG_INFO()
87 :
88 : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_setattribute, 0)
89 : ZEND_ARG_INFO(0, attribute)
90 : ZEND_ARG_INFO(0, value)
91 : ZEND_END_ARG_INFO()
92 :
93 : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getattribute, 0)
94 : ZEND_ARG_INFO(0, attribute)
95 : ZEND_END_ARG_INFO()
96 :
97 : ZEND_BEGIN_ARG_INFO(arginfo_pdostatement_getcolumnmeta, 0)
98 : ZEND_ARG_INFO(0, column)
99 : ZEND_END_ARG_INFO()
100 :
101 : ZEND_BEGIN_ARG_INFO_EX(arginfo_pdostatement_setfetchmode, 0, 0, 1)
102 : ZEND_ARG_INFO(0, mode)
103 : ZEND_ARG_INFO(0, params)
104 : ZEND_END_ARG_INFO()
105 : /* }}} */
106 :
107 : #define PHP_STMT_GET_OBJ \
108 : pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(getThis() TSRMLS_CC); \
109 : if (!stmt->dbh) { \
110 : RETURN_FALSE; \
111 : } \
112 :
113 : static PHP_FUNCTION(dbstmt_constructor) /* {{{ */
114 7 : {
115 7 : php_error_docref(NULL TSRMLS_CC, E_ERROR, "You should not create a PDOStatement manually");
116 0 : }
117 : /* }}} */
118 :
119 : static inline int rewrite_name_to_position(pdo_stmt_t *stmt, struct pdo_bound_param_data *param TSRMLS_DC) /* {{{ */
120 11504 : {
121 11504 : if (stmt->bound_param_map) {
122 : /* rewriting :name to ? style.
123 : * We need to fixup the parameter numbers on the parameters.
124 : * If we find that a given named parameter has been used twice,
125 : * we will raise an error, as we can't be sure that it is safe
126 : * to bind multiple parameters onto the same zval in the underlying
127 : * driver */
128 : char *name;
129 440 : int position = 0;
130 :
131 440 : if (stmt->named_rewrite_template) {
132 : /* this is not an error here */
133 149 : return 1;
134 : }
135 291 : if (!param->name) {
136 : /* do the reverse; map the parameter number to the name */
137 81 : if (SUCCESS == zend_hash_index_find(stmt->bound_param_map, param->paramno, (void**)&name)) {
138 81 : param->name = estrdup(name);
139 81 : param->namelen = strlen(param->name);
140 81 : return 1;
141 : }
142 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
143 0 : return 0;
144 : }
145 :
146 210 : zend_hash_internal_pointer_reset(stmt->bound_param_map);
147 210 : while (SUCCESS == zend_hash_get_current_data(stmt->bound_param_map, (void**)&name)) {
148 210 : if (strcmp(name, param->name)) {
149 99 : position++;
150 99 : zend_hash_move_forward(stmt->bound_param_map);
151 99 : continue;
152 : }
153 111 : if (param->paramno >= 0) {
154 0 : 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);
155 0 : return -1;
156 : }
157 111 : param->paramno = position;
158 111 : return 1;
159 : }
160 99 : pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "parameter was not defined" TSRMLS_CC);
161 99 : return 0;
162 : }
163 11064 : return 1;
164 : }
165 : /* }}} */
166 :
167 : /* trigger callback hook for parameters */
168 : static int dispatch_param_event(pdo_stmt_t *stmt, enum pdo_param_event event_type TSRMLS_DC) /* {{{ */
169 7716 : {
170 7716 : int ret = 1, is_param = 1;
171 : struct pdo_bound_param_data *param;
172 : HashTable *ht;
173 :
174 7716 : if (!stmt->methods->param_hook) {
175 0 : return 1;
176 : }
177 :
178 7716 : ht = stmt->bound_params;
179 :
180 15427 : iterate:
181 15427 : if (ht) {
182 3359 : zend_hash_internal_pointer_reset(ht);
183 12046 : while (SUCCESS == zend_hash_get_current_data(ht, (void**)¶m)) {
184 5333 : if (!stmt->methods->param_hook(stmt, param, event_type TSRMLS_CC)) {
185 5 : ret = 0;
186 5 : break;
187 : }
188 :
189 5328 : zend_hash_move_forward(ht);
190 : }
191 : }
192 15427 : if (ret && is_param) {
193 7711 : ht = stmt->bound_columns;
194 7711 : is_param = 0;
195 7711 : goto iterate;
196 : }
197 :
198 7716 : return ret;
199 : }
200 : /* }}} */
201 :
202 : int pdo_stmt_describe_columns(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
203 1694 : {
204 : int col;
205 :
206 1694 : stmt->columns = ecalloc(stmt->column_count, sizeof(struct pdo_column_data));
207 :
208 3752 : for (col = 0; col < stmt->column_count; col++) {
209 2058 : if (!stmt->methods->describer(stmt, col TSRMLS_CC)) {
210 0 : return 0;
211 : }
212 :
213 : /* if we are applying case conversions on column names, do so now */
214 2058 : if (stmt->dbh->native_case != stmt->dbh->desired_case && stmt->dbh->desired_case != PDO_CASE_NATURAL) {
215 2005 : char *s = stmt->columns[col].name;
216 :
217 2005 : switch (stmt->dbh->desired_case) {
218 : case PDO_CASE_UPPER:
219 70 : while (*s != '\0') {
220 44 : *s = toupper(*s);
221 44 : s++;
222 : }
223 13 : break;
224 : case PDO_CASE_LOWER:
225 11163 : while (*s != '\0') {
226 7179 : *s = tolower(*s);
227 7179 : s++;
228 : }
229 : break;
230 : default:
231 : ;
232 : }
233 : }
234 :
235 : #if 0
236 : /* update the column index on named bound parameters */
237 : if (stmt->bound_params) {
238 : struct pdo_bound_param_data *param;
239 :
240 : if (SUCCESS == zend_hash_find(stmt->bound_params, stmt->columns[col].name,
241 : stmt->columns[col].namelen, (void**)¶m)) {
242 : param->paramno = col;
243 : }
244 : }
245 : #endif
246 2058 : if (stmt->bound_columns) {
247 : struct pdo_bound_param_data *param;
248 :
249 2 : if (SUCCESS == zend_hash_find(stmt->bound_columns, stmt->columns[col].name,
250 : stmt->columns[col].namelen, (void**)¶m)) {
251 1 : param->paramno = col;
252 : }
253 : }
254 :
255 : }
256 1694 : return 1;
257 : }
258 : /* }}} */
259 :
260 : static void get_lazy_object(pdo_stmt_t *stmt, zval *return_value TSRMLS_DC) /* {{{ */
261 23 : {
262 23 : if (Z_TYPE(stmt->lazy_object_ref) == IS_NULL) {
263 17 : Z_TYPE(stmt->lazy_object_ref) = IS_OBJECT;
264 17 : 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);
265 17 : Z_OBJ_HT(stmt->lazy_object_ref) = &pdo_row_object_handlers;
266 17 : stmt->refcount++;
267 : }
268 23 : Z_TYPE_P(return_value) = IS_OBJECT;
269 23 : Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE(stmt->lazy_object_ref);
270 23 : Z_OBJ_HT_P(return_value) = Z_OBJ_HT(stmt->lazy_object_ref);
271 23 : zend_objects_store_add_ref(return_value TSRMLS_CC);
272 23 : }
273 : /* }}} */
274 :
275 : static void param_dtor(void *data) /* {{{ */
276 11801 : {
277 11801 : struct pdo_bound_param_data *param = (struct pdo_bound_param_data *)data;
278 : TSRMLS_FETCH();
279 :
280 : /* tell the driver that it is going away */
281 11801 : if (param->stmt->methods->param_hook) {
282 11801 : param->stmt->methods->param_hook(param->stmt, param, PDO_PARAM_EVT_FREE TSRMLS_CC);
283 : }
284 :
285 11801 : if (param->name) {
286 5532 : efree(param->name);
287 : }
288 :
289 11801 : if (param->parameter) {
290 11801 : zval_ptr_dtor(&(param->parameter));
291 11801 : param->parameter = NULL;
292 : }
293 11801 : if (param->driver_params) {
294 0 : zval_ptr_dtor(&(param->driver_params));
295 : }
296 11801 : }
297 : /* }}} */
298 :
299 : static int really_register_bound_param(struct pdo_bound_param_data *param, pdo_stmt_t *stmt, int is_param TSRMLS_DC) /* {{{ */
300 11925 : {
301 : HashTable *hash;
302 11925 : struct pdo_bound_param_data *pparam = NULL;
303 :
304 11925 : hash = is_param ? stmt->bound_params : stmt->bound_columns;
305 :
306 11925 : if (!hash) {
307 1248 : ALLOC_HASHTABLE(hash);
308 1248 : zend_hash_init(hash, 13, NULL, param_dtor, 0);
309 :
310 1248 : if (is_param) {
311 1051 : stmt->bound_params = hash;
312 : } else {
313 197 : stmt->bound_columns = hash;
314 : }
315 : }
316 :
317 23374 : if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_STR && param->max_value_len <= 0 && ! ZVAL_IS_NULL(param->parameter)) {
318 11449 : if (Z_TYPE_P(param->parameter) == IS_DOUBLE) {
319 : char *p;
320 29 : int len = spprintf(&p, 0, "%.*H", (int) EG(precision), Z_DVAL_P(param->parameter));
321 29 : ZVAL_STRINGL(param->parameter, p, len, 0);
322 : } else {
323 11420 : convert_to_string(param->parameter);
324 : }
325 483 : } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_INT && Z_TYPE_P(param->parameter) == IS_BOOL) {
326 7 : convert_to_long(param->parameter);
327 469 : } else if (PDO_PARAM_TYPE(param->param_type) == PDO_PARAM_BOOL && Z_TYPE_P(param->parameter) == IS_LONG) {
328 0 : convert_to_boolean(param->parameter);
329 : }
330 :
331 11925 : param->stmt = stmt;
332 11925 : param->is_param = is_param;
333 :
334 11925 : if (param->driver_params) {
335 0 : Z_ADDREF_P(param->driver_params);
336 : }
337 :
338 11925 : if (!is_param && param->name && stmt->columns) {
339 : /* try to map the name to the column */
340 : int i;
341 :
342 144 : for (i = 0; i < stmt->column_count; i++) {
343 144 : if (strcmp(stmt->columns[i].name, param->name) == 0) {
344 112 : param->paramno = i;
345 112 : break;
346 : }
347 : }
348 :
349 : /* if you prepare and then execute passing an array of params keyed by names,
350 : * then this will trigger, and we don't want that */
351 112 : if (param->paramno == -1) {
352 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Did not found column name '%s' in the defined columns; it will not be bound", param->name);
353 : }
354 : }
355 :
356 11925 : if (param->name) {
357 10589 : if (is_param && param->name[0] != ':') {
358 5014 : char *temp = emalloc(++param->namelen + 1);
359 5014 : temp[0] = ':';
360 5014 : memmove(temp+1, param->name, param->namelen);
361 5014 : param->name = temp;
362 : } else {
363 561 : param->name = estrndup(param->name, param->namelen);
364 : }
365 : }
366 :
367 11925 : if (is_param && !rewrite_name_to_position(stmt, param TSRMLS_CC)) {
368 99 : if (param->name) {
369 99 : efree(param->name);
370 99 : param->name = NULL;
371 : }
372 99 : return 0;
373 : }
374 :
375 : /* ask the driver to perform any normalization it needs on the
376 : * parameter name. Note that it is illegal for the driver to take
377 : * a reference to param, as it resides in transient storage only
378 : * at this time. */
379 11826 : if (stmt->methods->param_hook) {
380 11826 : if (!stmt->methods->param_hook(stmt, param, PDO_PARAM_EVT_NORMALIZE
381 : TSRMLS_CC)) {
382 21 : if (param->name) {
383 21 : efree(param->name);
384 21 : param->name = NULL;
385 : }
386 21 : return 0;
387 : }
388 : }
389 :
390 : /* delete any other parameter registered with this number.
391 : * If the parameter is named, it will be removed and correctly
392 : * disposed of by the hash_update call that follows */
393 11805 : if (param->paramno >= 0) {
394 6627 : zend_hash_index_del(hash, param->paramno);
395 : }
396 :
397 : /* allocate storage for the parameter, keyed by its "canonical" name */
398 11805 : if (param->name) {
399 5536 : zend_hash_update(hash, param->name, param->namelen, param,
400 : sizeof(*param), (void**)&pparam);
401 : } else {
402 6269 : zend_hash_index_update(hash, param->paramno, param, sizeof(*param),
403 : (void**)&pparam);
404 : }
405 :
406 : /* tell the driver we just created a parameter */
407 11805 : if (stmt->methods->param_hook) {
408 11805 : if (!stmt->methods->param_hook(stmt, pparam, PDO_PARAM_EVT_ALLOC
409 : TSRMLS_CC)) {
410 : /* undo storage allocation; the hash will free the parameter
411 : * name if required */
412 102 : if (pparam->name) {
413 3 : zend_hash_del(hash, pparam->name, pparam->namelen);
414 : } else {
415 99 : zend_hash_index_del(hash, pparam->paramno);
416 : }
417 : /* param->parameter is freed by hash dtor */
418 102 : param->parameter = NULL;
419 102 : return 0;
420 : }
421 : }
422 11703 : return 1;
423 : }
424 : /* }}} */
425 :
426 : /* {{{ proto bool PDOStatement::execute([array $bound_input_params])
427 : Execute a prepared statement, optionally binding parameters */
428 : static PHP_METHOD(PDOStatement, execute)
429 2025 : {
430 2025 : zval *input_params = NULL;
431 2025 : int ret = 1;
432 2025 : PHP_STMT_GET_OBJ;
433 :
434 2025 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|a!", &input_params)) {
435 0 : RETURN_FALSE;
436 : }
437 :
438 2025 : PDO_STMT_CLEAR_ERR();
439 :
440 2025 : if (input_params) {
441 : struct pdo_bound_param_data param;
442 : zval **tmp;
443 : uint str_length;
444 : ulong num_index;
445 :
446 780 : if (stmt->bound_params) {
447 155 : zend_hash_destroy(stmt->bound_params);
448 155 : FREE_HASHTABLE(stmt->bound_params);
449 155 : stmt->bound_params = NULL;
450 : }
451 :
452 780 : zend_hash_internal_pointer_reset(Z_ARRVAL_P(input_params));
453 12377 : while (SUCCESS == zend_hash_get_current_data(Z_ARRVAL_P(input_params), (void*)&tmp)) {
454 11029 : memset(¶m, 0, sizeof(param));
455 :
456 11029 : if (HASH_KEY_IS_STRING == zend_hash_get_current_key_ex(Z_ARRVAL_P(input_params),
457 : ¶m.name, &str_length, &num_index, 0, NULL)) {
458 : /* yes this is correct. we don't want to count the null byte. ask wez */
459 5349 : param.namelen = str_length - 1;
460 5349 : param.paramno = -1;
461 : } else {
462 : /* we're okay to be zero based here */
463 : if (num_index < 0) {
464 : pdo_raise_impl_error(stmt->dbh, stmt, "HY093", NULL TSRMLS_CC);
465 : RETURN_FALSE;
466 : }
467 5680 : param.paramno = num_index;
468 : }
469 :
470 11029 : param.param_type = PDO_PARAM_STR;
471 11029 : MAKE_STD_ZVAL(param.parameter);
472 11029 : *param.parameter = **tmp;
473 11029 : zval_copy_ctor(param.parameter);
474 11029 : INIT_PZVAL(param.parameter);
475 :
476 11029 : if (!really_register_bound_param(¶m, stmt, 1 TSRMLS_CC)) {
477 212 : if (param.parameter) {
478 111 : zval_ptr_dtor(¶m.parameter);
479 : }
480 212 : RETURN_FALSE;
481 : }
482 :
483 10817 : zend_hash_move_forward(Z_ARRVAL_P(input_params));
484 : }
485 : }
486 :
487 1813 : if (PDO_PLACEHOLDER_NONE == stmt->supports_placeholders) {
488 : /* handle the emulated parameter binding,
489 : * stmt->active_query_string holds the query with binds expanded and
490 : * quoted.
491 : */
492 :
493 839 : ret = pdo_parse_params(stmt, stmt->query_string, stmt->query_stringlen,
494 : &stmt->active_query_string, &stmt->active_query_stringlen TSRMLS_CC);
495 :
496 839 : if (ret == 0) {
497 : /* no changes were made */
498 327 : stmt->active_query_string = stmt->query_string;
499 327 : stmt->active_query_stringlen = stmt->query_stringlen;
500 512 : } else if (ret == -1) {
501 : /* something broke */
502 201 : PDO_HANDLE_STMT_ERR();
503 201 : RETURN_FALSE;
504 : }
505 974 : } else if (!dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_PRE TSRMLS_CC)) {
506 5 : PDO_HANDLE_STMT_ERR();
507 5 : RETURN_FALSE;
508 : }
509 1607 : if (stmt->methods->executer(stmt TSRMLS_CC)) {
510 1551 : if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
511 307 : efree(stmt->active_query_string);
512 : }
513 1551 : stmt->active_query_string = NULL;
514 1551 : if (!stmt->executed) {
515 : /* this is the first execute */
516 :
517 1181 : if (stmt->dbh->alloc_own_columns && !stmt->columns) {
518 : /* for "big boy" drivers, we need to allocate memory to fetch
519 : * the results into, so lets do that now */
520 952 : ret = pdo_stmt_describe_columns(stmt TSRMLS_CC);
521 : }
522 :
523 1181 : stmt->executed = 1;
524 : }
525 :
526 1551 : if (ret && !dispatch_param_event(stmt, PDO_PARAM_EVT_EXEC_POST TSRMLS_CC)) {
527 0 : RETURN_FALSE;
528 : }
529 :
530 1551 : RETURN_BOOL(ret);
531 : }
532 56 : if (stmt->active_query_string && stmt->active_query_string != stmt->query_string) {
533 4 : efree(stmt->active_query_string);
534 : }
535 56 : stmt->active_query_string = NULL;
536 56 : PDO_HANDLE_STMT_ERR();
537 56 : RETURN_FALSE;
538 : }
539 : /* }}} */
540 :
541 : static inline void fetch_value(pdo_stmt_t *stmt, zval *dest, int colno, int *type_override TSRMLS_DC) /* {{{ */
542 4774 : {
543 : struct pdo_column_data *col;
544 4774 : char *value = NULL;
545 4774 : unsigned long value_len = 0;
546 4774 : int caller_frees = 0;
547 : int type, new_type;
548 :
549 4774 : col = &stmt->columns[colno];
550 4774 : type = PDO_PARAM_TYPE(col->param_type);
551 4774 : new_type = type_override ? PDO_PARAM_TYPE(*type_override) : type;
552 :
553 4774 : value = NULL;
554 4774 : value_len = 0;
555 :
556 4774 : stmt->methods->get_col(stmt, colno, &value, &value_len, &caller_frees TSRMLS_CC);
557 :
558 4774 : switch (type) {
559 : case PDO_PARAM_ZVAL:
560 1778 : if (value && value_len == sizeof(zval)) {
561 889 : int need_copy = (new_type != PDO_PARAM_ZVAL || stmt->dbh->stringify) ? 1 : 0;
562 889 : zval *zv = *(zval**)value;
563 889 : ZVAL_ZVAL(dest, zv, need_copy, 1);
564 : } else {
565 0 : ZVAL_NULL(dest);
566 : }
567 :
568 889 : if (Z_TYPE_P(dest) == IS_NULL) {
569 12 : type = new_type;
570 : }
571 889 : break;
572 :
573 : case PDO_PARAM_INT:
574 191 : if (value && value_len == sizeof(long)) {
575 191 : ZVAL_LONG(dest, *(long*)value);
576 191 : break;
577 : }
578 0 : ZVAL_NULL(dest);
579 0 : break;
580 :
581 : case PDO_PARAM_BOOL:
582 0 : if (value && value_len == sizeof(zend_bool)) {
583 0 : ZVAL_BOOL(dest, *(zend_bool*)value);
584 0 : break;
585 : }
586 0 : ZVAL_NULL(dest);
587 0 : break;
588 :
589 : case PDO_PARAM_LOB:
590 15 : if (value == NULL) {
591 2 : ZVAL_NULL(dest);
592 13 : } else if (value_len == 0) {
593 : /* Warning, empty strings need to be passed as stream */
594 15 : if (stmt->dbh->stringify || new_type == PDO_PARAM_STR) {
595 5 : char *buf = NULL;
596 : size_t len;
597 5 : len = php_stream_copy_to_mem((php_stream*)value, &buf, PHP_STREAM_COPY_ALL, 0);
598 5 : if(buf == NULL) {
599 3 : ZVAL_EMPTY_STRING(dest);
600 : } else {
601 2 : ZVAL_STRINGL(dest, buf, len, 0);
602 : }
603 5 : php_stream_close((php_stream*)value);
604 : } else {
605 6 : php_stream_to_zval((php_stream*)value, dest);
606 : }
607 3 : } else if (!stmt->dbh->stringify && new_type != PDO_PARAM_STR) {
608 : /* they gave us a string, but LOBs are represented as streams in PDO */
609 : php_stream *stm;
610 : #ifdef TEMP_STREAM_TAKE_BUFFER
611 1 : if (caller_frees) {
612 1 : stm = php_stream_memory_open(TEMP_STREAM_TAKE_BUFFER, value, value_len);
613 1 : if (stm) {
614 1 : caller_frees = 0;
615 : }
616 : } else
617 : #endif
618 : {
619 0 : stm = php_stream_memory_open(TEMP_STREAM_READONLY, value, value_len);
620 : }
621 1 : if (stm) {
622 1 : php_stream_to_zval(stm, dest);
623 : } else {
624 0 : ZVAL_NULL(dest);
625 : }
626 : } else {
627 1 : ZVAL_STRINGL(dest, value, value_len, !caller_frees);
628 1 : if (caller_frees) {
629 1 : caller_frees = 0;
630 : }
631 : }
632 14 : break;
633 :
634 : case PDO_PARAM_STR:
635 3679 : if (value && !(value_len == 0 && stmt->dbh->oracle_nulls == PDO_NULL_EMPTY_STRING)) {
636 3581 : ZVAL_STRINGL(dest, value, value_len, !caller_frees);
637 3581 : if (caller_frees) {
638 0 : caller_frees = 0;
639 : }
640 3581 : break;
641 : }
642 : default:
643 98 : ZVAL_NULL(dest);
644 : }
645 :
646 4773 : if (type != new_type) {
647 369 : switch (new_type) {
648 : case PDO_PARAM_INT:
649 72 : convert_to_long_ex(&dest);
650 72 : break;
651 : case PDO_PARAM_BOOL:
652 0 : convert_to_boolean_ex(&dest);
653 0 : break;
654 : case PDO_PARAM_STR:
655 279 : convert_to_string_ex(&dest);
656 279 : break;
657 : case PDO_PARAM_NULL:
658 0 : convert_to_null_ex(&dest);
659 : break;
660 : default:
661 : ;
662 : }
663 : }
664 :
665 4773 : if (caller_frees && value) {
666 0 : efree(value);
667 : }
668 :
669 4773 : if (stmt->dbh->stringify) {
670 3277 : switch (Z_TYPE_P(dest)) {
671 : case IS_LONG:
672 : case IS_DOUBLE:
673 269 : convert_to_string(dest);
674 : break;
675 : }
676 : }
677 :
678 4773 : if (Z_TYPE_P(dest) == IS_NULL && stmt->dbh->oracle_nulls == PDO_NULL_TO_STRING) {
679 2 : ZVAL_EMPTY_STRING(dest);
680 : }
681 4773 : }
682 : /* }}} */
683 :
684 : static int do_fetch_common(pdo_stmt_t *stmt, enum pdo_fetch_orientation ori,
685 : long offset, int do_bind TSRMLS_DC) /* {{{ */
686 3018 : {
687 3018 : if (!stmt->executed) {
688 38 : return 0;
689 : }
690 :
691 2980 : if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_PRE TSRMLS_CC)) {
692 0 : return 0;
693 : }
694 :
695 2980 : if (!stmt->methods->fetcher(stmt, ori, offset TSRMLS_CC)) {
696 656 : return 0;
697 : }
698 :
699 : /* some drivers might need to describe the columns now */
700 2324 : if (!stmt->columns && !pdo_stmt_describe_columns(stmt TSRMLS_CC)) {
701 0 : return 0;
702 : }
703 :
704 2324 : if (!dispatch_param_event(stmt, PDO_PARAM_EVT_FETCH_POST TSRMLS_CC)) {
705 0 : return 0;
706 : }
707 :
708 2324 : if (do_bind && stmt->bound_columns) {
709 : /* update those bound column variables now */
710 : struct pdo_bound_param_data *param;
711 :
712 526 : zend_hash_internal_pointer_reset(stmt->bound_columns);
713 1966 : while (SUCCESS == zend_hash_get_current_data(stmt->bound_columns, (void**)¶m)) {
714 914 : if (param->paramno >= 0) {
715 914 : convert_to_string(param->parameter);
716 :
717 : /* delete old value */
718 914 : zval_dtor(param->parameter);
719 :
720 : /* set new value */
721 914 : fetch_value(stmt, param->parameter, param->paramno, (int *)¶m->param_type TSRMLS_CC);
722 :
723 : /* TODO: some smart thing that avoids duplicating the value in the
724 : * general loop below. For now, if you're binding output columns,
725 : * it's better to use LAZY or BOUND fetches if you want to shave
726 : * off those cycles */
727 : }
728 :
729 914 : zend_hash_move_forward(stmt->bound_columns);
730 : }
731 : }
732 :
733 2324 : return 1;
734 : }
735 : /* }}} */
736 :
737 : static int do_fetch_class_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
738 211 : {
739 211 : zend_class_entry * ce = stmt->fetch.cls.ce;
740 211 : zend_fcall_info * fci = &stmt->fetch.cls.fci;
741 211 : zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
742 :
743 211 : fci->size = sizeof(zend_fcall_info);
744 :
745 211 : if (!ce) {
746 1 : stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
747 1 : ce = ZEND_STANDARD_CLASS_DEF_PTR;
748 : }
749 :
750 211 : if (ce->constructor) {
751 148 : fci->function_table = &ce->function_table;
752 148 : fci->function_name = NULL;
753 148 : fci->symbol_table = NULL;
754 148 : fci->retval_ptr_ptr = &stmt->fetch.cls.retval_ptr;
755 148 : if (stmt->fetch.cls.ctor_args) {
756 44 : HashTable *ht = Z_ARRVAL_P(stmt->fetch.cls.ctor_args);
757 : Bucket *p;
758 :
759 44 : fci->param_count = 0;
760 44 : fci->params = safe_emalloc(sizeof(zval**), ht->nNumOfElements, 0);
761 44 : p = ht->pListHead;
762 135 : while (p != NULL) {
763 47 : fci->params[fci->param_count++] = (zval**)p->pData;
764 47 : p = p->pListNext;
765 : }
766 : } else {
767 104 : fci->param_count = 0;
768 104 : fci->params = NULL;
769 : }
770 148 : fci->no_separation = 1;
771 :
772 148 : fcc->initialized = 1;
773 148 : fcc->function_handler = ce->constructor;
774 148 : fcc->calling_scope = EG(scope);
775 148 : fcc->called_scope = ce;
776 148 : return 1;
777 63 : } else if (stmt->fetch.cls.ctor_args) {
778 0 : 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);
779 0 : return 0;
780 : } else {
781 63 : return 1; /* no ctor no args is also ok */
782 : }
783 : }
784 : /* }}} */
785 :
786 : 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) /* {{{ */
787 48 : {
788 48 : zval *object = NULL, **method = NULL;
789 48 : char *fname = NULL, *cname;
790 48 : zend_class_entry * ce = NULL, **pce;
791 : zend_function *function_handler;
792 :
793 48 : if (Z_TYPE_P(callable) == IS_ARRAY) {
794 30 : if (Z_ARRVAL_P(callable)->nNumOfElements < 2) {
795 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC);
796 0 : return 0;
797 : }
798 30 : object = *(zval**)Z_ARRVAL_P(callable)->pListHead->pData;
799 30 : method = (zval**)Z_ARRVAL_P(callable)->pListHead->pListNext->pData;
800 :
801 30 : if (Z_TYPE_P(object) == IS_STRING) { /* static call */
802 6 : if (zend_lookup_class(Z_STRVAL_P(object), Z_STRLEN_P(object), &pce TSRMLS_CC) == FAILURE) {
803 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not exist" TSRMLS_CC);
804 0 : return 0;
805 : } else {
806 6 : ce = *pce;
807 : }
808 6 : object = NULL;
809 24 : } else if (Z_TYPE_P(object) == IS_OBJECT) { /* object call */
810 24 : ce = Z_OBJCE_P(object);
811 : } else {
812 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback; bogus object/class name" TSRMLS_CC);
813 0 : return 0;
814 : }
815 :
816 30 : if (Z_TYPE_PP(method) != IS_STRING) {
817 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback; bogus method name" TSRMLS_CC);
818 0 : return 0;
819 : }
820 18 : } else if (Z_TYPE_P(callable) == IS_STRING) {
821 18 : method = &callable;
822 : }
823 :
824 48 : if (!method || !zend_is_callable(callable, 0, &fname TSRMLS_CC)) {
825 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function must be a valid callback" TSRMLS_CC);
826 0 : if (fname) {
827 0 : efree(fname);
828 : }
829 0 : return 0;
830 : }
831 :
832 : /* ATM we do not support array($obj, "CLASS::FUNC") or "CLASS_FUNC" */
833 48 : cname = fname;
834 48 : if ((fname = strstr(fname, "::")) == NULL) {
835 18 : fname = cname;
836 18 : cname = NULL;
837 : } else {
838 30 : *fname = '\0';
839 30 : fname += 2;
840 : }
841 48 : if (cname) {
842 30 : if (zend_lookup_class(cname, strlen(cname), &pce TSRMLS_CC) == FAILURE) {
843 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class does not exist" TSRMLS_CC);
844 0 : return 0;
845 : } else {
846 30 : if (ce) {
847 : /* pce must be base of ce or ce itself */
848 30 : if (ce != *pce && !instanceof_function(ce, *pce TSRMLS_CC)) {
849 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied class has bogus lineage" TSRMLS_CC);
850 0 : return 0;
851 : }
852 : }
853 30 : ce = *pce;
854 : }
855 : }
856 :
857 48 : zend_str_tolower_copy(fname, fname, strlen(fname));
858 48 : fci->function_table = ce ? &ce->function_table : EG(function_table);
859 48 : if (zend_hash_find(fci->function_table, fname, strlen(fname)+1, (void **)&function_handler) == FAILURE) {
860 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "user-supplied function does not exist" TSRMLS_CC);
861 0 : return 0;
862 : }
863 48 : efree(cname ? cname : fname);
864 :
865 48 : fci->size = sizeof(zend_fcall_info);
866 48 : fci->function_name = NULL;
867 48 : fci->symbol_table = NULL;
868 48 : fci->param_count = num_args; /* probably less */
869 48 : fci->params = safe_emalloc(sizeof(zval**), num_args, 0);
870 48 : fci->object_ptr = object;
871 :
872 48 : fcc->initialized = 1;
873 48 : fcc->function_handler = function_handler;
874 48 : fcc->calling_scope = EG(scope);
875 48 : fcc->called_scope = object ? Z_OBJCE_P(object) : NULL;
876 48 : fcc->object_ptr = object;
877 :
878 48 : return 1;
879 : }
880 : /* }}} */
881 :
882 : static int do_fetch_func_prepare(pdo_stmt_t *stmt TSRMLS_DC) /* {{{ */
883 48 : {
884 48 : zend_fcall_info * fci = &stmt->fetch.cls.fci;
885 48 : zend_fcall_info_cache * fcc = &stmt->fetch.cls.fcc;
886 :
887 48 : if (!make_callable_ex(stmt, stmt->fetch.func.function, fci, fcc, stmt->column_count TSRMLS_CC)) {
888 0 : return 0;
889 : } else {
890 48 : stmt->fetch.func.values = safe_emalloc(sizeof(zval*), stmt->column_count, 0);
891 48 : return 1;
892 : }
893 : }
894 : /* }}} */
895 :
896 : static int do_fetch_opt_finish(pdo_stmt_t *stmt, int free_ctor_agrs TSRMLS_DC) /* {{{ */
897 3515 : {
898 : /* fci.size is used to check if it is valid */
899 3515 : if (stmt->fetch.cls.fci.size && stmt->fetch.cls.fci.params) {
900 92 : efree(stmt->fetch.cls.fci.params);
901 92 : stmt->fetch.cls.fci.params = NULL;
902 : }
903 3515 : stmt->fetch.cls.fci.size = 0;
904 3515 : if (stmt->fetch.cls.ctor_args && free_ctor_agrs) {
905 26 : zval_ptr_dtor(&stmt->fetch.cls.ctor_args);
906 26 : stmt->fetch.cls.ctor_args = NULL;
907 26 : stmt->fetch.cls.fci.param_count = 0;
908 : }
909 3515 : if (stmt->fetch.func.values) {
910 48 : efree(stmt->fetch.func.values);
911 48 : stmt->fetch.func.values = NULL;
912 : }
913 3515 : return 1;
914 : }
915 : /* }}} */
916 :
917 : /* perform a fetch. If do_bind is true, update any bound columns.
918 : * If return_value is not null, store values into it according to HOW. */
919 : static int do_fetch(pdo_stmt_t *stmt, int do_bind, zval *return_value,
920 : enum pdo_fetch_type how, enum pdo_fetch_orientation ori, long offset, zval *return_all TSRMLS_DC) /* {{{ */
921 2932 : {
922 2932 : int flags, idx, old_arg_count = 0;
923 2932 : zend_class_entry *ce = NULL, *old_ce = NULL;
924 2932 : zval grp_val, *grp, **pgrp, *retval, *old_ctor_args = NULL;
925 : int colno;
926 :
927 2932 : if (how == PDO_FETCH_USE_DEFAULT) {
928 349 : how = stmt->default_fetch_type;
929 : }
930 2932 : flags = how & PDO_FETCH_FLAGS;
931 2932 : how = how & ~PDO_FETCH_FLAGS;
932 :
933 2932 : if (!do_fetch_common(stmt, ori, offset, do_bind TSRMLS_CC)) {
934 689 : return 0;
935 : }
936 :
937 2243 : if (how == PDO_FETCH_BOUND) {
938 413 : RETVAL_TRUE;
939 413 : return 1;
940 : }
941 :
942 1956 : if (flags & PDO_FETCH_GROUP && stmt->fetch.column == -1) {
943 126 : colno = 1;
944 : } else {
945 1704 : colno = stmt->fetch.column;
946 : }
947 :
948 1830 : if (return_value) {
949 1830 : int i = 0;
950 :
951 1830 : if (how == PDO_FETCH_LAZY) {
952 23 : get_lazy_object(stmt, return_value TSRMLS_CC);
953 23 : return 1;
954 : }
955 :
956 1807 : RETVAL_FALSE;
957 :
958 1807 : switch (how) {
959 : case PDO_FETCH_USE_DEFAULT:
960 : case PDO_FETCH_ASSOC:
961 : case PDO_FETCH_BOTH:
962 : case PDO_FETCH_NUM:
963 : case PDO_FETCH_NAMED:
964 1020 : if (!return_all) {
965 926 : ALLOC_HASHTABLE(return_value->value.ht);
966 926 : zend_hash_init(return_value->value.ht, stmt->column_count, NULL, ZVAL_PTR_DTOR, 0);
967 926 : Z_TYPE_P(return_value) = IS_ARRAY;
968 : } else {
969 94 : array_init(return_value);
970 : }
971 1020 : break;
972 :
973 : case PDO_FETCH_KEY_PAIR:
974 102 : if (stmt->column_count != 2) {
975 6 : 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);
976 6 : return 0;
977 : }
978 96 : if (!return_all) {
979 6 : array_init(return_value);
980 : }
981 96 : break;
982 :
983 : case PDO_FETCH_COLUMN:
984 206 : if (colno >= 0 && colno < stmt->column_count) {
985 230 : if (flags == PDO_FETCH_GROUP && stmt->fetch.column == -1) {
986 24 : fetch_value(stmt, return_value, 1, NULL TSRMLS_CC);
987 182 : } else if (flags == PDO_FETCH_GROUP && colno) {
988 0 : fetch_value(stmt, return_value, 0, NULL TSRMLS_CC);
989 : } else {
990 182 : fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
991 : }
992 206 : if (!return_all) {
993 44 : return 1;
994 : } else {
995 162 : break;
996 : }
997 : } else {
998 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid column index" TSRMLS_CC);
999 : }
1000 0 : return 0;
1001 :
1002 : case PDO_FETCH_OBJ:
1003 18 : object_init_ex(return_value, ZEND_STANDARD_CLASS_DEF_PTR);
1004 18 : break;
1005 :
1006 : case PDO_FETCH_CLASS:
1007 241 : if (flags & PDO_FETCH_CLASSTYPE) {
1008 : zval val;
1009 : zend_class_entry **cep;
1010 :
1011 96 : old_ce = stmt->fetch.cls.ce;
1012 96 : old_ctor_args = stmt->fetch.cls.ctor_args;
1013 96 : old_arg_count = stmt->fetch.cls.fci.param_count;
1014 96 : do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1015 :
1016 96 : INIT_PZVAL(&val);
1017 96 : fetch_value(stmt, &val, i++, NULL TSRMLS_CC);
1018 96 : if (Z_TYPE(val) != IS_NULL) {
1019 73 : convert_to_string(&val);
1020 73 : if (zend_lookup_class(Z_STRVAL(val), Z_STRLEN(val), &cep TSRMLS_CC) == FAILURE) {
1021 1 : stmt->fetch.cls.ce = ZEND_STANDARD_CLASS_DEF_PTR;
1022 : } else {
1023 72 : stmt->fetch.cls.ce = *cep;
1024 : }
1025 : }
1026 :
1027 96 : do_fetch_class_prepare(stmt TSRMLS_CC);
1028 96 : zval_dtor(&val);
1029 : }
1030 241 : ce = stmt->fetch.cls.ce;
1031 241 : if (!ce) {
1032 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch class specified" TSRMLS_CC);
1033 6 : return 0;
1034 : }
1035 235 : if ((flags & PDO_FETCH_SERIALIZE) == 0) {
1036 205 : object_init_ex(return_value, ce);
1037 205 : if (!stmt->fetch.cls.fci.size) {
1038 17 : if (!do_fetch_class_prepare(stmt TSRMLS_CC))
1039 : {
1040 0 : return 0;
1041 : }
1042 : }
1043 205 : if (ce->constructor && (flags & PDO_FETCH_PROPS_LATE)) {
1044 9 : stmt->fetch.cls.fci.object_ptr = return_value;
1045 9 : stmt->fetch.cls.fcc.object_ptr = return_value;
1046 9 : if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
1047 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
1048 0 : return 0;
1049 : } else {
1050 9 : if (stmt->fetch.cls.retval_ptr) {
1051 9 : zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
1052 : }
1053 : }
1054 : }
1055 : }
1056 235 : break;
1057 :
1058 : case PDO_FETCH_INTO:
1059 42 : if (!stmt->fetch.into) {
1060 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch-into object specified." TSRMLS_CC);
1061 0 : return 0;
1062 : break;
1063 : }
1064 :
1065 42 : Z_TYPE_P(return_value) = IS_OBJECT;
1066 42 : Z_OBJ_HANDLE_P(return_value) = Z_OBJ_HANDLE_P(stmt->fetch.into);
1067 42 : Z_OBJ_HT_P(return_value) = Z_OBJ_HT_P(stmt->fetch.into);
1068 42 : zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
1069 :
1070 42 : if (zend_get_class_entry(return_value TSRMLS_CC) == ZEND_STANDARD_CLASS_DEF_PTR) {
1071 0 : how = PDO_FETCH_OBJ;
1072 : }
1073 42 : break;
1074 :
1075 : case PDO_FETCH_FUNC:
1076 178 : if (!stmt->fetch.func.function) {
1077 4 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "No fetch function specified" TSRMLS_CC);
1078 4 : return 0;
1079 : }
1080 174 : if (!stmt->fetch.func.fci.size) {
1081 0 : if (!do_fetch_func_prepare(stmt TSRMLS_CC))
1082 : {
1083 0 : return 0;
1084 : }
1085 : }
1086 174 : break;
1087 :
1088 :
1089 : default:
1090 : /* shouldn't happen */
1091 0 : return 0;
1092 : }
1093 :
1094 1747 : if (return_all && how != PDO_FETCH_KEY_PAIR) {
1095 328 : INIT_PZVAL(&grp_val);
1096 328 : if (flags == PDO_FETCH_GROUP && how == PDO_FETCH_COLUMN && stmt->fetch.column > 0) {
1097 0 : fetch_value(stmt, &grp_val, colno, NULL TSRMLS_CC);
1098 : } else {
1099 328 : fetch_value(stmt, &grp_val, i, NULL TSRMLS_CC);
1100 : }
1101 328 : convert_to_string(&grp_val);
1102 328 : if (how == PDO_FETCH_COLUMN) {
1103 162 : i = stmt->column_count; /* no more data to fetch */
1104 : } else {
1105 166 : i++;
1106 : }
1107 : }
1108 :
1109 1747 : switch (how) {
1110 : case PDO_FETCH_CLASS:
1111 235 : if (ce->constructor && !(flags & (PDO_FETCH_PROPS_LATE | PDO_FETCH_SERIALIZE))) {
1112 140 : stmt->fetch.cls.fci.object_ptr = return_value;
1113 140 : stmt->fetch.cls.fcc.object_ptr = return_value;
1114 140 : if (zend_call_function(&stmt->fetch.cls.fci, &stmt->fetch.cls.fcc TSRMLS_CC) == FAILURE) {
1115 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call class constructor" TSRMLS_CC);
1116 0 : return 0;
1117 : } else {
1118 140 : if (stmt->fetch.cls.retval_ptr) {
1119 140 : zval_ptr_dtor(&stmt->fetch.cls.retval_ptr);
1120 : }
1121 : }
1122 : }
1123 235 : if (flags & PDO_FETCH_CLASSTYPE) {
1124 96 : do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1125 96 : stmt->fetch.cls.ce = old_ce;
1126 96 : stmt->fetch.cls.ctor_args = old_ctor_args;
1127 96 : stmt->fetch.cls.fci.param_count = old_arg_count;
1128 : }
1129 : break;
1130 :
1131 : default:
1132 : break;
1133 : }
1134 :
1135 4660 : for (idx = 0; i < stmt->column_count; i++, idx++) {
1136 : zval *val;
1137 3021 : MAKE_STD_ZVAL(val);
1138 3021 : fetch_value(stmt, val, i, NULL TSRMLS_CC);
1139 :
1140 3020 : switch (how) {
1141 : case PDO_FETCH_ASSOC:
1142 1483 : add_assoc_zval(return_value, stmt->columns[i].name, val);
1143 1483 : break;
1144 :
1145 : case PDO_FETCH_KEY_PAIR:
1146 : {
1147 : zval *tmp;
1148 96 : MAKE_STD_ZVAL(tmp);
1149 96 : fetch_value(stmt, tmp, ++i, NULL TSRMLS_CC);
1150 :
1151 96 : if (Z_TYPE_P(val) == IS_LONG) {
1152 0 : zend_hash_index_update((return_all ? Z_ARRVAL_P(return_all) : Z_ARRVAL_P(return_value)), Z_LVAL_P(val), &tmp, sizeof(zval *), NULL);
1153 : } else {
1154 96 : convert_to_string(val);
1155 96 : 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);
1156 : }
1157 96 : zval_ptr_dtor(&val);
1158 96 : return 1;
1159 : }
1160 : break;
1161 :
1162 : case PDO_FETCH_USE_DEFAULT:
1163 : case PDO_FETCH_BOTH:
1164 209 : add_assoc_zval(return_value, stmt->columns[i].name, val);
1165 209 : Z_ADDREF_P(val);
1166 209 : add_next_index_zval(return_value, val);
1167 209 : break;
1168 :
1169 : case PDO_FETCH_NAMED:
1170 : /* already have an item with this name? */
1171 : {
1172 0 : zval **curr_val = NULL;
1173 0 : if (zend_hash_find(Z_ARRVAL_P(return_value), stmt->columns[i].name,
1174 : strlen(stmt->columns[i].name)+1,
1175 : (void**)&curr_val) == SUCCESS) {
1176 : zval *arr;
1177 0 : if (Z_TYPE_PP(curr_val) != IS_ARRAY) {
1178 : /* a little bit of black magic here:
1179 : * we're creating a new array and swapping it for the
1180 : * zval that's already stored in the hash under the name
1181 : * we want. We then add that zval to the array.
1182 : * This is effectively the same thing as:
1183 : * if (!is_array($hash[$name])) {
1184 : * $hash[$name] = array($hash[$name]);
1185 : * }
1186 : * */
1187 : zval *cur;
1188 :
1189 0 : MAKE_STD_ZVAL(arr);
1190 0 : array_init(arr);
1191 :
1192 0 : cur = *curr_val;
1193 0 : *curr_val = arr;
1194 :
1195 0 : add_next_index_zval(arr, cur);
1196 : } else {
1197 0 : arr = *curr_val;
1198 : }
1199 0 : add_next_index_zval(arr, val);
1200 : } else {
1201 0 : add_assoc_zval(return_value, stmt->columns[i].name, val);
1202 : }
1203 : }
1204 0 : break;
1205 :
1206 : case PDO_FETCH_NUM:
1207 275 : add_next_index_zval(return_value, val);
1208 275 : break;
1209 :
1210 : case PDO_FETCH_OBJ:
1211 : case PDO_FETCH_INTO:
1212 150 : zend_update_property(NULL, return_value,
1213 : stmt->columns[i].name, stmt->columns[i].namelen,
1214 : val TSRMLS_CC);
1215 144 : zval_ptr_dtor(&val);
1216 144 : break;
1217 :
1218 : case PDO_FETCH_CLASS:
1219 948 : if ((flags & PDO_FETCH_SERIALIZE) == 0 || idx) {
1220 459 : zend_update_property(ce, return_value,
1221 : stmt->columns[i].name, stmt->columns[i].namelen,
1222 : val TSRMLS_CC);
1223 459 : zval_ptr_dtor(&val);
1224 : } else {
1225 : #ifdef MBO_0
1226 : php_unserialize_data_t var_hash;
1227 :
1228 : PHP_VAR_UNSERIALIZE_INIT(var_hash);
1229 : 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) {
1230 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize data" TSRMLS_CC);
1231 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1232 : return 0;
1233 : }
1234 : PHP_VAR_UNSERIALIZE_DESTROY(var_hash);
1235 : #endif
1236 : #if PHP_MAJOR_VERSION > 5 || PHP_MINOR_VERSION >= 1
1237 30 : if (!ce->unserialize) {
1238 5 : zval_ptr_dtor(&val);
1239 5 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
1240 5 : return 0;
1241 25 : } 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) {
1242 0 : zval_ptr_dtor(&val);
1243 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "cannot unserialize class" TSRMLS_CC);
1244 0 : zval_dtor(return_value);
1245 0 : ZVAL_NULL(return_value);
1246 0 : return 0;
1247 : } else {
1248 25 : zval_ptr_dtor(&val);
1249 : }
1250 : #endif
1251 : }
1252 484 : break;
1253 :
1254 : case PDO_FETCH_FUNC:
1255 318 : stmt->fetch.func.values[idx] = val;
1256 318 : stmt->fetch.cls.fci.params[idx] = &stmt->fetch.func.values[idx];
1257 318 : break;
1258 :
1259 : default:
1260 0 : zval_ptr_dtor(&val);
1261 0 : pdo_raise_impl_error(stmt->dbh, stmt, "22003", "mode is out of range" TSRMLS_CC);
1262 0 : return 0;
1263 : break;
1264 : }
1265 : }
1266 :
1267 1639 : switch (how) {
1268 : case PDO_FETCH_FUNC:
1269 174 : stmt->fetch.func.fci.param_count = idx;
1270 174 : stmt->fetch.func.fci.retval_ptr_ptr = &retval;
1271 174 : if (zend_call_function(&stmt->fetch.func.fci, &stmt->fetch.func.fcc TSRMLS_CC) == FAILURE) {
1272 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not call user-supplied function" TSRMLS_CC);
1273 0 : return 0;
1274 : } else {
1275 174 : if (return_all) {
1276 24 : zval_ptr_dtor(&return_value); /* we don't need that */
1277 24 : return_value = retval;
1278 150 : } else if (retval) {
1279 150 : *return_value = *retval;
1280 150 : zval_copy_ctor(return_value);
1281 150 : INIT_PZVAL(return_value);
1282 150 : zval_ptr_dtor(&retval);
1283 : }
1284 : }
1285 666 : while(idx--) {
1286 318 : zval_ptr_dtor(&stmt->fetch.func.values[idx]);
1287 : }
1288 : break;
1289 :
1290 : default:
1291 : break;
1292 : }
1293 :
1294 1639 : if (return_all) {
1295 328 : if ((flags & PDO_FETCH_UNIQUE) == PDO_FETCH_UNIQUE) {
1296 216 : add_assoc_zval(return_all, Z_STRVAL(grp_val), return_value);
1297 : } else {
1298 112 : if (zend_symtable_find(Z_ARRVAL_P(return_all), Z_STRVAL(grp_val), Z_STRLEN(grp_val)+1, (void**)&pgrp) == FAILURE) {
1299 70 : MAKE_STD_ZVAL(grp);
1300 70 : array_init(grp);
1301 70 : add_assoc_zval(return_all, Z_STRVAL(grp_val), grp);
1302 : } else {
1303 42 : grp = *pgrp;
1304 : }
1305 112 : add_next_index_zval(grp, return_value);
1306 : }
1307 328 : zval_dtor(&grp_val);
1308 : }
1309 :
1310 : }
1311 :
1312 1639 : return 1;
1313 : }
1314 : /* }}} */
1315 :
1316 : static int pdo_stmt_verify_mode(pdo_stmt_t *stmt, long mode, int fetch_all TSRMLS_DC) /* {{{ */
1317 1672 : {
1318 1672 : int flags = mode & PDO_FETCH_FLAGS;
1319 :
1320 1672 : mode = mode & ~PDO_FETCH_FLAGS;
1321 :
1322 1672 : if (mode < 0 || mode > PDO_FETCH__MAX) {
1323 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1324 0 : return 0;
1325 : }
1326 :
1327 1672 : if (mode == PDO_FETCH_USE_DEFAULT) {
1328 109 : flags = stmt->default_fetch_type & PDO_FETCH_FLAGS;
1329 109 : mode = stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1330 : }
1331 :
1332 : #if PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION < 1
1333 : if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1334 : pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "PDO::FETCH_SERIALIZE is not supported in this PHP version" TSRMLS_CC);
1335 : return 0;
1336 : }
1337 : #endif
1338 :
1339 1672 : switch(mode) {
1340 : case PDO_FETCH_FUNC:
1341 53 : if (!fetch_all) {
1342 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_FUNC is only allowed in PDOStatement::fetchAll()" TSRMLS_CC);
1343 0 : return 0;
1344 : }
1345 53 : return 1;
1346 :
1347 : case PDO_FETCH_LAZY:
1348 23 : if (fetch_all) {
1349 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_LAZY can't be used with PDOStatement::fetchAll()" TSRMLS_CC);
1350 0 : return 0;
1351 : }
1352 : /* fall through */
1353 :
1354 : default:
1355 1477 : if ((flags & PDO_FETCH_SERIALIZE) == PDO_FETCH_SERIALIZE) {
1356 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_SERIALIZE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
1357 0 : return 0;
1358 : }
1359 1477 : if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1360 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "PDO::FETCH_CLASSTYPE can only be used together with PDO::FETCH_CLASS" TSRMLS_CC);
1361 0 : return 0;
1362 : }
1363 1477 : if (mode >= PDO_FETCH__MAX) {
1364 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "invalid fetch mode" TSRMLS_CC);
1365 0 : return 0;
1366 : }
1367 : /* no break; */
1368 :
1369 : case PDO_FETCH_CLASS:
1370 1619 : return 1;
1371 : }
1372 : }
1373 : /* }}} */
1374 :
1375 : /* {{{ proto mixed PDOStatement::fetch([int $how = PDO_FETCH_BOTH [, int $orientation [, int $offset]]])
1376 : Fetches the next row and returns it, or false if there are no more rows */
1377 : static PHP_METHOD(PDOStatement, fetch)
1378 1041 : {
1379 1041 : long how = PDO_FETCH_USE_DEFAULT;
1380 1041 : long ori = PDO_FETCH_ORI_NEXT;
1381 1041 : long off = 0;
1382 1041 : PHP_STMT_GET_OBJ;
1383 :
1384 1041 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lll", &how,
1385 : &ori, &off)) {
1386 0 : RETURN_FALSE;
1387 : }
1388 :
1389 1041 : PDO_STMT_CLEAR_ERR();
1390 :
1391 1041 : if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1392 0 : RETURN_FALSE;
1393 : }
1394 :
1395 1041 : if (!do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1396 144 : PDO_HANDLE_STMT_ERR();
1397 144 : RETURN_FALSE;
1398 : }
1399 : }
1400 : /* }}} */
1401 :
1402 : /* {{{ proto mixed PDOStatement::fetchObject([string class_name [, NULL|array ctor_args]])
1403 : Fetches the next row and returns it as an object. */
1404 : static PHP_METHOD(PDOStatement, fetchObject)
1405 5 : {
1406 5 : long how = PDO_FETCH_CLASS;
1407 5 : long ori = PDO_FETCH_ORI_NEXT;
1408 5 : long off = 0;
1409 : char *class_name;
1410 : int class_name_len;
1411 : zend_class_entry *old_ce;
1412 : zval *old_ctor_args, *ctor_args;
1413 5 : int error = 0, old_arg_count;
1414 :
1415 5 : PHP_STMT_GET_OBJ;
1416 :
1417 5 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|sz",
1418 : &class_name, &class_name_len, &ctor_args)) {
1419 0 : RETURN_FALSE;
1420 : }
1421 :
1422 5 : PDO_STMT_CLEAR_ERR();
1423 :
1424 5 : if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1425 0 : RETURN_FALSE;
1426 : }
1427 :
1428 5 : old_ce = stmt->fetch.cls.ce;
1429 5 : old_ctor_args = stmt->fetch.cls.ctor_args;
1430 5 : old_arg_count = stmt->fetch.cls.fci.param_count;
1431 :
1432 5 : do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1433 :
1434 5 : switch(ZEND_NUM_ARGS()) {
1435 : case 0:
1436 0 : stmt->fetch.cls.ce = zend_standard_class_def;
1437 0 : break;
1438 : case 2:
1439 5 : if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1440 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1441 0 : error = 1;
1442 0 : break;
1443 : }
1444 10 : if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1445 5 : ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1446 5 : *stmt->fetch.cls.ctor_args = *ctor_args;
1447 5 : zval_copy_ctor(stmt->fetch.cls.ctor_args);
1448 : } else {
1449 0 : stmt->fetch.cls.ctor_args = NULL;
1450 : }
1451 : /* no break */
1452 : case 1:
1453 5 : stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1454 :
1455 5 : if (!stmt->fetch.cls.ce) {
1456 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
1457 0 : error = 1;
1458 0 : break;
1459 : }
1460 : }
1461 :
1462 5 : if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1463 1 : error = 1;
1464 : }
1465 5 : if (error) {
1466 1 : PDO_HANDLE_STMT_ERR();
1467 : }
1468 5 : do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1469 :
1470 5 : stmt->fetch.cls.ce = old_ce;
1471 5 : stmt->fetch.cls.ctor_args = old_ctor_args;
1472 5 : stmt->fetch.cls.fci.param_count = old_arg_count;
1473 5 : if (error) {
1474 1 : RETURN_FALSE;
1475 : }
1476 : }
1477 : /* }}} */
1478 :
1479 : /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1480 : Returns a data of the specified column in the result set. */
1481 : static PHP_METHOD(PDOStatement, fetchColumn)
1482 86 : {
1483 86 : long col_n = 0;
1484 86 : PHP_STMT_GET_OBJ;
1485 :
1486 86 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
1487 0 : RETURN_FALSE;
1488 : }
1489 :
1490 86 : PDO_STMT_CLEAR_ERR();
1491 :
1492 86 : if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
1493 5 : PDO_HANDLE_STMT_ERR();
1494 5 : RETURN_FALSE;
1495 : }
1496 :
1497 81 : fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
1498 : }
1499 : /* }}} */
1500 :
1501 : /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1502 : Returns an array of all of the results. */
1503 : static PHP_METHOD(PDOStatement, fetchAll)
1504 493 : {
1505 493 : long how = PDO_FETCH_USE_DEFAULT;
1506 : zval *data, *return_all;
1507 : zval *arg2;
1508 : zend_class_entry *old_ce;
1509 493 : zval *old_ctor_args, *ctor_args = NULL;
1510 493 : int error = 0, flags, old_arg_count;
1511 493 : PHP_STMT_GET_OBJ;
1512 :
1513 493 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
1514 0 : RETURN_FALSE;
1515 : }
1516 :
1517 493 : if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
1518 0 : RETURN_FALSE;
1519 : }
1520 :
1521 493 : old_ce = stmt->fetch.cls.ce;
1522 493 : old_ctor_args = stmt->fetch.cls.ctor_args;
1523 493 : old_arg_count = stmt->fetch.cls.fci.param_count;
1524 :
1525 493 : do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1526 :
1527 493 : switch(how & ~PDO_FETCH_FLAGS) {
1528 : case PDO_FETCH_CLASS:
1529 61 : switch(ZEND_NUM_ARGS()) {
1530 : case 0:
1531 : case 1:
1532 6 : stmt->fetch.cls.ce = zend_standard_class_def;
1533 6 : break;
1534 : case 3:
1535 18 : if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1536 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1537 0 : error = 1;
1538 0 : break;
1539 : }
1540 18 : if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1541 5 : ctor_args = NULL;
1542 : }
1543 : /* no break */
1544 : case 2:
1545 55 : stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
1546 55 : if (Z_TYPE_P(arg2) != IS_STRING) {
1547 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
1548 0 : error = 1;
1549 0 : break;
1550 : } else {
1551 55 : stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1552 55 : if (!stmt->fetch.cls.ce) {
1553 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
1554 0 : error = 1;
1555 0 : break;
1556 : }
1557 : }
1558 : }
1559 61 : if (!error) {
1560 61 : do_fetch_class_prepare(stmt TSRMLS_CC);
1561 : }
1562 61 : break;
1563 :
1564 : case PDO_FETCH_FUNC:
1565 48 : switch(ZEND_NUM_ARGS()) {
1566 : case 0:
1567 : case 1:
1568 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
1569 0 : error = 1;
1570 0 : break;
1571 : case 3:
1572 : case 2:
1573 48 : stmt->fetch.func.function = arg2;
1574 48 : do_fetch_func_prepare(stmt TSRMLS_CC);
1575 : break;
1576 : }
1577 48 : break;
1578 :
1579 : case PDO_FETCH_COLUMN:
1580 83 : switch(ZEND_NUM_ARGS()) {
1581 : case 0:
1582 : case 1:
1583 59 : stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1584 59 : break;
1585 : case 2:
1586 24 : convert_to_long(arg2);
1587 24 : stmt->fetch.column = Z_LVAL_P(arg2);
1588 24 : break;
1589 : case 3:
1590 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
1591 0 : error = 1;
1592 : }
1593 83 : break;
1594 :
1595 : default:
1596 301 : if (ZEND_NUM_ARGS() > 1) {
1597 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
1598 0 : error = 1;
1599 : }
1600 : }
1601 :
1602 493 : flags = how & PDO_FETCH_FLAGS;
1603 :
1604 493 : if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1605 43 : flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1606 43 : how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1607 : }
1608 :
1609 493 : if (!error) {
1610 493 : PDO_STMT_CLEAR_ERR();
1611 493 : MAKE_STD_ZVAL(data);
1612 629 : if ( (how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1613 : (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1614 : ) {
1615 136 : array_init(return_value);
1616 136 : return_all = return_value;
1617 : } else {
1618 357 : return_all = 0;
1619 : }
1620 493 : if (!do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
1621 39 : FREE_ZVAL(data);
1622 39 : error = 2;
1623 : }
1624 : }
1625 493 : if (!error) {
1626 454 : if ((how & PDO_FETCH_GROUP)) {
1627 : do {
1628 328 : MAKE_STD_ZVAL(data);
1629 328 : } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1630 354 : } else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1631 90 : while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1632 : } else {
1633 318 : array_init(return_value);
1634 : do {
1635 692 : add_next_index_zval(return_value, data);
1636 692 : MAKE_STD_ZVAL(data);
1637 692 : } while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
1638 : }
1639 454 : FREE_ZVAL(data);
1640 : }
1641 :
1642 493 : do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1643 :
1644 493 : stmt->fetch.cls.ce = old_ce;
1645 493 : stmt->fetch.cls.ctor_args = old_ctor_args;
1646 493 : stmt->fetch.cls.fci.param_count = old_arg_count;
1647 :
1648 493 : if (error) {
1649 39 : PDO_HANDLE_STMT_ERR();
1650 39 : if (error != 2) {
1651 0 : RETURN_FALSE;
1652 : } else { /* on no results, return an empty array */
1653 39 : if (Z_TYPE_P(return_value) != IS_ARRAY) {
1654 39 : array_init(return_value);
1655 : }
1656 39 : return;
1657 : }
1658 : }
1659 : }
1660 : /* }}} */
1661 :
1662 : static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1663 649 : {
1664 649 : struct pdo_bound_param_data param = {0};
1665 :
1666 649 : param.paramno = -1;
1667 649 : param.param_type = PDO_PARAM_STR;
1668 :
1669 649 : if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1670 : "lz|llz!", ¶m.paramno, ¶m.parameter, ¶m.param_type, ¶m.max_value_len,
1671 : ¶m.driver_params)) {
1672 207 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", ¶m.name,
1673 : ¶m.namelen, ¶m.parameter, ¶m.param_type, ¶m.max_value_len,
1674 : ¶m.driver_params)) {
1675 0 : return 0;
1676 : }
1677 : }
1678 :
1679 649 : if (param.paramno > 0) {
1680 442 : --param.paramno; /* make it zero-based internally */
1681 207 : } else if (!param.name) {
1682 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1683 0 : return 0;
1684 : }
1685 :
1686 649 : Z_ADDREF_P(param.parameter);
1687 649 : if (!really_register_bound_param(¶m, stmt, is_param TSRMLS_CC)) {
1688 7 : if (param.parameter) {
1689 6 : zval_ptr_dtor(&(param.parameter));
1690 6 : param.parameter = NULL;
1691 : }
1692 7 : return 0;
1693 : }
1694 642 : return 1;
1695 : } /* }}} */
1696 :
1697 : /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1698 : 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(). */
1699 : static PHP_METHOD(PDOStatement, bindValue)
1700 247 : {
1701 247 : struct pdo_bound_param_data param = {0};
1702 247 : PHP_STMT_GET_OBJ;
1703 :
1704 247 : param.paramno = -1;
1705 247 : param.param_type = PDO_PARAM_STR;
1706 :
1707 247 : if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1708 : "lz/|l", ¶m.paramno, ¶m.parameter, ¶m.param_type)) {
1709 19 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", ¶m.name,
1710 : ¶m.namelen, ¶m.parameter, ¶m.param_type)) {
1711 0 : RETURN_FALSE;
1712 : }
1713 : }
1714 :
1715 247 : if (param.paramno > 0) {
1716 228 : --param.paramno; /* make it zero-based internally */
1717 19 : } else if (!param.name) {
1718 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1719 0 : RETURN_FALSE;
1720 : }
1721 :
1722 247 : Z_ADDREF_P(param.parameter);
1723 247 : if (!really_register_bound_param(¶m, stmt, TRUE TSRMLS_CC)) {
1724 3 : if (param.parameter) {
1725 3 : zval_ptr_dtor(&(param.parameter));
1726 3 : param.parameter = NULL;
1727 : }
1728 3 : RETURN_FALSE;
1729 : }
1730 244 : RETURN_TRUE;
1731 : }
1732 : /* }}} */
1733 :
1734 :
1735 : /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1736 : 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(). */
1737 : static PHP_METHOD(PDOStatement, bindParam)
1738 228 : {
1739 228 : PHP_STMT_GET_OBJ;
1740 228 : RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1741 : }
1742 : /* }}} */
1743 :
1744 : /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1745 : 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(). */
1746 : static PHP_METHOD(PDOStatement, bindColumn)
1747 421 : {
1748 421 : PHP_STMT_GET_OBJ;
1749 421 : RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
1750 : }
1751 : /* }}} */
1752 :
1753 : /* {{{ proto int PDOStatement::rowCount()
1754 : Returns the number of rows in a result set, or the number of rows affected by the last execute(). It is not always meaningful. */
1755 : static PHP_METHOD(PDOStatement, rowCount)
1756 9 : {
1757 9 : PHP_STMT_GET_OBJ;
1758 :
1759 9 : RETURN_LONG(stmt->row_count);
1760 : }
1761 : /* }}} */
1762 :
1763 : /* {{{ proto string PDOStatement::errorCode()
1764 : Fetch the error code associated with the last operation on the statement handle */
1765 : static PHP_METHOD(PDOStatement, errorCode)
1766 37 : {
1767 37 : PHP_STMT_GET_OBJ;
1768 :
1769 37 : if (zend_parse_parameters_none() == FAILURE) {
1770 0 : return;
1771 : }
1772 :
1773 37 : if (stmt->error_code[0] == '\0') {
1774 0 : RETURN_NULL();
1775 : }
1776 :
1777 37 : RETURN_STRING(stmt->error_code, 1);
1778 : }
1779 : /* }}} */
1780 :
1781 : /* {{{ proto array PDOStatement::errorInfo()
1782 : Fetch extended error information associated with the last operation on the statement handle */
1783 : static PHP_METHOD(PDOStatement, errorInfo)
1784 503 : {
1785 : int error_count;
1786 503 : int error_count_diff = 0;
1787 503 : int error_expected_count = 3;
1788 :
1789 503 : PHP_STMT_GET_OBJ;
1790 :
1791 503 : if (zend_parse_parameters_none() == FAILURE) {
1792 0 : return;
1793 : }
1794 :
1795 503 : array_init(return_value);
1796 503 : add_next_index_string(return_value, stmt->error_code, 1);
1797 :
1798 503 : if (stmt->dbh->methods->fetch_err) {
1799 503 : stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
1800 : }
1801 :
1802 503 : error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1803 :
1804 503 : if (error_expected_count > error_count) {
1805 : int current_index;
1806 :
1807 489 : error_count_diff = error_expected_count - error_count;
1808 1467 : for (current_index = 0; current_index < error_count_diff; current_index++) {
1809 978 : add_next_index_null(return_value);
1810 : }
1811 : }
1812 : }
1813 : /* }}} */
1814 :
1815 : /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1816 : Set an attribute */
1817 : static PHP_METHOD(PDOStatement, setAttribute)
1818 1 : {
1819 : long attr;
1820 1 : zval *value = NULL;
1821 1 : PHP_STMT_GET_OBJ;
1822 :
1823 1 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
1824 0 : RETURN_FALSE;
1825 : }
1826 :
1827 1 : if (!stmt->methods->set_attribute) {
1828 1 : goto fail;
1829 : }
1830 :
1831 0 : PDO_STMT_CLEAR_ERR();
1832 0 : if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
1833 0 : RETURN_TRUE;
1834 : }
1835 :
1836 1 : fail:
1837 1 : if (!stmt->methods->set_attribute) {
1838 1 : pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
1839 : } else {
1840 0 : PDO_HANDLE_STMT_ERR();
1841 : }
1842 1 : RETURN_FALSE;
1843 : }
1844 : /* }}} */
1845 :
1846 : /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1847 : Get an attribute */
1848 :
1849 : static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr)
1850 0 : {
1851 0 : switch (attr) {
1852 : case PDO_ATTR_EMULATE_PREPARES:
1853 0 : RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1854 0 : return 1;
1855 : }
1856 0 : return 0;
1857 : }
1858 :
1859 : static PHP_METHOD(PDOStatement, getAttribute)
1860 0 : {
1861 : long attr;
1862 0 : PHP_STMT_GET_OBJ;
1863 :
1864 0 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
1865 0 : RETURN_FALSE;
1866 : }
1867 :
1868 0 : if (!stmt->methods->get_attribute) {
1869 0 : if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1870 0 : pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1871 : "This driver doesn't support getting attributes" TSRMLS_CC);
1872 0 : RETURN_FALSE;
1873 : }
1874 0 : return;
1875 : }
1876 :
1877 0 : PDO_STMT_CLEAR_ERR();
1878 0 : switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
1879 : case -1:
1880 0 : PDO_HANDLE_STMT_ERR();
1881 0 : RETURN_FALSE;
1882 :
1883 : case 0:
1884 0 : if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1885 : /* XXX: should do something better here */
1886 0 : pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1887 : "driver doesn't support getting that attribute" TSRMLS_CC);
1888 0 : RETURN_FALSE;
1889 : }
1890 0 : return;
1891 :
1892 : default:
1893 0 : return;
1894 : }
1895 : }
1896 : /* }}} */
1897 :
1898 : /* {{{ proto int PDOStatement::columnCount()
1899 : Returns the number of columns in the result set */
1900 : static PHP_METHOD(PDOStatement, columnCount)
1901 22 : {
1902 22 : PHP_STMT_GET_OBJ;
1903 22 : if (zend_parse_parameters_none() == FAILURE) {
1904 0 : return;
1905 : }
1906 22 : RETURN_LONG(stmt->column_count);
1907 : }
1908 : /* }}} */
1909 :
1910 : /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1911 : Returns meta data for a numbered column */
1912 : static PHP_METHOD(PDOStatement, getColumnMeta)
1913 4 : {
1914 : long colno;
1915 : struct pdo_column_data *col;
1916 4 : PHP_STMT_GET_OBJ;
1917 :
1918 4 : if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
1919 0 : RETURN_FALSE;
1920 : }
1921 4 : if(colno < 0) {
1922 0 : pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
1923 0 : RETURN_FALSE;
1924 : }
1925 :
1926 4 : if (!stmt->methods->get_column_meta) {
1927 0 : pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
1928 0 : RETURN_FALSE;
1929 : }
1930 :
1931 4 : PDO_STMT_CLEAR_ERR();
1932 4 : if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
1933 1 : PDO_HANDLE_STMT_ERR();
1934 1 : RETURN_FALSE;
1935 : }
1936 :
1937 : /* add stock items */
1938 3 : col = &stmt->columns[colno];
1939 3 : add_assoc_string(return_value, "name", col->name, 1);
1940 3 : add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1941 3 : add_assoc_long(return_value, "precision", col->precision);
1942 3 : if (col->param_type != PDO_PARAM_ZVAL) {
1943 : /* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1944 3 : add_assoc_long(return_value, "pdo_type", col->param_type);
1945 : }
1946 : }
1947 : /* }}} */
1948 :
1949 : /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1950 : Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1951 :
1952 : int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1953 139 : {
1954 139 : long mode = PDO_FETCH_BOTH;
1955 139 : int flags, argc = ZEND_NUM_ARGS() - skip;
1956 : zval ***args;
1957 : zend_class_entry **cep;
1958 : int retval;
1959 :
1960 139 : do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1961 :
1962 139 : switch (stmt->default_fetch_type) {
1963 : case PDO_FETCH_INTO:
1964 6 : if (stmt->fetch.into) {
1965 6 : Z_DELREF_P(stmt->fetch.into);
1966 6 : stmt->fetch.into = NULL;
1967 : }
1968 : break;
1969 : default:
1970 : ;
1971 : }
1972 :
1973 139 : stmt->default_fetch_type = PDO_FETCH_BOTH;
1974 :
1975 139 : if (argc == 0) {
1976 0 : return SUCCESS;
1977 : }
1978 :
1979 139 : args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
1980 :
1981 139 : retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1982 :
1983 139 : if (SUCCESS == retval) {
1984 139 : if (Z_TYPE_PP(args[skip]) != IS_LONG) {
1985 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
1986 6 : retval = FAILURE;
1987 : } else {
1988 133 : mode = Z_LVAL_PP(args[skip]);
1989 133 : flags = mode & PDO_FETCH_FLAGS;
1990 :
1991 133 : retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
1992 : }
1993 : }
1994 :
1995 139 : if (FAILURE == retval) {
1996 6 : PDO_STMT_CLEAR_ERR();
1997 6 : efree(args);
1998 6 : return FAILURE;
1999 : }
2000 :
2001 133 : retval = FAILURE;
2002 133 : switch (mode & ~PDO_FETCH_FLAGS) {
2003 : case PDO_FETCH_USE_DEFAULT:
2004 : case PDO_FETCH_LAZY:
2005 : case PDO_FETCH_ASSOC:
2006 : case PDO_FETCH_NUM:
2007 : case PDO_FETCH_BOTH:
2008 : case PDO_FETCH_OBJ:
2009 : case PDO_FETCH_BOUND:
2010 : case PDO_FETCH_NAMED:
2011 : case PDO_FETCH_KEY_PAIR:
2012 60 : if (argc != 1) {
2013 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
2014 : } else {
2015 54 : retval = SUCCESS;
2016 : }
2017 60 : break;
2018 :
2019 : case PDO_FETCH_COLUMN:
2020 6 : if (argc != 2) {
2021 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument" TSRMLS_CC);
2022 0 : } else if (Z_TYPE_PP(args[skip+1]) != IS_LONG) {
2023 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer" TSRMLS_CC);
2024 : } else {
2025 0 : stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
2026 0 : retval = SUCCESS;
2027 : }
2028 6 : break;
2029 :
2030 : case PDO_FETCH_CLASS:
2031 : /* Gets its class name from 1st column */
2032 49 : if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
2033 1 : if (argc != 1) {
2034 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
2035 : } else {
2036 1 : stmt->fetch.cls.ce = NULL;
2037 1 : retval = SUCCESS;
2038 : }
2039 : } else {
2040 48 : if (argc < 2) {
2041 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument" TSRMLS_CC);
2042 42 : } else if (argc > 3) {
2043 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments" TSRMLS_CC);
2044 36 : } else if (Z_TYPE_PP(args[skip+1]) != IS_STRING) {
2045 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string" TSRMLS_CC);
2046 : } else {
2047 36 : retval = zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
2048 : Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC);
2049 :
2050 36 : if (SUCCESS == retval && cep && *cep) {
2051 36 : stmt->fetch.cls.ce = *cep;
2052 : }
2053 : }
2054 : }
2055 :
2056 49 : if (SUCCESS == retval) {
2057 37 : stmt->fetch.cls.ctor_args = NULL;
2058 : #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
2059 : if (stmt->dbh->is_persistent) {
2060 : 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");
2061 : }
2062 : #endif
2063 37 : if (argc == 3) {
2064 21 : if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
2065 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
2066 0 : retval = FAILURE;
2067 21 : } else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
2068 21 : ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
2069 21 : *stmt->fetch.cls.ctor_args = **args[skip+2];
2070 21 : zval_copy_ctor(stmt->fetch.cls.ctor_args);
2071 : }
2072 : }
2073 :
2074 37 : if (SUCCESS == retval) {
2075 37 : do_fetch_class_prepare(stmt TSRMLS_CC);
2076 : }
2077 : }
2078 :
2079 49 : break;
2080 :
2081 : case PDO_FETCH_INTO:
2082 18 : if (argc != 2) {
2083 6 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter" TSRMLS_CC);
2084 12 : } else if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
2085 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object" TSRMLS_CC);
2086 : } else {
2087 12 : retval = SUCCESS;
2088 : }
2089 :
2090 18 : if (SUCCESS == retval) {
2091 : #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
2092 : if (stmt->dbh->is_persistent) {
2093 : 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");
2094 : }
2095 : #endif
2096 12 : MAKE_STD_ZVAL(stmt->fetch.into);
2097 :
2098 12 : Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
2099 12 : Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
2100 12 : Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
2101 12 : zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
2102 : }
2103 :
2104 18 : break;
2105 :
2106 : default:
2107 0 : pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
2108 : }
2109 :
2110 133 : if (SUCCESS == retval) {
2111 103 : stmt->default_fetch_type = mode;
2112 : }
2113 :
2114 : /*
2115 : * PDO error (if any) has already been raised at this point.
2116 : *
2117 : * The error_code is cleared, otherwise the caller will read the
2118 : * last error message from the driver.
2119 : *
2120 : */
2121 133 : PDO_STMT_CLEAR_ERR();
2122 :
2123 133 : efree(args);
2124 :
2125 133 : return retval;
2126 : }
2127 :
2128 : static PHP_METHOD(PDOStatement, setFetchMode)
2129 61 : {
2130 61 : PHP_STMT_GET_OBJ;
2131 :
2132 61 : RETVAL_BOOL(
2133 : pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2134 : stmt, 0) == SUCCESS ? 1 : 0
2135 : );
2136 : }
2137 : /* }}} */
2138 :
2139 : /* {{{ proto bool PDOStatement::nextRowset()
2140 : Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
2141 :
2142 : static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
2143 43 : {
2144 : /* un-describe */
2145 43 : if (stmt->columns) {
2146 : int i;
2147 38 : struct pdo_column_data *cols = stmt->columns;
2148 :
2149 97 : for (i = 0; i < stmt->column_count; i++) {
2150 59 : efree(cols[i].name);
2151 : }
2152 38 : efree(stmt->columns);
2153 38 : stmt->columns = NULL;
2154 38 : stmt->column_count = 0;
2155 : }
2156 :
2157 43 : if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
2158 38 : return 0;
2159 : }
2160 :
2161 5 : pdo_stmt_describe_columns(stmt TSRMLS_CC);
2162 :
2163 5 : return 1;
2164 : }
2165 :
2166 : static PHP_METHOD(PDOStatement, nextRowset)
2167 43 : {
2168 43 : PHP_STMT_GET_OBJ;
2169 :
2170 43 : if (!stmt->methods->next_rowset) {
2171 0 : pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
2172 0 : RETURN_FALSE;
2173 : }
2174 :
2175 43 : PDO_STMT_CLEAR_ERR();
2176 :
2177 43 : if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2178 38 : PDO_HANDLE_STMT_ERR();
2179 38 : RETURN_FALSE;
2180 : }
2181 :
2182 5 : RETURN_TRUE;
2183 : }
2184 : /* }}} */
2185 :
2186 : /* {{{ proto bool PDOStatement::closeCursor()
2187 : Closes the cursor, leaving the statement ready for re-execution. */
2188 : static PHP_METHOD(PDOStatement, closeCursor)
2189 459 : {
2190 459 : PHP_STMT_GET_OBJ;
2191 :
2192 459 : if (!stmt->methods->cursor_closer) {
2193 : /* emulate it by fetching and discarding rows */
2194 : do {
2195 58 : while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
2196 : ;
2197 56 : if (!stmt->methods->next_rowset) {
2198 56 : break;
2199 : }
2200 :
2201 0 : if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2202 0 : break;
2203 : }
2204 :
2205 0 : } while (1);
2206 56 : stmt->executed = 0;
2207 56 : RETURN_TRUE;
2208 : }
2209 :
2210 403 : PDO_STMT_CLEAR_ERR();
2211 :
2212 403 : if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
2213 0 : PDO_HANDLE_STMT_ERR();
2214 0 : RETURN_FALSE;
2215 : }
2216 403 : stmt->executed = 0;
2217 403 : RETURN_TRUE;
2218 : }
2219 : /* }}} */
2220 :
2221 : /* {{{ proto void PDOStatement::debugDumpParams()
2222 : A utility for internals hackers to debug parameter internals */
2223 : static PHP_METHOD(PDOStatement, debugDumpParams)
2224 1 : {
2225 1 : php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
2226 : HashPosition pos;
2227 : struct pdo_bound_param_data *param;
2228 1 : PHP_STMT_GET_OBJ;
2229 :
2230 1 : if (out == NULL) {
2231 0 : RETURN_FALSE;
2232 : }
2233 :
2234 1 : php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
2235 : stmt->query_stringlen,
2236 : stmt->query_stringlen, stmt->query_string);
2237 :
2238 1 : php_stream_printf(out TSRMLS_CC, "Params: %d\n",
2239 : stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2240 :
2241 1 : if (stmt->bound_params) {
2242 1 : zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
2243 5 : while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
2244 : (void**)¶m, &pos)) {
2245 : char *str;
2246 : uint len;
2247 : ulong num;
2248 : int res;
2249 :
2250 3 : res = zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos);
2251 3 : if (res == HASH_KEY_IS_LONG) {
2252 1 : php_stream_printf(out TSRMLS_CC, "Key: Position #%ld:\n", num);
2253 2 : } else if (res == HASH_KEY_IS_STRING) {
2254 2 : php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
2255 : }
2256 :
2257 3 : php_stream_printf(out TSRMLS_CC, "paramno=%d\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
2258 : param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
2259 : param->is_param,
2260 : param->param_type);
2261 :
2262 3 : zend_hash_move_forward_ex(stmt->bound_params, &pos);
2263 : }
2264 : }
2265 :
2266 1 : php_stream_close(out);
2267 : }
2268 : /* }}} */
2269 :
2270 : /* {{{ proto int PDOStatement::__wakeup()
2271 : Prevents use of a PDOStatement instance that has been unserialized */
2272 : static PHP_METHOD(PDOStatement, __wakeup)
2273 0 : {
2274 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2275 0 : }
2276 : /* }}} */
2277 :
2278 : /* {{{ proto int PDOStatement::__sleep()
2279 : Prevents serialization of a PDOStatement instance */
2280 : static PHP_METHOD(PDOStatement, __sleep)
2281 0 : {
2282 0 : zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2283 0 : }
2284 : /* }}} */
2285 :
2286 : const zend_function_entry pdo_dbstmt_functions[] = {
2287 : PHP_ME(PDOStatement, execute, arginfo_pdostatement_execute, ZEND_ACC_PUBLIC)
2288 : PHP_ME(PDOStatement, fetch, arginfo_pdostatement_fetch, ZEND_ACC_PUBLIC)
2289 : PHP_ME(PDOStatement, bindParam, arginfo_pdostatement_bindparam, ZEND_ACC_PUBLIC)
2290 : PHP_ME(PDOStatement, bindColumn, arginfo_pdostatement_bindcolumn, ZEND_ACC_PUBLIC)
2291 : PHP_ME(PDOStatement, bindValue, arginfo_pdostatement_bindvalue, ZEND_ACC_PUBLIC)
2292 : PHP_ME(PDOStatement, rowCount, NULL, ZEND_ACC_PUBLIC)
2293 : PHP_ME(PDOStatement, fetchColumn, arginfo_pdostatement_fetchcolumn, ZEND_ACC_PUBLIC)
2294 : PHP_ME(PDOStatement, fetchAll, arginfo_pdostatement_fetchall, ZEND_ACC_PUBLIC)
2295 : PHP_ME(PDOStatement, fetchObject, arginfo_pdostatement_fetchobject, ZEND_ACC_PUBLIC)
2296 : PHP_ME(PDOStatement, errorCode, NULL, ZEND_ACC_PUBLIC)
2297 : PHP_ME(PDOStatement, errorInfo, NULL, ZEND_ACC_PUBLIC)
2298 : PHP_ME(PDOStatement, setAttribute, arginfo_pdostatement_setattribute, ZEND_ACC_PUBLIC)
2299 : PHP_ME(PDOStatement, getAttribute, arginfo_pdostatement_getattribute, ZEND_ACC_PUBLIC)
2300 : PHP_ME(PDOStatement, columnCount, NULL, ZEND_ACC_PUBLIC)
2301 : PHP_ME(PDOStatement, getColumnMeta, arginfo_pdostatement_getcolumnmeta, ZEND_ACC_PUBLIC)
2302 : PHP_ME(PDOStatement, setFetchMode, arginfo_pdostatement_setfetchmode, ZEND_ACC_PUBLIC)
2303 : PHP_ME(PDOStatement, nextRowset, NULL, ZEND_ACC_PUBLIC)
2304 : PHP_ME(PDOStatement, closeCursor, NULL, ZEND_ACC_PUBLIC)
2305 : PHP_ME(PDOStatement, debugDumpParams, NULL, ZEND_ACC_PUBLIC)
2306 : PHP_ME(PDOStatement, __wakeup, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2307 : PHP_ME(PDOStatement, __sleep, NULL, ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2308 : {NULL, NULL, NULL}
2309 : };
2310 :
2311 : /* {{{ overloaded handlers for PDOStatement class */
2312 : static void dbstmt_prop_write(zval *object, zval *member, zval *value TSRMLS_DC)
2313 72 : {
2314 72 : pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2315 :
2316 72 : convert_to_string(member);
2317 :
2318 72 : if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2319 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2320 : } else {
2321 72 : std_object_handlers.write_property(object, member, value TSRMLS_CC);
2322 : }
2323 72 : }
2324 :
2325 : static void dbstmt_prop_delete(zval *object, zval *member TSRMLS_DC)
2326 0 : {
2327 0 : pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2328 :
2329 0 : convert_to_string(member);
2330 :
2331 0 : if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2332 0 : pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2333 : } else {
2334 0 : std_object_handlers.unset_property(object, member TSRMLS_CC);
2335 : }
2336 0 : }
2337 :
2338 : static union _zend_function *dbstmt_method_get(
2339 : #if PHP_API_VERSION >= 20041225
2340 : zval **object_pp,
2341 : #else
2342 : zval *object,
2343 : #endif
2344 : char *method_name, int method_len TSRMLS_DC)
2345 5688 : {
2346 5688 : zend_function *fbc = NULL;
2347 : char *lc_method_name;
2348 : #if PHP_API_VERSION >= 20041225
2349 5688 : zval *object = *object_pp;
2350 : #endif
2351 :
2352 5688 : lc_method_name = emalloc(method_len + 1);
2353 5688 : zend_str_tolower_copy(lc_method_name, method_name, method_len);
2354 :
2355 5688 : if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
2356 : method_len+1, (void**)&fbc) == FAILURE) {
2357 0 : pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2358 : /* not a pre-defined method, nor a user-defined method; check
2359 : * the driver specific methods */
2360 0 : if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2361 0 : if (!pdo_hash_methods(stmt->dbh,
2362 : PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
2363 : || !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2364 : goto out;
2365 : }
2366 : }
2367 :
2368 0 : if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
2369 : lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2370 0 : fbc = NULL;
2371 0 : goto out;
2372 : }
2373 : /* got it */
2374 : }
2375 :
2376 5688 : out:
2377 5688 : efree(lc_method_name);
2378 5688 : return fbc;
2379 : }
2380 :
2381 : static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
2382 0 : {
2383 0 : return -1;
2384 : }
2385 :
2386 : static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
2387 0 : {
2388 : zend_object_value retval;
2389 : zval *tmp;
2390 : pdo_stmt_t *stmt;
2391 : pdo_stmt_t *old_stmt;
2392 0 : zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
2393 :
2394 0 : stmt = ecalloc(1, sizeof(*stmt));
2395 0 : stmt->ce = Z_OBJCE_P(zobject);
2396 0 : stmt->refcount = 1;
2397 0 : ALLOC_HASHTABLE(stmt->properties);
2398 0 : zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2399 0 : zend_hash_copy(stmt->properties, &stmt->ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2400 :
2401 0 : old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
2402 :
2403 0 : 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);
2404 0 : retval.handlers = Z_OBJ_HT_P(zobject);
2405 :
2406 0 : zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
2407 :
2408 0 : zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
2409 0 : stmt->database_object_handle = old_stmt->database_object_handle;
2410 :
2411 0 : return retval;
2412 : }
2413 :
2414 : zend_object_handlers pdo_dbstmt_object_handlers;
2415 :
2416 : void pdo_stmt_init(TSRMLS_D)
2417 17633 : {
2418 : zend_class_entry ce;
2419 :
2420 17633 : INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2421 17633 : pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
2422 17633 : pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2423 17633 : pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2424 17633 : zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
2425 17633 : zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
2426 :
2427 17633 : memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2428 17633 : pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2429 17633 : pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2430 17633 : pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2431 17633 : pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2432 17633 : pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
2433 :
2434 17633 : INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2435 17633 : pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
2436 17633 : pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
2437 17633 : pdo_row_ce->create_object = pdo_row_new;
2438 17633 : }
2439 :
2440 : static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
2441 2188 : {
2442 2188 : if (stmt->properties) {
2443 2188 : zend_hash_destroy(stmt->properties);
2444 2188 : efree(stmt->properties);
2445 2188 : stmt->properties = NULL;
2446 : }
2447 :
2448 2188 : if (stmt->bound_params) {
2449 894 : zend_hash_destroy(stmt->bound_params);
2450 894 : FREE_HASHTABLE(stmt->bound_params);
2451 894 : stmt->bound_params = NULL;
2452 : }
2453 2188 : if (stmt->bound_param_map) {
2454 162 : zend_hash_destroy(stmt->bound_param_map);
2455 162 : FREE_HASHTABLE(stmt->bound_param_map);
2456 162 : stmt->bound_param_map = NULL;
2457 : }
2458 2188 : if (stmt->bound_columns) {
2459 197 : zend_hash_destroy(stmt->bound_columns);
2460 197 : FREE_HASHTABLE(stmt->bound_columns);
2461 197 : stmt->bound_columns = NULL;
2462 : }
2463 :
2464 2188 : if (stmt->methods && stmt->methods->dtor) {
2465 2176 : stmt->methods->dtor(stmt TSRMLS_CC);
2466 : }
2467 2188 : if (stmt->query_string) {
2468 2181 : efree(stmt->query_string);
2469 : }
2470 :
2471 2188 : if (stmt->columns) {
2472 : int i;
2473 1646 : struct pdo_column_data *cols = stmt->columns;
2474 :
2475 3625 : for (i = 0; i < stmt->column_count; i++) {
2476 1979 : if (cols[i].name) {
2477 1979 : efree(cols[i].name);
2478 1979 : cols[i].name = NULL;
2479 : }
2480 : }
2481 1646 : efree(stmt->columns);
2482 1646 : stmt->columns = NULL;
2483 : }
2484 :
2485 2188 : if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
2486 0 : FREE_ZVAL(stmt->fetch.into);
2487 0 : stmt->fetch.into = NULL;
2488 : }
2489 :
2490 2188 : do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
2491 :
2492 2188 : zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
2493 2188 : if (stmt->dbh) {
2494 2181 : php_pdo_dbh_delref(stmt->dbh TSRMLS_CC);
2495 : }
2496 2188 : efree(stmt);
2497 2188 : }
2498 :
2499 : PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
2500 5 : {
2501 5 : stmt->refcount++;
2502 5 : }
2503 :
2504 : PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
2505 2197 : {
2506 2197 : if (--stmt->refcount == 0) {
2507 2143 : free_statement(stmt TSRMLS_CC);
2508 : }
2509 2197 : }
2510 :
2511 : void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2512 2194 : {
2513 2194 : php_pdo_stmt_delref(stmt TSRMLS_CC);
2514 2194 : }
2515 :
2516 : zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
2517 2198 : {
2518 : zend_object_value retval;
2519 : zval *tmp;
2520 :
2521 : pdo_stmt_t *stmt;
2522 2198 : stmt = emalloc(sizeof(*stmt));
2523 2198 : memset(stmt, 0, sizeof(*stmt));
2524 2198 : stmt->ce = ce;
2525 2198 : stmt->refcount = 1;
2526 2198 : ALLOC_HASHTABLE(stmt->properties);
2527 2198 : zend_hash_init(stmt->properties, 0, NULL, ZVAL_PTR_DTOR, 0);
2528 2198 : zend_hash_copy(stmt->properties, &ce->default_properties, (copy_ctor_func_t) zval_add_ref, (void *) &tmp, sizeof(zval *));
2529 :
2530 2198 : 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);
2531 2198 : retval.handlers = &pdo_dbstmt_object_handlers;
2532 :
2533 2198 : return retval;
2534 : }
2535 : /* }}} */
2536 :
2537 : /* {{{ statement iterator */
2538 :
2539 : struct php_pdo_iterator {
2540 : zend_object_iterator iter;
2541 : pdo_stmt_t *stmt;
2542 : ulong key;
2543 : zval *fetch_ahead;
2544 : };
2545 :
2546 : static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
2547 84 : {
2548 84 : struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2549 :
2550 84 : if (--I->stmt->refcount == 0) {
2551 28 : free_statement(I->stmt TSRMLS_CC);
2552 : }
2553 :
2554 84 : if (I->fetch_ahead) {
2555 18 : zval_ptr_dtor(&I->fetch_ahead);
2556 : }
2557 :
2558 84 : efree(I);
2559 84 : }
2560 :
2561 : static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
2562 276 : {
2563 276 : struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2564 :
2565 276 : return I->fetch_ahead ? SUCCESS : FAILURE;
2566 : }
2567 :
2568 : static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
2569 205 : {
2570 205 : struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2571 :
2572 : /* sanity */
2573 205 : if (!I->fetch_ahead) {
2574 0 : *data = NULL;
2575 0 : return;
2576 : }
2577 :
2578 205 : *data = &I->fetch_ahead;
2579 : }
2580 :
2581 : static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
2582 : ulong *int_key TSRMLS_DC)
2583 24 : {
2584 24 : struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2585 :
2586 24 : if (I->key == (ulong)-1) {
2587 0 : return HASH_KEY_NON_EXISTANT;
2588 : }
2589 24 : *int_key = I->key;
2590 24 : return HASH_KEY_IS_LONG;
2591 : }
2592 :
2593 : static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
2594 193 : {
2595 193 : struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2596 :
2597 193 : if (I->fetch_ahead) {
2598 187 : zval_ptr_dtor(&I->fetch_ahead);
2599 187 : I->fetch_ahead = NULL;
2600 : }
2601 :
2602 193 : MAKE_STD_ZVAL(I->fetch_ahead);
2603 :
2604 193 : if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2605 : PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2606 72 : pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
2607 :
2608 72 : PDO_HANDLE_STMT_ERR();
2609 72 : I->key = (ulong)-1;
2610 72 : FREE_ZVAL(I->fetch_ahead);
2611 72 : I->fetch_ahead = NULL;
2612 :
2613 72 : return;
2614 : }
2615 :
2616 121 : I->key++;
2617 : }
2618 :
2619 : static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2620 : pdo_stmt_iter_dtor,
2621 : pdo_stmt_iter_valid,
2622 : pdo_stmt_iter_get_data,
2623 : pdo_stmt_iter_get_key,
2624 : pdo_stmt_iter_move_forwards,
2625 : NULL
2626 : };
2627 :
2628 : zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
2629 90 : {
2630 90 : pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2631 : struct php_pdo_iterator *I;
2632 :
2633 90 : if (by_ref) {
2634 0 : zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2635 : }
2636 :
2637 90 : I = ecalloc(1, sizeof(*I));
2638 90 : I->iter.funcs = &pdo_stmt_iter_funcs;
2639 90 : I->iter.data = I;
2640 90 : I->stmt = stmt;
2641 90 : stmt->refcount++;
2642 :
2643 90 : MAKE_STD_ZVAL(I->fetch_ahead);
2644 90 : if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2645 : PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2646 0 : PDO_HANDLE_STMT_ERR();
2647 0 : I->key = (ulong)-1;
2648 0 : FREE_ZVAL(I->fetch_ahead);
2649 0 : I->fetch_ahead = NULL;
2650 : }
2651 :
2652 84 : return &I->iter;
2653 : }
2654 :
2655 : /* }}} */
2656 :
2657 : /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2658 :
2659 : const zend_function_entry pdo_row_functions[] = {
2660 : {NULL, NULL, NULL}
2661 : };
2662 :
2663 : static zval *row_prop_or_dim_read(zval *object, zval *member, int type TSRMLS_DC)
2664 34 : {
2665 : zval *return_value;
2666 34 : pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2667 34 : int colno = -1;
2668 :
2669 34 : MAKE_STD_ZVAL(return_value);
2670 34 : RETVAL_NULL();
2671 :
2672 34 : if (stmt) {
2673 34 : if (Z_TYPE_P(member) == IS_LONG) {
2674 3 : if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
2675 1 : fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
2676 : }
2677 : } else {
2678 31 : convert_to_string(member);
2679 : /* TODO: replace this with a hash of available column names to column
2680 : * numbers */
2681 47 : for (colno = 0; colno < stmt->column_count; colno++) {
2682 43 : if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2683 27 : fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
2684 27 : Z_SET_REFCOUNT_P(return_value, 0);
2685 27 : Z_UNSET_ISREF_P(return_value);
2686 27 : return return_value;
2687 : }
2688 : }
2689 4 : if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2690 3 : zval_ptr_dtor(&return_value);
2691 3 : return std_object_handlers.read_property(object, member, IS_STRING TSRMLS_CC);
2692 : }
2693 : }
2694 : }
2695 :
2696 4 : Z_SET_REFCOUNT_P(return_value, 0);
2697 4 : Z_UNSET_ISREF_P(return_value);
2698 :
2699 4 : return return_value;
2700 : }
2701 :
2702 : static void row_prop_or_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
2703 0 : {
2704 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2705 0 : }
2706 :
2707 : static int row_prop_or_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
2708 0 : {
2709 0 : pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2710 0 : int colno = -1;
2711 :
2712 0 : if (stmt) {
2713 0 : if (Z_TYPE_P(member) == IS_LONG) {
2714 0 : return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
2715 : } else {
2716 0 : convert_to_string(member);
2717 :
2718 : /* TODO: replace this with a hash of available column names to column
2719 : * numbers */
2720 0 : for (colno = 0; colno < stmt->column_count; colno++) {
2721 0 : if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2722 0 : return 1;
2723 : }
2724 : }
2725 : }
2726 : }
2727 :
2728 0 : return 0;
2729 : }
2730 :
2731 : static void row_prop_or_dim_delete(zval *object, zval *offset TSRMLS_DC)
2732 0 : {
2733 0 : php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2734 0 : }
2735 :
2736 : static HashTable *row_get_properties(zval *object TSRMLS_DC)
2737 11 : {
2738 11 : pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2739 : int i;
2740 :
2741 11 : if (stmt == NULL) {
2742 7 : return NULL;
2743 : }
2744 :
2745 8 : for (i = 0; i < stmt->column_count; i++) {
2746 : zval *val;
2747 4 : MAKE_STD_ZVAL(val);
2748 4 : fetch_value(stmt, val, i, NULL TSRMLS_CC);
2749 :
2750 4 : zend_hash_update(stmt->properties, stmt->columns[i].name, stmt->columns[i].namelen + 1, (void *)&val, sizeof(zval *), NULL);
2751 : }
2752 :
2753 4 : return stmt->properties;
2754 : }
2755 :
2756 : static union _zend_function *row_method_get(
2757 : #if PHP_API_VERSION >= 20041225
2758 : zval **object_pp,
2759 : #else
2760 : zval *object,
2761 : #endif
2762 : char *method_name, int method_len TSRMLS_DC)
2763 0 : {
2764 : zend_function *fbc;
2765 : char *lc_method_name;
2766 :
2767 0 : lc_method_name = emalloc(method_len + 1);
2768 0 : zend_str_tolower_copy(lc_method_name, method_name, method_len);
2769 :
2770 0 : if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2771 0 : efree(lc_method_name);
2772 0 : return NULL;
2773 : }
2774 :
2775 0 : efree(lc_method_name);
2776 0 : return fbc;
2777 : }
2778 :
2779 : static int row_call_method(char *method, INTERNAL_FUNCTION_PARAMETERS)
2780 0 : {
2781 0 : return FAILURE;
2782 : }
2783 :
2784 : static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
2785 7 : {
2786 : static zend_internal_function ctor = {0};
2787 :
2788 7 : ctor.type = ZEND_INTERNAL_FUNCTION;
2789 7 : ctor.function_name = "__construct";
2790 7 : ctor.scope = pdo_row_ce;
2791 7 : ctor.handler = ZEND_FN(dbstmt_constructor);
2792 :
2793 7 : return (union _zend_function*)&ctor;
2794 : }
2795 :
2796 : static zend_class_entry *row_get_ce(const zval *object TSRMLS_DC)
2797 7 : {
2798 7 : return pdo_row_ce;
2799 : }
2800 :
2801 : static int row_get_classname(const zval *object, char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
2802 25 : {
2803 25 : if (parent) {
2804 7 : return FAILURE;
2805 : } else {
2806 18 : *class_name = estrndup("PDORow", sizeof("PDORow")-1);
2807 18 : *class_name_len = sizeof("PDORow")-1;
2808 18 : return SUCCESS;
2809 : }
2810 : }
2811 :
2812 : static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
2813 0 : {
2814 0 : return -1;
2815 : }
2816 :
2817 : zend_object_handlers pdo_row_object_handlers = {
2818 : ZEND_OBJECTS_STORE_HANDLERS,
2819 : row_prop_or_dim_read,
2820 : row_prop_or_dim_write,
2821 : row_prop_or_dim_read,
2822 : row_prop_or_dim_write,
2823 : NULL,
2824 : NULL,
2825 : NULL,
2826 : row_prop_or_dim_exists,
2827 : row_prop_or_dim_delete,
2828 : row_prop_or_dim_exists,
2829 : row_prop_or_dim_delete,
2830 : row_get_properties,
2831 : row_method_get,
2832 : row_call_method,
2833 : row_get_ctor,
2834 : row_get_ce,
2835 : row_get_classname,
2836 : row_compare,
2837 : NULL, /* cast */
2838 : NULL
2839 : };
2840 :
2841 : void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2842 31 : {
2843 31 : if (stmt) {
2844 17 : ZVAL_NULL(&stmt->lazy_object_ref);
2845 :
2846 17 : if (--stmt->refcount == 0) {
2847 17 : free_statement(stmt TSRMLS_CC);
2848 : }
2849 : }
2850 31 : }
2851 :
2852 : zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
2853 14 : {
2854 : zend_object_value retval;
2855 :
2856 14 : 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);
2857 14 : retval.handlers = &pdo_row_object_handlers;
2858 :
2859 14 : return retval;
2860 : }
2861 : /* }}} */
2862 :
2863 : /*
2864 : * Local variables:
2865 : * tab-width: 4
2866 : * c-basic-offset: 4
2867 : * End:
2868 : * vim600: noet sw=4 ts=4 fdm=marker
2869 : * vim<600: noet sw=4 ts=4
2870 : */
|