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