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