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