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