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