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