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