xref: /PHP-5.4/ext/pdo/pdo_stmt.c (revision c0d060f5)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 5                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2014 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, (unsigned char *)(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 = NULL;
1337 	int class_name_len;
1338 	zend_class_entry *old_ce;
1339 	zval *old_ctor_args, *ctor_args = NULL;
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, "|s!a", &class_name, &class_name_len, &ctor_args)) {
1345 		RETURN_FALSE;
1346 	}
1347 
1348 	PDO_STMT_CLEAR_ERR();
1349 
1350 	if (!pdo_stmt_verify_mode(stmt, how, 0 TSRMLS_CC)) {
1351 		RETURN_FALSE;
1352 	}
1353 
1354 	old_ce = stmt->fetch.cls.ce;
1355 	old_ctor_args = stmt->fetch.cls.ctor_args;
1356 	old_arg_count = stmt->fetch.cls.fci.param_count;
1357 
1358 	do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1359 
1360 	if (ctor_args) {
1361 		if (Z_TYPE_P(ctor_args) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1362 			ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1363 			*stmt->fetch.cls.ctor_args = *ctor_args;
1364 			zval_copy_ctor(stmt->fetch.cls.ctor_args);
1365 		} else {
1366 			stmt->fetch.cls.ctor_args = NULL;
1367 		}
1368 	}
1369 	if (class_name && !error) {
1370 		stmt->fetch.cls.ce = zend_fetch_class(class_name, class_name_len, ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1371 
1372 		if (!stmt->fetch.cls.ce) {
1373 			pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Could not find user-supplied class" TSRMLS_CC);
1374 			error = 1;
1375 		}
1376 	} else if (!error) {
1377 		stmt->fetch.cls.ce = zend_standard_class_def;
1378 	}
1379 
1380 	if (!error && !do_fetch(stmt, TRUE, return_value, how, ori, off, 0 TSRMLS_CC)) {
1381 		error = 1;
1382 	}
1383 	if (error) {
1384 		PDO_HANDLE_STMT_ERR();
1385 	}
1386 	do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1387 
1388 	stmt->fetch.cls.ce = old_ce;
1389 	stmt->fetch.cls.ctor_args = old_ctor_args;
1390 	stmt->fetch.cls.fci.param_count = old_arg_count;
1391 	if (error) {
1392 		RETURN_FALSE;
1393 	}
1394 }
1395 /* }}} */
1396 
1397 /* {{{ proto string PDOStatement::fetchColumn([int column_number])
1398    Returns a data of the specified column in the result set. */
PHP_METHOD(PDOStatement,fetchColumn)1399 static PHP_METHOD(PDOStatement, fetchColumn)
1400 {
1401 	long col_n = 0;
1402 	PHP_STMT_GET_OBJ;
1403 
1404 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &col_n)) {
1405 		RETURN_FALSE;
1406 	}
1407 
1408 	PDO_STMT_CLEAR_ERR();
1409 
1410 	if (!do_fetch_common(stmt, PDO_FETCH_ORI_NEXT, 0, TRUE TSRMLS_CC)) {
1411 		PDO_HANDLE_STMT_ERR();
1412 		RETURN_FALSE;
1413 	}
1414 
1415 	fetch_value(stmt, return_value, col_n, NULL TSRMLS_CC);
1416 }
1417 /* }}} */
1418 
1419 /* {{{ proto array PDOStatement::fetchAll([int $how = PDO_FETCH_BOTH [, string class_name [, NULL|array ctor_args]]])
1420    Returns an array of all of the results. */
PHP_METHOD(PDOStatement,fetchAll)1421 static PHP_METHOD(PDOStatement, fetchAll)
1422 {
1423 	long how = PDO_FETCH_USE_DEFAULT;
1424 	zval *data, *return_all;
1425 	zval *arg2;
1426 	zend_class_entry *old_ce;
1427 	zval *old_ctor_args, *ctor_args = NULL;
1428 	int error = 0, flags, old_arg_count;
1429 	PHP_STMT_GET_OBJ;
1430 
1431 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|lzz", &how, &arg2, &ctor_args)) {
1432 		RETURN_FALSE;
1433 	}
1434 
1435 	if (!pdo_stmt_verify_mode(stmt, how, 1 TSRMLS_CC)) {
1436 		RETURN_FALSE;
1437 	}
1438 
1439 	old_ce = stmt->fetch.cls.ce;
1440 	old_ctor_args = stmt->fetch.cls.ctor_args;
1441 	old_arg_count = stmt->fetch.cls.fci.param_count;
1442 
1443 	do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1444 
1445 	switch(how & ~PDO_FETCH_FLAGS) {
1446 	case PDO_FETCH_CLASS:
1447 		switch(ZEND_NUM_ARGS()) {
1448 		case 0:
1449 		case 1:
1450 			stmt->fetch.cls.ce = zend_standard_class_def;
1451 			break;
1452 		case 3:
1453 			if (Z_TYPE_P(ctor_args) != IS_NULL && Z_TYPE_P(ctor_args) != IS_ARRAY) {
1454 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1455 				error = 1;
1456 				break;
1457 			}
1458 			if (Z_TYPE_P(ctor_args) != IS_ARRAY || !zend_hash_num_elements(Z_ARRVAL_P(ctor_args))) {
1459 				ctor_args = NULL;
1460 			}
1461 			/* no break */
1462 		case 2:
1463 			stmt->fetch.cls.ctor_args = ctor_args; /* we're not going to free these */
1464 			if (Z_TYPE_P(arg2) != IS_STRING) {
1465 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Invalid class name (should be a string)" TSRMLS_CC);
1466 				error = 1;
1467 				break;
1468 			} else {
1469 				stmt->fetch.cls.ce = zend_fetch_class(Z_STRVAL_P(arg2), Z_STRLEN_P(arg2), ZEND_FETCH_CLASS_AUTO TSRMLS_CC);
1470 				if (!stmt->fetch.cls.ce) {
1471 					pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "could not find user-specified class" TSRMLS_CC);
1472 					error = 1;
1473 					break;
1474 				}
1475 			}
1476 		}
1477 		if (!error) {
1478 			do_fetch_class_prepare(stmt TSRMLS_CC);
1479 		}
1480 		break;
1481 
1482 	case PDO_FETCH_FUNC:
1483 		switch(ZEND_NUM_ARGS()) {
1484 		case 0:
1485 		case 1:
1486 			pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "no fetch function specified" TSRMLS_CC);
1487 			error = 1;
1488 			break;
1489 		case 3:
1490 		case 2:
1491 			stmt->fetch.func.function = arg2;
1492 			if (do_fetch_func_prepare(stmt TSRMLS_CC) == 0) {
1493 				error = 1;
1494 			}
1495 			break;
1496 		}
1497 		break;
1498 
1499 	case PDO_FETCH_COLUMN:
1500 		switch(ZEND_NUM_ARGS()) {
1501 		case 0:
1502 		case 1:
1503 			stmt->fetch.column = how & PDO_FETCH_GROUP ? -1 : 0;
1504 			break;
1505 		case 2:
1506 			convert_to_long(arg2);
1507 			stmt->fetch.column = Z_LVAL_P(arg2);
1508 			break;
1509 		case 3:
1510 			pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Third parameter not allowed for PDO::FETCH_COLUMN" TSRMLS_CC);
1511 			error = 1;
1512 		}
1513 		break;
1514 
1515 	default:
1516 		if (ZEND_NUM_ARGS() > 1) {
1517 			pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "Extraneous additional parameters" TSRMLS_CC);
1518 			error = 1;
1519 		}
1520 	}
1521 
1522 	flags = how & PDO_FETCH_FLAGS;
1523 
1524 	if ((how & ~PDO_FETCH_FLAGS) == PDO_FETCH_USE_DEFAULT) {
1525 		flags |= stmt->default_fetch_type & PDO_FETCH_FLAGS;
1526 		how |= stmt->default_fetch_type & ~PDO_FETCH_FLAGS;
1527 	}
1528 
1529 	if (!error)	{
1530 		PDO_STMT_CLEAR_ERR();
1531 		MAKE_STD_ZVAL(data);
1532 		if (	(how & PDO_FETCH_GROUP) || how == PDO_FETCH_KEY_PAIR ||
1533 			(how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)
1534 		) {
1535 			array_init(return_value);
1536 			return_all = return_value;
1537 		} else {
1538 			return_all = 0;
1539 		}
1540 		if (!do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC)) {
1541 			FREE_ZVAL(data);
1542 			error = 2;
1543 		}
1544 	}
1545 	if (!error) {
1546 		if ((how & PDO_FETCH_GROUP)) {
1547 			do {
1548 				MAKE_STD_ZVAL(data);
1549 			} while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1550 		} else if (how == PDO_FETCH_KEY_PAIR || (how == PDO_FETCH_USE_DEFAULT && stmt->default_fetch_type == PDO_FETCH_KEY_PAIR)) {
1551 			while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, return_all TSRMLS_CC));
1552 		} else {
1553 			array_init(return_value);
1554 			do {
1555 				add_next_index_zval(return_value, data);
1556 				MAKE_STD_ZVAL(data);
1557 			} while (do_fetch(stmt, TRUE, data, how | flags, PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC));
1558 		}
1559 		FREE_ZVAL(data);
1560 	}
1561 
1562 	do_fetch_opt_finish(stmt, 0 TSRMLS_CC);
1563 
1564 	stmt->fetch.cls.ce = old_ce;
1565 	stmt->fetch.cls.ctor_args = old_ctor_args;
1566 	stmt->fetch.cls.fci.param_count = old_arg_count;
1567 
1568 	if (error) {
1569 		PDO_HANDLE_STMT_ERR();
1570 		if (error != 2) {
1571 			RETURN_FALSE;
1572 		} else { /* on no results, return an empty array */
1573 			if (Z_TYPE_P(return_value) != IS_ARRAY) {
1574 				array_init(return_value);
1575 			}
1576 			return;
1577 		}
1578 	}
1579 }
1580 /* }}} */
1581 
register_bound_param(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int is_param)1582 static int register_bound_param(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int is_param) /* {{{ */
1583 {
1584 	struct pdo_bound_param_data param = {0};
1585 	long param_type = PDO_PARAM_STR;
1586 
1587 	param.paramno = -1;
1588 
1589 	if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1590 			"lz|llz!", &param.paramno, &param.parameter, &param_type, &param.max_value_len,
1591 			&param.driver_params)) {
1592 		if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz|llz!", &param.name,
1593 				&param.namelen, &param.parameter, &param_type, &param.max_value_len,
1594 				&param.driver_params)) {
1595 			return 0;
1596 		}
1597 	}
1598 
1599 	param.param_type = (int) param_type;
1600 
1601 	if (param.paramno > 0) {
1602 		--param.paramno; /* make it zero-based internally */
1603 	} else if (!param.name) {
1604 		pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1605 		return 0;
1606 	}
1607 
1608 	Z_ADDREF_P(param.parameter);
1609 	if (!really_register_bound_param(&param, stmt, is_param TSRMLS_CC)) {
1610 		if (param.parameter) {
1611 			zval_ptr_dtor(&(param.parameter));
1612 			param.parameter = NULL;
1613 		}
1614 		return 0;
1615 	}
1616 	return 1;
1617 } /* }}} */
1618 
1619 /* {{{ proto bool PDOStatement::bindValue(mixed $paramno, mixed $param [, int $type ])
1620    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)1621 static PHP_METHOD(PDOStatement, bindValue)
1622 {
1623 	struct pdo_bound_param_data param = {0};
1624 	long param_type = PDO_PARAM_STR;
1625 	PHP_STMT_GET_OBJ;
1626 
1627 	param.paramno = -1;
1628 
1629 	if (FAILURE == zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC,
1630 			"lz/|l", &param.paramno, &param.parameter, &param_type)) {
1631 		if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "sz/|l", &param.name,
1632 				&param.namelen, &param.parameter, &param_type)) {
1633 			RETURN_FALSE;
1634 		}
1635 	}
1636 
1637 	param.param_type = (int) param_type;
1638 
1639 	if (param.paramno > 0) {
1640 		--param.paramno; /* make it zero-based internally */
1641 	} else if (!param.name) {
1642 		pdo_raise_impl_error(stmt->dbh, stmt, "HY093", "Columns/Parameters are 1-based" TSRMLS_CC);
1643 		RETURN_FALSE;
1644 	}
1645 
1646 	Z_ADDREF_P(param.parameter);
1647 	if (!really_register_bound_param(&param, stmt, TRUE TSRMLS_CC)) {
1648 		if (param.parameter) {
1649 			zval_ptr_dtor(&(param.parameter));
1650 			param.parameter = NULL;
1651 		}
1652 		RETURN_FALSE;
1653 	}
1654 	RETURN_TRUE;
1655 }
1656 /* }}} */
1657 
1658 
1659 /* {{{ proto bool PDOStatement::bindParam(mixed $paramno, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1660    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)1661 static PHP_METHOD(PDOStatement, bindParam)
1662 {
1663 	PHP_STMT_GET_OBJ;
1664 	RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, TRUE));
1665 }
1666 /* }}} */
1667 
1668 /* {{{ proto bool PDOStatement::bindColumn(mixed $column, mixed &$param [, int $type [, int $maxlen [, mixed $driverdata]]])
1669    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)1670 static PHP_METHOD(PDOStatement, bindColumn)
1671 {
1672 	PHP_STMT_GET_OBJ;
1673 	RETURN_BOOL(register_bound_param(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, FALSE));
1674 }
1675 /* }}} */
1676 
1677 /* {{{ proto int PDOStatement::rowCount()
1678    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)1679 static PHP_METHOD(PDOStatement, rowCount)
1680 {
1681 	PHP_STMT_GET_OBJ;
1682 
1683 	RETURN_LONG(stmt->row_count);
1684 }
1685 /* }}} */
1686 
1687 /* {{{ proto string PDOStatement::errorCode()
1688    Fetch the error code associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorCode)1689 static PHP_METHOD(PDOStatement, errorCode)
1690 {
1691 	PHP_STMT_GET_OBJ;
1692 
1693 	if (zend_parse_parameters_none() == FAILURE) {
1694 		return;
1695 	}
1696 
1697 	if (stmt->error_code[0] == '\0') {
1698 		RETURN_NULL();
1699 	}
1700 
1701 	RETURN_STRING(stmt->error_code, 1);
1702 }
1703 /* }}} */
1704 
1705 /* {{{ proto array PDOStatement::errorInfo()
1706    Fetch extended error information associated with the last operation on the statement handle */
PHP_METHOD(PDOStatement,errorInfo)1707 static PHP_METHOD(PDOStatement, errorInfo)
1708 {
1709 	int error_count;
1710 	int error_count_diff     = 0;
1711 	int error_expected_count = 3;
1712 
1713 	PHP_STMT_GET_OBJ;
1714 
1715 	if (zend_parse_parameters_none() == FAILURE) {
1716 		return;
1717 	}
1718 
1719 	array_init(return_value);
1720 	add_next_index_string(return_value, stmt->error_code, 1);
1721 
1722 	if (stmt->dbh->methods->fetch_err) {
1723 		stmt->dbh->methods->fetch_err(stmt->dbh, stmt, return_value TSRMLS_CC);
1724 	}
1725 
1726 	error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1727 
1728 	if (error_expected_count > error_count) {
1729 		int current_index;
1730 
1731 		error_count_diff = error_expected_count - error_count;
1732 		for (current_index = 0; current_index < error_count_diff; current_index++) {
1733 			add_next_index_null(return_value);
1734 		}
1735 	}
1736 }
1737 /* }}} */
1738 
1739 /* {{{ proto bool PDOStatement::setAttribute(long attribute, mixed value)
1740    Set an attribute */
PHP_METHOD(PDOStatement,setAttribute)1741 static PHP_METHOD(PDOStatement, setAttribute)
1742 {
1743 	long attr;
1744 	zval *value = NULL;
1745 	PHP_STMT_GET_OBJ;
1746 
1747 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "lz!", &attr, &value)) {
1748 		RETURN_FALSE;
1749 	}
1750 
1751 	if (!stmt->methods->set_attribute) {
1752 		goto fail;
1753 	}
1754 
1755 	PDO_STMT_CLEAR_ERR();
1756 	if (stmt->methods->set_attribute(stmt, attr, value TSRMLS_CC)) {
1757 		RETURN_TRUE;
1758 	}
1759 
1760 fail:
1761 	if (!stmt->methods->set_attribute) {
1762 		pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "This driver doesn't support setting attributes" TSRMLS_CC);
1763 	} else {
1764 		PDO_HANDLE_STMT_ERR();
1765 	}
1766 	RETURN_FALSE;
1767 }
1768 /* }}} */
1769 
1770 /* {{{ proto mixed PDOStatement::getAttribute(long attribute)
1771    Get an attribute */
1772 
generic_stmt_attr_get(pdo_stmt_t * stmt,zval * return_value,long attr)1773 static int generic_stmt_attr_get(pdo_stmt_t *stmt, zval *return_value, long attr)
1774 {
1775 	switch (attr) {
1776 		case PDO_ATTR_EMULATE_PREPARES:
1777 			RETVAL_BOOL(stmt->supports_placeholders == PDO_PLACEHOLDER_NONE);
1778 			return 1;
1779 	}
1780 	return 0;
1781 }
1782 
PHP_METHOD(PDOStatement,getAttribute)1783 static PHP_METHOD(PDOStatement, getAttribute)
1784 {
1785 	long attr;
1786 	PHP_STMT_GET_OBJ;
1787 
1788 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &attr)) {
1789 		RETURN_FALSE;
1790 	}
1791 
1792 	if (!stmt->methods->get_attribute) {
1793 		if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1794 			pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1795 				"This driver doesn't support getting attributes" TSRMLS_CC);
1796 			RETURN_FALSE;
1797 		}
1798 		return;
1799 	}
1800 
1801 	PDO_STMT_CLEAR_ERR();
1802 	switch (stmt->methods->get_attribute(stmt, attr, return_value TSRMLS_CC)) {
1803 		case -1:
1804 			PDO_HANDLE_STMT_ERR();
1805 			RETURN_FALSE;
1806 
1807 		case 0:
1808 			if (!generic_stmt_attr_get(stmt, return_value, attr)) {
1809 				/* XXX: should do something better here */
1810 				pdo_raise_impl_error(stmt->dbh, stmt, "IM001",
1811 					"driver doesn't support getting that attribute" TSRMLS_CC);
1812 				RETURN_FALSE;
1813 			}
1814 			return;
1815 
1816 		default:
1817 			return;
1818 	}
1819 }
1820 /* }}} */
1821 
1822 /* {{{ proto int PDOStatement::columnCount()
1823    Returns the number of columns in the result set */
PHP_METHOD(PDOStatement,columnCount)1824 static PHP_METHOD(PDOStatement, columnCount)
1825 {
1826 	PHP_STMT_GET_OBJ;
1827 	if (zend_parse_parameters_none() == FAILURE) {
1828 		return;
1829 	}
1830 	RETURN_LONG(stmt->column_count);
1831 }
1832 /* }}} */
1833 
1834 /* {{{ proto array PDOStatement::getColumnMeta(int $column)
1835    Returns meta data for a numbered column */
PHP_METHOD(PDOStatement,getColumnMeta)1836 static PHP_METHOD(PDOStatement, getColumnMeta)
1837 {
1838 	long colno;
1839 	struct pdo_column_data *col;
1840 	PHP_STMT_GET_OBJ;
1841 
1842 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &colno)) {
1843 		RETURN_FALSE;
1844 	}
1845 	if(colno < 0) {
1846 		pdo_raise_impl_error(stmt->dbh, stmt, "42P10", "column number must be non-negative" TSRMLS_CC);
1847 		RETURN_FALSE;
1848 	}
1849 
1850 	if (!stmt->methods->get_column_meta) {
1851 		pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver doesn't support meta data" TSRMLS_CC);
1852 		RETURN_FALSE;
1853 	}
1854 
1855 	PDO_STMT_CLEAR_ERR();
1856 	if (FAILURE == stmt->methods->get_column_meta(stmt, colno, return_value TSRMLS_CC)) {
1857 		PDO_HANDLE_STMT_ERR();
1858 		RETURN_FALSE;
1859 	}
1860 
1861 	/* add stock items */
1862 	col = &stmt->columns[colno];
1863 	add_assoc_string(return_value, "name", col->name, 1);
1864 	add_assoc_long(return_value, "len", col->maxlen); /* FIXME: unsigned ? */
1865 	add_assoc_long(return_value, "precision", col->precision);
1866 	if (col->param_type != PDO_PARAM_ZVAL) {
1867 		/* if param_type is PDO_PARAM_ZVAL the driver has to provide correct data */
1868 		add_assoc_long(return_value, "pdo_type", col->param_type);
1869 	}
1870 }
1871 /* }}} */
1872 
1873 /* {{{ proto bool PDOStatement::setFetchMode(int mode [mixed* params])
1874    Changes the default fetch mode for subsequent fetches (params have different meaning for different fetch modes) */
1875 
pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS,pdo_stmt_t * stmt,int skip)1876 int pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAMETERS, pdo_stmt_t *stmt, int skip)
1877 {
1878 	long mode = PDO_FETCH_BOTH;
1879 	int flags = 0, argc = ZEND_NUM_ARGS() - skip;
1880 	zval ***args;
1881 	zend_class_entry **cep;
1882 	int retval;
1883 
1884 	do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
1885 
1886 	switch (stmt->default_fetch_type) {
1887 		case PDO_FETCH_INTO:
1888 			if (stmt->fetch.into) {
1889 				zval_ptr_dtor(&stmt->fetch.into);
1890 				stmt->fetch.into = NULL;
1891 			}
1892 			break;
1893 		default:
1894 			;
1895 	}
1896 
1897 	stmt->default_fetch_type = PDO_FETCH_BOTH;
1898 
1899 	if (argc == 0) {
1900 		return SUCCESS;
1901 	}
1902 
1903 	args = safe_emalloc(ZEND_NUM_ARGS(), sizeof(zval*), 0);
1904 
1905 	retval = zend_get_parameters_array_ex(ZEND_NUM_ARGS(), args);
1906 
1907 	if (SUCCESS == retval) {
1908 		if (Z_TYPE_PP(args[skip]) != IS_LONG) {
1909 			pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "mode must be an integer" TSRMLS_CC);
1910 			retval = FAILURE;
1911 		} else {
1912 			mode = Z_LVAL_PP(args[skip]);
1913 			flags = mode & PDO_FETCH_FLAGS;
1914 
1915 			retval = pdo_stmt_verify_mode(stmt, mode, 0 TSRMLS_CC);
1916 		}
1917 	}
1918 
1919 	if (FAILURE == retval) {
1920 		PDO_STMT_CLEAR_ERR();
1921 		efree(args);
1922 		return FAILURE;
1923 	}
1924 
1925 	retval = FAILURE;
1926 	switch (mode & ~PDO_FETCH_FLAGS) {
1927 		case PDO_FETCH_USE_DEFAULT:
1928 		case PDO_FETCH_LAZY:
1929 		case PDO_FETCH_ASSOC:
1930 		case PDO_FETCH_NUM:
1931 		case PDO_FETCH_BOTH:
1932 		case PDO_FETCH_OBJ:
1933 		case PDO_FETCH_BOUND:
1934 		case PDO_FETCH_NAMED:
1935 		case PDO_FETCH_KEY_PAIR:
1936 			if (argc != 1) {
1937 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1938 			} else {
1939 				retval = SUCCESS;
1940 			}
1941 			break;
1942 
1943 		case PDO_FETCH_COLUMN:
1944 			if (argc != 2) {
1945 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the colno argument" TSRMLS_CC);
1946 			} else	if (Z_TYPE_PP(args[skip+1]) != IS_LONG) {
1947 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "colno must be an integer" TSRMLS_CC);
1948 			} else {
1949 				stmt->fetch.column = Z_LVAL_PP(args[skip+1]);
1950 				retval = SUCCESS;
1951 			}
1952 			break;
1953 
1954 		case PDO_FETCH_CLASS:
1955 			/* Gets its class name from 1st column */
1956 			if ((flags & PDO_FETCH_CLASSTYPE) == PDO_FETCH_CLASSTYPE) {
1957 				if (argc != 1) {
1958 					pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode doesn't allow any extra arguments" TSRMLS_CC);
1959 				} else {
1960 					stmt->fetch.cls.ce = NULL;
1961 					retval = SUCCESS;
1962 				}
1963 			} else {
1964 				if (argc < 2) {
1965 					pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the classname argument" TSRMLS_CC);
1966 				} else if (argc > 3) {
1967 					pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "too many arguments" TSRMLS_CC);
1968 				} else if (Z_TYPE_PP(args[skip+1]) != IS_STRING) {
1969 					pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "classname must be a string" TSRMLS_CC);
1970 				} else {
1971 					retval = zend_lookup_class(Z_STRVAL_PP(args[skip+1]),
1972 						Z_STRLEN_PP(args[skip+1]), &cep TSRMLS_CC);
1973 
1974 					if (SUCCESS == retval && cep && *cep) {
1975 						stmt->fetch.cls.ce = *cep;
1976 					}
1977 				}
1978 			}
1979 
1980 			if (SUCCESS == retval) {
1981 				stmt->fetch.cls.ctor_args = NULL;
1982 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
1983 				if (stmt->dbh->is_persistent) {
1984 					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");
1985 				}
1986 #endif
1987 				if (argc == 3) {
1988 					if (Z_TYPE_PP(args[skip+2]) != IS_NULL && Z_TYPE_PP(args[skip+2]) != IS_ARRAY) {
1989 						pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "ctor_args must be either NULL or an array" TSRMLS_CC);
1990 						retval = FAILURE;
1991 					} else if (Z_TYPE_PP(args[skip+2]) == IS_ARRAY && zend_hash_num_elements(Z_ARRVAL_PP(args[skip+2]))) {
1992 						ALLOC_ZVAL(stmt->fetch.cls.ctor_args);
1993 						*stmt->fetch.cls.ctor_args = **args[skip+2];
1994 						zval_copy_ctor(stmt->fetch.cls.ctor_args);
1995 					}
1996 				}
1997 
1998 				if (SUCCESS == retval) {
1999 					do_fetch_class_prepare(stmt TSRMLS_CC);
2000 				}
2001 			}
2002 
2003 			break;
2004 
2005 		case PDO_FETCH_INTO:
2006 			if (argc != 2) {
2007 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "fetch mode requires the object parameter" TSRMLS_CC);
2008 			} else if (Z_TYPE_PP(args[skip+1]) != IS_OBJECT) {
2009 				pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "object must be an object" TSRMLS_CC);
2010 			} else {
2011 				retval = SUCCESS;
2012 			}
2013 
2014 			if (SUCCESS == retval) {
2015 #ifdef ilia_0 /* we'll only need this when we have persistent statements, if ever */
2016 				if (stmt->dbh->is_persistent) {
2017 					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");
2018 				}
2019 #endif
2020 				MAKE_STD_ZVAL(stmt->fetch.into);
2021 
2022 				Z_TYPE_P(stmt->fetch.into) = IS_OBJECT;
2023 				Z_OBJ_HANDLE_P(stmt->fetch.into) = Z_OBJ_HANDLE_PP(args[skip+1]);
2024 				Z_OBJ_HT_P(stmt->fetch.into) = Z_OBJ_HT_PP(args[skip+1]);
2025 				zend_objects_store_add_ref(stmt->fetch.into TSRMLS_CC);
2026 			}
2027 
2028 			break;
2029 
2030 		default:
2031 			pdo_raise_impl_error(stmt->dbh, stmt, "22003", "Invalid fetch mode specified" TSRMLS_CC);
2032 	}
2033 
2034 	if (SUCCESS == retval) {
2035 		stmt->default_fetch_type = mode;
2036 	}
2037 
2038 	/*
2039 	 * PDO error (if any) has already been raised at this point.
2040 	 *
2041 	 * The error_code is cleared, otherwise the caller will read the
2042 	 * last error message from the driver.
2043 	 *
2044 	 */
2045 	PDO_STMT_CLEAR_ERR();
2046 
2047 	efree(args);
2048 
2049 	return retval;
2050 }
2051 
PHP_METHOD(PDOStatement,setFetchMode)2052 static PHP_METHOD(PDOStatement, setFetchMode)
2053 {
2054 	PHP_STMT_GET_OBJ;
2055 
2056 	RETVAL_BOOL(
2057 		pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU,
2058 			stmt, 0) == SUCCESS ? 1 : 0
2059 		);
2060 }
2061 /* }}} */
2062 
2063 /* {{{ proto bool PDOStatement::nextRowset()
2064    Advances to the next rowset in a multi-rowset statement handle. Returns true if it succeded, false otherwise */
2065 
pdo_stmt_do_next_rowset(pdo_stmt_t * stmt TSRMLS_DC)2066 static int pdo_stmt_do_next_rowset(pdo_stmt_t *stmt TSRMLS_DC)
2067 {
2068 	/* un-describe */
2069 	if (stmt->columns) {
2070 		int i;
2071 		struct pdo_column_data *cols = stmt->columns;
2072 
2073 		for (i = 0; i < stmt->column_count; i++) {
2074 			efree(cols[i].name);
2075 		}
2076 		efree(stmt->columns);
2077 		stmt->columns = NULL;
2078 		stmt->column_count = 0;
2079 	}
2080 
2081 	if (!stmt->methods->next_rowset(stmt TSRMLS_CC)) {
2082 		/* Set the executed flag to 0 to reallocate columns on next execute */
2083 		stmt->executed = 0;
2084 		return 0;
2085 	}
2086 
2087 	pdo_stmt_describe_columns(stmt TSRMLS_CC);
2088 
2089 	return 1;
2090 }
2091 
PHP_METHOD(PDOStatement,nextRowset)2092 static PHP_METHOD(PDOStatement, nextRowset)
2093 {
2094 	PHP_STMT_GET_OBJ;
2095 
2096 	if (!stmt->methods->next_rowset) {
2097 		pdo_raise_impl_error(stmt->dbh, stmt, "IM001", "driver does not support multiple rowsets" TSRMLS_CC);
2098 		RETURN_FALSE;
2099 	}
2100 
2101 	PDO_STMT_CLEAR_ERR();
2102 
2103 	if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2104 		PDO_HANDLE_STMT_ERR();
2105 		RETURN_FALSE;
2106 	}
2107 
2108 	RETURN_TRUE;
2109 }
2110 /* }}} */
2111 
2112 /* {{{ proto bool PDOStatement::closeCursor()
2113    Closes the cursor, leaving the statement ready for re-execution. */
PHP_METHOD(PDOStatement,closeCursor)2114 static PHP_METHOD(PDOStatement, closeCursor)
2115 {
2116 	PHP_STMT_GET_OBJ;
2117 
2118 	if (!stmt->methods->cursor_closer) {
2119 		/* emulate it by fetching and discarding rows */
2120 		do {
2121 			while (stmt->methods->fetcher(stmt, PDO_FETCH_ORI_NEXT, 0 TSRMLS_CC))
2122 				;
2123 			if (!stmt->methods->next_rowset) {
2124 				break;
2125 			}
2126 
2127 			if (!pdo_stmt_do_next_rowset(stmt TSRMLS_CC)) {
2128 				break;
2129 			}
2130 
2131 		} while (1);
2132 		stmt->executed = 0;
2133 		RETURN_TRUE;
2134 	}
2135 
2136 	PDO_STMT_CLEAR_ERR();
2137 
2138 	if (!stmt->methods->cursor_closer(stmt TSRMLS_CC)) {
2139 		PDO_HANDLE_STMT_ERR();
2140 		RETURN_FALSE;
2141 	}
2142 	stmt->executed = 0;
2143 	RETURN_TRUE;
2144 }
2145 /* }}} */
2146 
2147 /* {{{ proto void PDOStatement::debugDumpParams()
2148    A utility for internals hackers to debug parameter internals */
PHP_METHOD(PDOStatement,debugDumpParams)2149 static PHP_METHOD(PDOStatement, debugDumpParams)
2150 {
2151 	php_stream *out = php_stream_open_wrapper("php://output", "w", 0, NULL);
2152 	HashPosition pos;
2153 	struct pdo_bound_param_data *param;
2154 	PHP_STMT_GET_OBJ;
2155 
2156 	if (out == NULL) {
2157 		RETURN_FALSE;
2158 	}
2159 
2160 	php_stream_printf(out TSRMLS_CC, "SQL: [%d] %.*s\n",
2161 		stmt->query_stringlen,
2162 		stmt->query_stringlen, stmt->query_string);
2163 
2164 	php_stream_printf(out TSRMLS_CC, "Params:  %d\n",
2165 		stmt->bound_params ? zend_hash_num_elements(stmt->bound_params) : 0);
2166 
2167 	if (stmt->bound_params) {
2168 		zend_hash_internal_pointer_reset_ex(stmt->bound_params, &pos);
2169 		while (SUCCESS == zend_hash_get_current_data_ex(stmt->bound_params,
2170 				(void**)&param, &pos)) {
2171 			char *str;
2172 			uint len;
2173 			ulong num;
2174 			int res;
2175 
2176 			res = zend_hash_get_current_key_ex(stmt->bound_params, &str, &len, &num, 0, &pos);
2177 			if (res == HASH_KEY_IS_LONG) {
2178 				php_stream_printf(out TSRMLS_CC, "Key: Position #%ld:\n", num);
2179 			} else if (res == HASH_KEY_IS_STRING) {
2180 				php_stream_printf(out TSRMLS_CC, "Key: Name: [%d] %.*s\n", len, len, str);
2181 			}
2182 
2183 			php_stream_printf(out TSRMLS_CC, "paramno=%ld\nname=[%d] \"%.*s\"\nis_param=%d\nparam_type=%d\n",
2184 				param->paramno, param->namelen, param->namelen, param->name ? param->name : "",
2185 				param->is_param,
2186 				param->param_type);
2187 
2188 			zend_hash_move_forward_ex(stmt->bound_params, &pos);
2189 		}
2190 	}
2191 
2192 	php_stream_close(out);
2193 }
2194 /* }}} */
2195 
2196 /* {{{ proto int PDOStatement::__wakeup()
2197    Prevents use of a PDOStatement instance that has been unserialized */
PHP_METHOD(PDOStatement,__wakeup)2198 static PHP_METHOD(PDOStatement, __wakeup)
2199 {
2200 	zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2201 }
2202 /* }}} */
2203 
2204 /* {{{ proto int PDOStatement::__sleep()
2205    Prevents serialization of a PDOStatement instance */
PHP_METHOD(PDOStatement,__sleep)2206 static PHP_METHOD(PDOStatement, __sleep)
2207 {
2208 	zend_throw_exception_ex(php_pdo_get_exception(), 0 TSRMLS_CC, "You cannot serialize or unserialize PDOStatement instances");
2209 }
2210 /* }}} */
2211 
2212 const zend_function_entry pdo_dbstmt_functions[] = {
2213 	PHP_ME(PDOStatement, execute,		arginfo_pdostatement_execute,		ZEND_ACC_PUBLIC)
2214 	PHP_ME(PDOStatement, fetch,			arginfo_pdostatement_fetch,			ZEND_ACC_PUBLIC)
2215 	PHP_ME(PDOStatement, bindParam,		arginfo_pdostatement_bindparam,		ZEND_ACC_PUBLIC)
2216 	PHP_ME(PDOStatement, bindColumn,	arginfo_pdostatement_bindcolumn,	ZEND_ACC_PUBLIC)
2217 	PHP_ME(PDOStatement, bindValue,		arginfo_pdostatement_bindvalue,		ZEND_ACC_PUBLIC)
2218 	PHP_ME(PDOStatement, rowCount,		arginfo_pdostatement__void,			ZEND_ACC_PUBLIC)
2219 	PHP_ME(PDOStatement, fetchColumn,	arginfo_pdostatement_fetchcolumn,	ZEND_ACC_PUBLIC)
2220 	PHP_ME(PDOStatement, fetchAll,		arginfo_pdostatement_fetchall,		ZEND_ACC_PUBLIC)
2221 	PHP_ME(PDOStatement, fetchObject,	arginfo_pdostatement_fetchobject,	ZEND_ACC_PUBLIC)
2222 	PHP_ME(PDOStatement, errorCode,		arginfo_pdostatement__void,			ZEND_ACC_PUBLIC)
2223 	PHP_ME(PDOStatement, errorInfo,		arginfo_pdostatement__void,			ZEND_ACC_PUBLIC)
2224 	PHP_ME(PDOStatement, setAttribute,	arginfo_pdostatement_setattribute,	ZEND_ACC_PUBLIC)
2225 	PHP_ME(PDOStatement, getAttribute,	arginfo_pdostatement_getattribute,	ZEND_ACC_PUBLIC)
2226 	PHP_ME(PDOStatement, columnCount,	arginfo_pdostatement__void,			ZEND_ACC_PUBLIC)
2227 	PHP_ME(PDOStatement, getColumnMeta,	arginfo_pdostatement_getcolumnmeta,	ZEND_ACC_PUBLIC)
2228 	PHP_ME(PDOStatement, setFetchMode,	arginfo_pdostatement_setfetchmode,	ZEND_ACC_PUBLIC)
2229 	PHP_ME(PDOStatement, nextRowset,	arginfo_pdostatement__void,			ZEND_ACC_PUBLIC)
2230 	PHP_ME(PDOStatement, closeCursor,	arginfo_pdostatement__void,			ZEND_ACC_PUBLIC)
2231 	PHP_ME(PDOStatement, debugDumpParams, arginfo_pdostatement__void,		ZEND_ACC_PUBLIC)
2232 	PHP_ME(PDOStatement, __wakeup,		arginfo_pdostatement__void,			ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2233 	PHP_ME(PDOStatement, __sleep,		arginfo_pdostatement__void,			ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
2234 	{NULL, NULL, NULL}
2235 };
2236 
2237 /* {{{ overloaded handlers for PDOStatement class */
dbstmt_prop_write(zval * object,zval * member,zval * value,const zend_literal * key TSRMLS_DC)2238 static void dbstmt_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
2239 {
2240 	pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2241 
2242 	convert_to_string(member);
2243 
2244 	if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2245 		pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2246 	} else {
2247 		std_object_handlers.write_property(object, member, value, key TSRMLS_CC);
2248 	}
2249 }
2250 
dbstmt_prop_delete(zval * object,zval * member,const zend_literal * key TSRMLS_DC)2251 static void dbstmt_prop_delete(zval *object, zval *member, const zend_literal *key TSRMLS_DC)
2252 {
2253 	pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2254 
2255 	convert_to_string(member);
2256 
2257 	if(strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2258 		pdo_raise_impl_error(stmt->dbh, stmt, "HY000", "property queryString is read only" TSRMLS_CC);
2259 	} else {
2260 		std_object_handlers.unset_property(object, member, key TSRMLS_CC);
2261 	}
2262 }
2263 
dbstmt_method_get(zval ** object_pp,char * method_name,int method_len,const zend_literal * key TSRMLS_DC)2264 static union _zend_function *dbstmt_method_get(
2265 #if PHP_API_VERSION >= 20041225
2266 	zval **object_pp,
2267 #else
2268 	zval *object,
2269 #endif
2270    	char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
2271 {
2272 	zend_function *fbc = NULL;
2273 	char *lc_method_name;
2274 #if PHP_API_VERSION >= 20041225
2275 	zval *object = *object_pp;
2276 #endif
2277 
2278 	lc_method_name = emalloc(method_len + 1);
2279 	zend_str_tolower_copy(lc_method_name, method_name, method_len);
2280 
2281 	if (zend_hash_find(&Z_OBJCE_P(object)->function_table, lc_method_name,
2282 			method_len+1, (void**)&fbc) == FAILURE) {
2283 		pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2284 		/* instance not created by PDO object */
2285 		if (!stmt->dbh) {
2286 			goto out;
2287 		}
2288 		/* not a pre-defined method, nor a user-defined method; check
2289 		 * the driver specific methods */
2290 		if (!stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2291 			if (!pdo_hash_methods(stmt->dbh,
2292 				PDO_DBH_DRIVER_METHOD_KIND_STMT TSRMLS_CC)
2293 				|| !stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT]) {
2294 				goto out;
2295 			}
2296 		}
2297 
2298 		if (zend_hash_find(stmt->dbh->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_STMT],
2299 				lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2300 			fbc = NULL;
2301 			goto out;
2302 		}
2303 		/* got it */
2304 	}
2305 
2306 out:
2307 	efree(lc_method_name);
2308 	return fbc;
2309 }
2310 
dbstmt_compare(zval * object1,zval * object2 TSRMLS_DC)2311 static int dbstmt_compare(zval *object1, zval *object2 TSRMLS_DC)
2312 {
2313 	return -1;
2314 }
2315 
dbstmt_clone_obj(zval * zobject TSRMLS_DC)2316 static zend_object_value dbstmt_clone_obj(zval *zobject TSRMLS_DC)
2317 {
2318 	zend_object_value retval;
2319 	pdo_stmt_t *stmt;
2320 	pdo_stmt_t *old_stmt;
2321 	zend_object_handle handle = Z_OBJ_HANDLE_P(zobject);
2322 
2323 	stmt = ecalloc(1, sizeof(*stmt));
2324 	zend_object_std_init(&stmt->std, Z_OBJCE_P(zobject) TSRMLS_CC);
2325 	object_properties_init(&stmt->std, Z_OBJCE_P(zobject));
2326 	stmt->refcount = 1;
2327 
2328 	old_stmt = (pdo_stmt_t *)zend_object_store_get_object(zobject TSRMLS_CC);
2329 
2330 	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);
2331 	retval.handlers = Z_OBJ_HT_P(zobject);
2332 
2333 	zend_objects_clone_members((zend_object *)stmt, retval, (zend_object *)old_stmt, handle TSRMLS_CC);
2334 
2335 	zend_objects_store_add_ref(&old_stmt->database_object_handle TSRMLS_CC);
2336 	stmt->database_object_handle = old_stmt->database_object_handle;
2337 
2338 	return retval;
2339 }
2340 
2341 zend_object_handlers pdo_dbstmt_object_handlers;
2342 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC);
2343 
pdo_stmt_init(TSRMLS_D)2344 void pdo_stmt_init(TSRMLS_D)
2345 {
2346 	zend_class_entry ce;
2347 
2348 	INIT_CLASS_ENTRY(ce, "PDOStatement", pdo_dbstmt_functions);
2349 	pdo_dbstmt_ce = zend_register_internal_class(&ce TSRMLS_CC);
2350 	pdo_dbstmt_ce->get_iterator = pdo_stmt_iter_get;
2351 	pdo_dbstmt_ce->create_object = pdo_dbstmt_new;
2352 	zend_class_implements(pdo_dbstmt_ce TSRMLS_CC, 1, zend_ce_traversable);
2353 	zend_declare_property_null(pdo_dbstmt_ce, "queryString", sizeof("queryString")-1, ZEND_ACC_PUBLIC TSRMLS_CC);
2354 
2355 	memcpy(&pdo_dbstmt_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
2356 	pdo_dbstmt_object_handlers.write_property = dbstmt_prop_write;
2357 	pdo_dbstmt_object_handlers.unset_property = dbstmt_prop_delete;
2358 	pdo_dbstmt_object_handlers.get_method = dbstmt_method_get;
2359 	pdo_dbstmt_object_handlers.compare_objects = dbstmt_compare;
2360 	pdo_dbstmt_object_handlers.clone_obj = dbstmt_clone_obj;
2361 
2362 	INIT_CLASS_ENTRY(ce, "PDORow", pdo_row_functions);
2363 	pdo_row_ce = zend_register_internal_class(&ce TSRMLS_CC);
2364 	pdo_row_ce->ce_flags |= ZEND_ACC_FINAL_CLASS; /* when removing this a lot of handlers need to be redone */
2365 	pdo_row_ce->create_object = pdo_row_new;
2366 	pdo_row_ce->serialize = pdo_row_serialize;
2367 }
2368 
free_statement(pdo_stmt_t * stmt TSRMLS_DC)2369 static void free_statement(pdo_stmt_t *stmt TSRMLS_DC)
2370 {
2371 	if (stmt->bound_params) {
2372 		zend_hash_destroy(stmt->bound_params);
2373 		FREE_HASHTABLE(stmt->bound_params);
2374 		stmt->bound_params = NULL;
2375 	}
2376 	if (stmt->bound_param_map) {
2377 		zend_hash_destroy(stmt->bound_param_map);
2378 		FREE_HASHTABLE(stmt->bound_param_map);
2379 		stmt->bound_param_map = NULL;
2380 	}
2381 	if (stmt->bound_columns) {
2382 		zend_hash_destroy(stmt->bound_columns);
2383 		FREE_HASHTABLE(stmt->bound_columns);
2384 		stmt->bound_columns = NULL;
2385 	}
2386 
2387 	if (stmt->methods && stmt->methods->dtor) {
2388 		stmt->methods->dtor(stmt TSRMLS_CC);
2389 	}
2390 	if (stmt->query_string) {
2391 		efree(stmt->query_string);
2392 	}
2393 
2394 	if (stmt->columns) {
2395 		int i;
2396 		struct pdo_column_data *cols = stmt->columns;
2397 
2398 		for (i = 0; i < stmt->column_count; i++) {
2399 			if (cols[i].name) {
2400 				efree(cols[i].name);
2401 				cols[i].name = NULL;
2402 			}
2403 		}
2404 		efree(stmt->columns);
2405 		stmt->columns = NULL;
2406 	}
2407 
2408 	if (stmt->fetch.into && stmt->default_fetch_type == PDO_FETCH_INTO) {
2409 		FREE_ZVAL(stmt->fetch.into);
2410 		stmt->fetch.into = NULL;
2411 	}
2412 
2413 	do_fetch_opt_finish(stmt, 1 TSRMLS_CC);
2414 
2415 	zend_objects_store_del_ref(&stmt->database_object_handle TSRMLS_CC);
2416 	if (stmt->dbh) {
2417 		php_pdo_dbh_delref(stmt->dbh TSRMLS_CC);
2418 	}
2419 	zend_object_std_dtor(&stmt->std TSRMLS_CC);
2420 	efree(stmt);
2421 }
2422 
php_pdo_stmt_addref(pdo_stmt_t * stmt TSRMLS_DC)2423 PDO_API void php_pdo_stmt_addref(pdo_stmt_t *stmt TSRMLS_DC)
2424 {
2425 	stmt->refcount++;
2426 }
2427 
php_pdo_stmt_delref(pdo_stmt_t * stmt TSRMLS_DC)2428 PDO_API void php_pdo_stmt_delref(pdo_stmt_t *stmt TSRMLS_DC)
2429 {
2430 	if (--stmt->refcount == 0) {
2431 		free_statement(stmt TSRMLS_CC);
2432 	}
2433 }
2434 
pdo_dbstmt_free_storage(pdo_stmt_t * stmt TSRMLS_DC)2435 void pdo_dbstmt_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2436 {
2437 	php_pdo_stmt_delref(stmt TSRMLS_CC);
2438 }
2439 
pdo_dbstmt_new(zend_class_entry * ce TSRMLS_DC)2440 zend_object_value pdo_dbstmt_new(zend_class_entry *ce TSRMLS_DC)
2441 {
2442 	zend_object_value retval;
2443 
2444 	pdo_stmt_t *stmt;
2445 	stmt = emalloc(sizeof(*stmt));
2446 	memset(stmt, 0, sizeof(*stmt));
2447 	zend_object_std_init(&stmt->std, ce TSRMLS_CC);
2448 	object_properties_init(&stmt->std, ce);
2449 	stmt->refcount = 1;
2450 
2451 	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);
2452 	retval.handlers = &pdo_dbstmt_object_handlers;
2453 
2454 	return retval;
2455 }
2456 /* }}} */
2457 
2458 /* {{{ statement iterator */
2459 
2460 struct php_pdo_iterator {
2461 	zend_object_iterator iter;
2462 	pdo_stmt_t *stmt;
2463 	ulong key;
2464 	zval *fetch_ahead;
2465 };
2466 
pdo_stmt_iter_dtor(zend_object_iterator * iter TSRMLS_DC)2467 static void pdo_stmt_iter_dtor(zend_object_iterator *iter TSRMLS_DC)
2468 {
2469 	struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2470 
2471 	if (--I->stmt->refcount == 0) {
2472 		free_statement(I->stmt TSRMLS_CC);
2473 	}
2474 
2475 	if (I->fetch_ahead) {
2476 		zval_ptr_dtor(&I->fetch_ahead);
2477 	}
2478 
2479 	efree(I);
2480 }
2481 
pdo_stmt_iter_valid(zend_object_iterator * iter TSRMLS_DC)2482 static int pdo_stmt_iter_valid(zend_object_iterator *iter TSRMLS_DC)
2483 {
2484 	struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2485 
2486 	return I->fetch_ahead ? SUCCESS : FAILURE;
2487 }
2488 
pdo_stmt_iter_get_data(zend_object_iterator * iter,zval *** data TSRMLS_DC)2489 static void pdo_stmt_iter_get_data(zend_object_iterator *iter, zval ***data TSRMLS_DC)
2490 {
2491 	struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2492 
2493 	/* sanity */
2494 	if (!I->fetch_ahead) {
2495 		*data = NULL;
2496 		return;
2497 	}
2498 
2499 	*data = &I->fetch_ahead;
2500 }
2501 
pdo_stmt_iter_get_key(zend_object_iterator * iter,char ** str_key,uint * str_key_len,ulong * int_key TSRMLS_DC)2502 static int pdo_stmt_iter_get_key(zend_object_iterator *iter, char **str_key, uint *str_key_len,
2503 	ulong *int_key TSRMLS_DC)
2504 {
2505 	struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2506 
2507 	if (I->key == (ulong)-1) {
2508 		return HASH_KEY_NON_EXISTANT;
2509 	}
2510 	*int_key = I->key;
2511 	return HASH_KEY_IS_LONG;
2512 }
2513 
pdo_stmt_iter_move_forwards(zend_object_iterator * iter TSRMLS_DC)2514 static void pdo_stmt_iter_move_forwards(zend_object_iterator *iter TSRMLS_DC)
2515 {
2516 	struct php_pdo_iterator *I = (struct php_pdo_iterator*)iter->data;
2517 
2518 	if (I->fetch_ahead) {
2519 		zval_ptr_dtor(&I->fetch_ahead);
2520 		I->fetch_ahead = NULL;
2521 	}
2522 
2523 	MAKE_STD_ZVAL(I->fetch_ahead);
2524 
2525 	if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2526 			PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2527 		pdo_stmt_t *stmt = I->stmt; /* for PDO_HANDLE_STMT_ERR() */
2528 
2529 		PDO_HANDLE_STMT_ERR();
2530 		I->key = (ulong)-1;
2531 		FREE_ZVAL(I->fetch_ahead);
2532 		I->fetch_ahead = NULL;
2533 
2534 		return;
2535 	}
2536 
2537 	I->key++;
2538 }
2539 
2540 static zend_object_iterator_funcs pdo_stmt_iter_funcs = {
2541 	pdo_stmt_iter_dtor,
2542 	pdo_stmt_iter_valid,
2543 	pdo_stmt_iter_get_data,
2544 	pdo_stmt_iter_get_key,
2545 	pdo_stmt_iter_move_forwards,
2546 	NULL
2547 };
2548 
pdo_stmt_iter_get(zend_class_entry * ce,zval * object,int by_ref TSRMLS_DC)2549 zend_object_iterator *pdo_stmt_iter_get(zend_class_entry *ce, zval *object, int by_ref TSRMLS_DC)
2550 {
2551 	pdo_stmt_t *stmt = (pdo_stmt_t*)zend_object_store_get_object(object TSRMLS_CC);
2552 	struct php_pdo_iterator *I;
2553 
2554 	if (by_ref) {
2555 		zend_error(E_ERROR, "An iterator cannot be used with foreach by reference");
2556 	}
2557 
2558 	I = ecalloc(1, sizeof(*I));
2559 	I->iter.funcs = &pdo_stmt_iter_funcs;
2560 	I->iter.data = I;
2561 	I->stmt = stmt;
2562 	stmt->refcount++;
2563 
2564 	MAKE_STD_ZVAL(I->fetch_ahead);
2565 	if (!do_fetch(I->stmt, TRUE, I->fetch_ahead, PDO_FETCH_USE_DEFAULT,
2566 			PDO_FETCH_ORI_NEXT, 0, 0 TSRMLS_CC)) {
2567 		PDO_HANDLE_STMT_ERR();
2568 		I->key = (ulong)-1;
2569 		FREE_ZVAL(I->fetch_ahead);
2570 		I->fetch_ahead = NULL;
2571 	}
2572 
2573 	return &I->iter;
2574 }
2575 
2576 /* }}} */
2577 
2578 /* {{{ overloaded handlers for PDORow class (used by PDO_FETCH_LAZY) */
2579 
2580 const zend_function_entry pdo_row_functions[] = {
2581 	{NULL, NULL, NULL}
2582 };
2583 
row_prop_read(zval * object,zval * member,int type,const zend_literal * key TSRMLS_DC)2584 static zval *row_prop_read(zval *object, zval *member, int type, const zend_literal *key TSRMLS_DC)
2585 {
2586 	zval *return_value;
2587 	pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2588 	int colno = -1;
2589 
2590 	MAKE_STD_ZVAL(return_value);
2591 	RETVAL_NULL();
2592 
2593 	if (stmt) {
2594 		if (Z_TYPE_P(member) == IS_LONG) {
2595 			if (Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count) {
2596 				fetch_value(stmt, return_value, Z_LVAL_P(member), NULL TSRMLS_CC);
2597 			}
2598 		} else {
2599 			convert_to_string(member);
2600 			/* TODO: replace this with a hash of available column names to column
2601 			 * numbers */
2602 			for (colno = 0; colno < stmt->column_count; colno++) {
2603 				if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2604 					fetch_value(stmt, return_value, colno, NULL TSRMLS_CC);
2605 					Z_SET_REFCOUNT_P(return_value, 0);
2606 					Z_UNSET_ISREF_P(return_value);
2607 					return return_value;
2608 				}
2609 			}
2610 			if (strcmp(Z_STRVAL_P(member), "queryString") == 0) {
2611 				zval_ptr_dtor(&return_value);
2612 				return std_object_handlers.read_property(object, member, type, key TSRMLS_CC);
2613 			}
2614 		}
2615 	}
2616 
2617 	Z_SET_REFCOUNT_P(return_value, 0);
2618 	Z_UNSET_ISREF_P(return_value);
2619 
2620 	return return_value;
2621 }
2622 
row_dim_read(zval * object,zval * member,int type TSRMLS_DC)2623 static zval *row_dim_read(zval *object, zval *member, int type TSRMLS_DC)
2624 {
2625 	return row_prop_read(object, member, type, NULL TSRMLS_CC);
2626 }
2627 
row_prop_write(zval * object,zval * member,zval * value,const zend_literal * key TSRMLS_DC)2628 static void row_prop_write(zval *object, zval *member, zval *value, const zend_literal *key TSRMLS_DC)
2629 {
2630 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2631 }
2632 
row_dim_write(zval * object,zval * member,zval * value TSRMLS_DC)2633 static void row_dim_write(zval *object, zval *member, zval *value TSRMLS_DC)
2634 {
2635 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "This PDORow is not from a writable result set");
2636 }
2637 
row_prop_exists(zval * object,zval * member,int check_empty,const zend_literal * key TSRMLS_DC)2638 static int row_prop_exists(zval *object, zval *member, int check_empty, const zend_literal *key TSRMLS_DC)
2639 {
2640 	pdo_stmt_t * stmt = (pdo_stmt_t *) zend_object_store_get_object(object TSRMLS_CC);
2641 	int colno = -1;
2642 
2643 	if (stmt) {
2644 		if (Z_TYPE_P(member) == IS_LONG) {
2645 			return Z_LVAL_P(member) >= 0 && Z_LVAL_P(member) < stmt->column_count;
2646 		} else {
2647 			convert_to_string(member);
2648 
2649 			/* TODO: replace this with a hash of available column names to column
2650 			 * numbers */
2651 			for (colno = 0; colno < stmt->column_count; colno++) {
2652 				if (strcmp(stmt->columns[colno].name, Z_STRVAL_P(member)) == 0) {
2653 					return 1;
2654 				}
2655 			}
2656 		}
2657 	}
2658 
2659 	return 0;
2660 }
2661 
row_dim_exists(zval * object,zval * member,int check_empty TSRMLS_DC)2662 static int row_dim_exists(zval *object, zval *member, int check_empty TSRMLS_DC)
2663 {
2664 	return row_prop_exists(object, member, check_empty, NULL TSRMLS_CC);
2665 }
2666 
row_prop_delete(zval * object,zval * offset,const zend_literal * key TSRMLS_DC)2667 static void row_prop_delete(zval *object, zval *offset, const zend_literal *key TSRMLS_DC)
2668 {
2669 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot delete properties from a PDORow");
2670 }
2671 
row_dim_delete(zval * object,zval * offset TSRMLS_DC)2672 static void row_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 	if (!stmt->std.properties) {
2687 		rebuild_object_properties(&stmt->std);
2688 	}
2689 	for (i = 0; i < stmt->column_count; i++) {
2690 		zval *val;
2691 		MAKE_STD_ZVAL(val);
2692 		fetch_value(stmt, val, i, NULL TSRMLS_CC);
2693 
2694 		zend_hash_update(stmt->std.properties, stmt->columns[i].name, stmt->columns[i].namelen + 1, (void *)&val, sizeof(zval *), NULL);
2695 	}
2696 
2697 	return stmt->std.properties;
2698 }
2699 
row_method_get(zval ** object_pp,char * method_name,int method_len,const zend_literal * key TSRMLS_DC)2700 static union _zend_function *row_method_get(
2701 #if PHP_API_VERSION >= 20041225
2702 	zval **object_pp,
2703 #else
2704 	zval *object,
2705 #endif
2706 	char *method_name, int method_len, const zend_literal *key TSRMLS_DC)
2707 {
2708 	zend_function *fbc;
2709 	char *lc_method_name;
2710 
2711 	lc_method_name = emalloc(method_len + 1);
2712 	zend_str_tolower_copy(lc_method_name, method_name, method_len);
2713 
2714 	if (zend_hash_find(&pdo_row_ce->function_table, lc_method_name, method_len+1, (void**)&fbc) == FAILURE) {
2715 		efree(lc_method_name);
2716 		return NULL;
2717 	}
2718 
2719 	efree(lc_method_name);
2720 	return fbc;
2721 }
2722 
row_call_method(const char * method,INTERNAL_FUNCTION_PARAMETERS)2723 static int row_call_method(const char *method, INTERNAL_FUNCTION_PARAMETERS)
2724 {
2725 	return FAILURE;
2726 }
2727 
row_get_ctor(zval * object TSRMLS_DC)2728 static union _zend_function *row_get_ctor(zval *object TSRMLS_DC)
2729 {
2730 	static zend_internal_function ctor = {0};
2731 
2732 	ctor.type = ZEND_INTERNAL_FUNCTION;
2733 	ctor.function_name = "__construct";
2734 	ctor.scope = pdo_row_ce;
2735 	ctor.handler = ZEND_FN(dbstmt_constructor);
2736 
2737 	return (union _zend_function*)&ctor;
2738 }
2739 
row_get_ce(const zval * object TSRMLS_DC)2740 static zend_class_entry *row_get_ce(const zval *object TSRMLS_DC)
2741 {
2742 	return pdo_row_ce;
2743 }
2744 
row_get_classname(const zval * object,const char ** class_name,zend_uint * class_name_len,int parent TSRMLS_DC)2745 static int row_get_classname(const zval *object, const char **class_name, zend_uint *class_name_len, int parent TSRMLS_DC)
2746 {
2747 	if (parent) {
2748 		return FAILURE;
2749 	} else {
2750 		*class_name = estrndup("PDORow", sizeof("PDORow")-1);
2751 		*class_name_len = sizeof("PDORow")-1;
2752 		return SUCCESS;
2753 	}
2754 }
2755 
row_compare(zval * object1,zval * object2 TSRMLS_DC)2756 static int row_compare(zval *object1, zval *object2 TSRMLS_DC)
2757 {
2758 	return -1;
2759 }
2760 
2761 zend_object_handlers pdo_row_object_handlers = {
2762 	zend_objects_store_add_ref,
2763 	zend_objects_store_del_ref,
2764 	NULL,
2765 	row_prop_read,
2766 	row_prop_write,
2767 	row_dim_read,
2768 	row_dim_write,
2769 	NULL,
2770 	NULL,
2771 	NULL,
2772 	row_prop_exists,
2773 	row_prop_delete,
2774 	row_dim_exists,
2775 	row_dim_delete,
2776 	row_get_properties,
2777 	row_method_get,
2778 	row_call_method,
2779 	row_get_ctor,
2780 	row_get_ce,
2781 	row_get_classname,
2782 	row_compare,
2783 	NULL, /* cast */
2784 	NULL
2785 };
2786 
pdo_row_free_storage(pdo_stmt_t * stmt TSRMLS_DC)2787 void pdo_row_free_storage(pdo_stmt_t *stmt TSRMLS_DC)
2788 {
2789 	if (stmt) {
2790 		ZVAL_NULL(&stmt->lazy_object_ref);
2791 
2792 		if (--stmt->refcount == 0) {
2793 			free_statement(stmt TSRMLS_CC);
2794 		}
2795 	}
2796 }
2797 
pdo_row_new(zend_class_entry * ce TSRMLS_DC)2798 zend_object_value pdo_row_new(zend_class_entry *ce TSRMLS_DC)
2799 {
2800 	zend_object_value retval;
2801 
2802 	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);
2803 	retval.handlers = &pdo_row_object_handlers;
2804 
2805 	return retval;
2806 }
2807 
pdo_row_serialize(zval * object,unsigned char ** buffer,zend_uint * buf_len,zend_serialize_data * data TSRMLS_DC)2808 static int pdo_row_serialize(zval *object, unsigned char **buffer, zend_uint *buf_len, zend_serialize_data *data TSRMLS_DC)
2809 {
2810 	php_error_docref(NULL TSRMLS_CC, E_WARNING, "PDORow instances may not be serialized");
2811 	return FAILURE;
2812 }
2813 /* }}} */
2814 
2815 /*
2816  * Local variables:
2817  * tab-width: 4
2818  * c-basic-offset: 4
2819  * End:
2820  * vim600: noet sw=4 ts=4 fdm=marker
2821  * vim<600: noet sw=4 ts=4
2822  */
2823