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