xref: /PHP-7.0/ext/pdo/pdo_dbh.c (revision 478f119a)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2017 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 Database 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 "php_pdo.h"
33 #include "php_pdo_driver.h"
34 #include "php_pdo_int.h"
35 #include "zend_exceptions.h"
36 #include "zend_object_handlers.h"
37 #include "zend_hash.h"
38 
39 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value);
40 
pdo_raise_impl_error(pdo_dbh_t * dbh,pdo_stmt_t * stmt,const char * sqlstate,const char * supp)41 void pdo_raise_impl_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, const char *sqlstate, const char *supp) /* {{{ */
42 {
43 	pdo_error_type *pdo_err = &dbh->error_code;
44 	char *message = NULL;
45 	const char *msg;
46 
47 	if (dbh && dbh->error_mode == PDO_ERRMODE_SILENT) {
48 #if 0
49 		/* BUG: if user is running in silent mode and hits an error at the driver level
50 		 * when they use the PDO methods to call up the error information, they may
51 		 * get bogus information */
52 		return;
53 #endif
54 	}
55 
56 	if (stmt) {
57 		pdo_err = &stmt->error_code;
58 	}
59 
60 	strncpy(*pdo_err, sqlstate, 6);
61 
62 	/* hash sqlstate to error messages */
63 	msg = pdo_sqlstate_state_to_description(*pdo_err);
64 	if (!msg) {
65 		msg = "<<Unknown error>>";
66 	}
67 
68 	if (supp) {
69 		spprintf(&message, 0, "SQLSTATE[%s]: %s: %s", *pdo_err, msg, supp);
70 	} else {
71 		spprintf(&message, 0, "SQLSTATE[%s]: %s", *pdo_err, msg);
72 	}
73 
74 	if (dbh && dbh->error_mode != PDO_ERRMODE_EXCEPTION) {
75 		php_error_docref(NULL, E_WARNING, "%s", message);
76 	} else {
77 		zval ex, info;
78 		zend_class_entry *def_ex = php_pdo_get_exception_base(1), *pdo_ex = php_pdo_get_exception();
79 
80 		object_init_ex(&ex, pdo_ex);
81 
82 		zend_update_property_string(def_ex, &ex, "message", sizeof("message")-1, message);
83 		zend_update_property_string(def_ex, &ex, "code", sizeof("code")-1, *pdo_err);
84 
85 		array_init(&info);
86 
87 		add_next_index_string(&info, *pdo_err);
88 		add_next_index_long(&info, 0);
89 		zend_update_property(pdo_ex, &ex, "errorInfo", sizeof("errorInfo")-1, &info);
90 		zval_ptr_dtor(&info);
91 
92 		zend_throw_exception_object(&ex);
93 	}
94 
95 	if (message) {
96 		efree(message);
97 	}
98 }
99 /* }}} */
100 
pdo_handle_error(pdo_dbh_t * dbh,pdo_stmt_t * stmt)101 PDO_API void pdo_handle_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt) /* {{{ */
102 {
103 	pdo_error_type *pdo_err = &dbh->error_code;
104 	const char *msg = "<<Unknown>>";
105 	char *supp = NULL;
106 	zend_long native_code = 0;
107 	zend_string *message = NULL;
108 	zval info;
109 
110 	if (dbh == NULL || dbh->error_mode == PDO_ERRMODE_SILENT) {
111 		return;
112 	}
113 
114 	if (stmt) {
115 		pdo_err = &stmt->error_code;
116 	}
117 
118 	/* hash sqlstate to error messages */
119 	msg = pdo_sqlstate_state_to_description(*pdo_err);
120 	if (!msg) {
121 		msg = "<<Unknown error>>";
122 	}
123 
124 	ZVAL_UNDEF(&info);
125 	if (dbh->methods->fetch_err) {
126 		array_init(&info);
127 
128 		add_next_index_string(&info, *pdo_err);
129 
130 		if (dbh->methods->fetch_err(dbh, stmt, &info)) {
131 			zval *item;
132 
133 			if ((item = zend_hash_index_find(Z_ARRVAL(info), 1)) != NULL) {
134 				native_code = Z_LVAL_P(item);
135 			}
136 
137 			if ((item = zend_hash_index_find(Z_ARRVAL(info), 2)) != NULL) {
138 				supp = estrndup(Z_STRVAL_P(item), Z_STRLEN_P(item));
139 			}
140 		}
141 	}
142 
143 	if (supp) {
144 		message = strpprintf(0, "SQLSTATE[%s]: %s: %ld %s", *pdo_err, msg, native_code, supp);
145 	} else {
146 		message = strpprintf(0, "SQLSTATE[%s]: %s", *pdo_err, msg);
147 	}
148 
149 	if (dbh->error_mode == PDO_ERRMODE_WARNING) {
150 		php_error_docref(NULL, E_WARNING, "%s", ZSTR_VAL(message));
151 	} else if (EG(exception) == NULL) {
152 		zval ex;
153 		zend_class_entry *def_ex = php_pdo_get_exception_base(1), *pdo_ex = php_pdo_get_exception();
154 
155 		object_init_ex(&ex, pdo_ex);
156 
157 		zend_update_property_str(def_ex, &ex, "message", sizeof("message") - 1, message);
158 		zend_update_property_string(def_ex, &ex, "code", sizeof("code") - 1, *pdo_err);
159 
160 		if (!Z_ISUNDEF(info)) {
161 			zend_update_property(pdo_ex, &ex, "errorInfo", sizeof("errorInfo") - 1, &info);
162 		}
163 
164 		zend_throw_exception_object(&ex);
165 	}
166 
167 	if (!Z_ISUNDEF(info)) {
168 		zval_ptr_dtor(&info);
169 	}
170 
171 	if (message) {
172 		zend_string_release(message);
173 	}
174 
175 	if (supp) {
176 		efree(supp);
177 	}
178 }
179 /* }}} */
180 
dsn_from_uri(char * uri,char * buf,size_t buflen)181 static char *dsn_from_uri(char *uri, char *buf, size_t buflen) /* {{{ */
182 {
183 	php_stream *stream;
184 	char *dsn = NULL;
185 
186 	stream = php_stream_open_wrapper(uri, "rb", REPORT_ERRORS, NULL);
187 	if (stream) {
188 		dsn = php_stream_get_line(stream, buf, buflen, NULL);
189 		php_stream_close(stream);
190 	}
191 	return dsn;
192 }
193 /* }}} */
194 
195 /* {{{ proto void PDO::__construct(string dsn[, string username[, string passwd [, array options]]])
196    */
PHP_METHOD(PDO,dbh_constructor)197 static PHP_METHOD(PDO, dbh_constructor)
198 {
199 	zval *object = getThis();
200 	pdo_dbh_t *dbh = NULL;
201 	zend_bool is_persistent = 0;
202 	char *data_source;
203 	size_t data_source_len;
204 	char *colon;
205 	char *username=NULL, *password=NULL;
206 	size_t usernamelen, passwordlen;
207 	pdo_driver_t *driver = NULL;
208 	zval *options = NULL;
209 	char alt_dsn[512];
210 	int call_factory = 1;
211 	zend_error_handling zeh;
212 
213 	if (FAILURE == zend_parse_parameters_throw(ZEND_NUM_ARGS(),
214 				"s|s!s!a!", &data_source, &data_source_len,
215 				&username, &usernamelen, &password, &passwordlen, &options)) {
216 		return;
217 	}
218 
219 	/* parse the data source name */
220 	colon = strchr(data_source, ':');
221 
222 	if (!colon) {
223 		/* let's see if this string has a matching dsn in the php.ini */
224 		char *ini_dsn = NULL;
225 
226 		snprintf(alt_dsn, sizeof(alt_dsn), "pdo.dsn.%s", data_source);
227 		if (FAILURE == cfg_get_string(alt_dsn, &ini_dsn)) {
228 			zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source name");
229 			return;
230 		}
231 
232 		data_source = ini_dsn;
233 		colon = strchr(data_source, ':');
234 
235 		if (!colon) {
236 			zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source name (via INI: %s)", alt_dsn);
237 			return;
238 		}
239 	}
240 
241 	if (!strncmp(data_source, "uri:", sizeof("uri:")-1)) {
242 		/* the specified URI holds connection details */
243 		data_source = dsn_from_uri(data_source + sizeof("uri:")-1, alt_dsn, sizeof(alt_dsn));
244 		if (!data_source) {
245 			zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source URI");
246 			return;
247 		}
248 		colon = strchr(data_source, ':');
249 		if (!colon) {
250 			zend_throw_exception_ex(php_pdo_get_exception(), 0, "invalid data source name (via URI)");
251 			return;
252 		}
253 	}
254 
255 	driver = pdo_find_driver(data_source, colon - data_source);
256 
257 	if (!driver) {
258 		/* NB: don't want to include the data_source in the error message as
259 		 * it might contain a password */
260 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "could not find driver");
261 		return;
262 	}
263 
264 	dbh = Z_PDO_DBH_P(object);
265 
266 	/* is this supposed to be a persistent connection ? */
267 	if (options) {
268 		int plen = 0;
269 		char *hashkey = NULL;
270 		zend_resource *le;
271 		pdo_dbh_t *pdbh = NULL;
272 		zval *v;
273 
274 		if ((v = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_PERSISTENT)) != NULL) {
275 			if (Z_TYPE_P(v) == IS_STRING &&
276 				!is_numeric_string(Z_STRVAL_P(v), Z_STRLEN_P(v), NULL, NULL, 0) && Z_STRLEN_P(v) > 0) {
277 				/* user specified key */
278 				plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s:%s", data_source,
279 						username ? username : "",
280 						password ? password : "",
281 						Z_STRVAL_P(v));
282 				is_persistent = 1;
283 			} else {
284 				is_persistent = zval_get_long(v) ? 1 : 0;
285 				plen = spprintf(&hashkey, 0, "PDO:DBH:DSN=%s:%s:%s", data_source,
286 						username ? username : "",
287 						password ? password : "");
288 			}
289 		}
290 
291 		if (is_persistent) {
292 			/* let's see if we have one cached.... */
293 			if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hashkey, plen)) != NULL) {
294 				if (le->type == php_pdo_list_entry()) {
295 					pdbh = (pdo_dbh_t*)le->ptr;
296 
297 					/* is the connection still alive ? */
298 					if (pdbh->methods->check_liveness && FAILURE == (pdbh->methods->check_liveness)(pdbh)) {
299 						/* nope... need to kill it */
300 						pdbh->refcount--;
301 						zend_list_close(le);
302 						pdbh = NULL;
303 					}
304 				}
305 			}
306 
307 			if (pdbh) {
308 				call_factory = 0;
309 			} else {
310 				/* need a brand new pdbh */
311 				pdbh = pecalloc(1, sizeof(*pdbh), 1);
312 
313 				pdbh->refcount = 1;
314 				pdbh->is_persistent = 1;
315 				pdbh->persistent_id = pemalloc(plen + 1, 1);
316 				memcpy((char *)pdbh->persistent_id, hashkey, plen+1);
317 				pdbh->persistent_id_len = plen;
318 				pdbh->def_stmt_ce = dbh->def_stmt_ce;
319 			}
320 		}
321 
322 		if (pdbh) {
323 			efree(dbh);
324 			/* switch over to the persistent one */
325 			Z_PDO_OBJECT_P(object)->inner = pdbh;
326 			pdbh->refcount++;
327 			dbh = pdbh;
328 		}
329 
330 		if (hashkey) {
331 			efree(hashkey);
332 		}
333 	}
334 
335 	if (call_factory) {
336 		dbh->data_source_len = strlen(colon + 1);
337 		dbh->data_source = (const char*)pestrdup(colon + 1, is_persistent);
338 		dbh->username = username ? pestrdup(username, is_persistent) : NULL;
339 		dbh->password = password ? pestrdup(password, is_persistent) : NULL;
340 		dbh->default_fetch_type = PDO_FETCH_BOTH;
341 	}
342 
343 	dbh->auto_commit = pdo_attr_lval(options, PDO_ATTR_AUTOCOMMIT, 1);
344 
345 	if (!dbh->data_source || (username && !dbh->username) || (password && !dbh->password)) {
346 		php_error_docref(NULL, E_ERROR, "out of memory");
347 	}
348 
349 	zend_replace_error_handling(EH_THROW, pdo_exception_ce, &zeh);
350 
351 	if (!call_factory) {
352 		/* we got a persistent guy from our cache */
353 		goto options;
354 	}
355 
356 	if (driver->db_handle_factory(dbh, options)) {
357 		/* all set */
358 
359 		if (is_persistent) {
360 			zend_resource le;
361 
362 			/* register in the persistent list etc. */
363 			/* we should also need to replace the object store entry,
364 			   since it was created with emalloc */
365 
366 			le.type = php_pdo_list_entry();
367 			le.ptr = dbh;
368 			GC_REFCOUNT(&le) = 1;
369 
370 			if ((zend_hash_str_update_mem(&EG(persistent_list),
371 						(char*)dbh->persistent_id, dbh->persistent_id_len, &le, sizeof(le))) == NULL) {
372 				php_error_docref(NULL, E_ERROR, "Failed to register persistent entry");
373 			}
374 		}
375 
376 		dbh->driver = driver;
377 options:
378 		if (options) {
379 			zval *attr_value;
380 			zend_ulong long_key;
381 			zend_string *str_key = NULL;
382 
383 			ZEND_HASH_FOREACH_KEY_VAL(Z_ARRVAL_P(options), long_key, str_key, attr_value) {
384 				if (str_key) {
385 					continue;
386 				}
387 				pdo_dbh_attribute_set(dbh, long_key, attr_value);
388 			} ZEND_HASH_FOREACH_END();
389 		}
390 
391 		zend_restore_error_handling(&zeh);
392 		return;
393 	}
394 
395 	/* the connection failed; things will tidy up in free_storage */
396 	/* XXX raise exception */
397 	zend_restore_error_handling(&zeh);
398 	if (!EG(exception)) {
399 		zend_throw_exception(pdo_exception_ce, "Constructor failed", 0);
400 	}
401 }
402 /* }}} */
403 
pdo_stmt_instantiate(pdo_dbh_t * dbh,zval * object,zend_class_entry * dbstmt_ce,zval * ctor_args)404 static zval *pdo_stmt_instantiate(pdo_dbh_t *dbh, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */
405 {
406 	if (!Z_ISUNDEF_P(ctor_args)) {
407 		if (Z_TYPE_P(ctor_args) != IS_ARRAY) {
408 			pdo_raise_impl_error(dbh, NULL, "HY000", "constructor arguments must be passed as an array");
409 			return NULL;
410 		}
411 		if (!dbstmt_ce->constructor) {
412 			pdo_raise_impl_error(dbh, NULL, "HY000", "user-supplied statement does not accept constructor arguments");
413 			return NULL;
414 		}
415 	}
416 
417 	if (UNEXPECTED(object_init_ex(object, dbstmt_ce) != SUCCESS)) {
418 		return NULL;
419 	}
420 
421 	return object;
422 } /* }}} */
423 
pdo_stmt_construct(zend_execute_data * execute_data,pdo_stmt_t * stmt,zval * object,zend_class_entry * dbstmt_ce,zval * ctor_args)424 static void pdo_stmt_construct(zend_execute_data *execute_data, pdo_stmt_t *stmt, zval *object, zend_class_entry *dbstmt_ce, zval *ctor_args) /* {{{ */
425 {
426 	zval query_string;
427 	zval z_key;
428 
429 	ZVAL_STRINGL(&query_string, stmt->query_string, stmt->query_stringlen);
430 	ZVAL_STRINGL(&z_key, "queryString", sizeof("queryString") - 1);
431 	std_object_handlers.write_property(object, &z_key, &query_string, NULL);
432 	zval_ptr_dtor(&query_string);
433 	zval_ptr_dtor(&z_key);
434 
435 	if (dbstmt_ce->constructor) {
436 		zend_fcall_info fci;
437 		zend_fcall_info_cache fcc;
438 		zval retval;
439 
440 		fci.size = sizeof(zend_fcall_info);
441 		fci.function_table = &dbstmt_ce->function_table;
442 		ZVAL_UNDEF(&fci.function_name);
443 		fci.object = Z_OBJ_P(object);
444 		fci.symbol_table = NULL;
445 		fci.retval = &retval;
446 		fci.param_count = 0;
447 		fci.params = NULL;
448 		fci.no_separation = 1;
449 
450 		zend_fcall_info_args(&fci, ctor_args);
451 
452 		fcc.initialized = 1;
453 		fcc.function_handler = dbstmt_ce->constructor;
454 		fcc.calling_scope = EG(scope);
455 		fcc.called_scope = Z_OBJCE_P(object);
456 		fcc.object = Z_OBJ_P(object);
457 
458 		if (zend_call_function(&fci, &fcc) != FAILURE) {
459 			zval_ptr_dtor(&retval);
460 		}
461 
462 		zend_fcall_info_args_clear(&fci, 1);
463 	}
464 }
465 /* }}} */
466 
467 /* {{{ proto object PDO::prepare(string statement [, array options])
468    Prepares a statement for execution and returns a statement object */
PHP_METHOD(PDO,prepare)469 static PHP_METHOD(PDO, prepare)
470 {
471 	pdo_stmt_t *stmt;
472 	char *statement;
473 	size_t statement_len;
474 	zval *options = NULL, *opt, *item, ctor_args;
475 	zend_class_entry *dbstmt_ce, *pce;
476 	pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis());
477 	pdo_dbh_t *dbh = dbh_obj->inner;
478 
479 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &statement,
480 			&statement_len, &options)) {
481 		RETURN_FALSE;
482 	}
483 
484 	PDO_DBH_CLEAR_ERR();
485 	PDO_CONSTRUCT_CHECK;
486 
487 	if (ZEND_NUM_ARGS() > 1 && (opt = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS)) != NULL) {
488 		if (Z_TYPE_P(opt) != IS_ARRAY || (item = zend_hash_index_find(Z_ARRVAL_P(opt), 0)) == NULL
489 			|| Z_TYPE_P(item) != IS_STRING
490 			|| (pce = zend_lookup_class(Z_STR_P(item))) == NULL
491 		) {
492 			pdo_raise_impl_error(dbh, NULL, "HY000",
493 				"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
494 				"the classname must be a string specifying an existing class"
495 				);
496 			PDO_HANDLE_DBH_ERR();
497 			RETURN_FALSE;
498 		}
499 		dbstmt_ce = pce;
500 		if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce)) {
501 			pdo_raise_impl_error(dbh, NULL, "HY000",
502 				"user-supplied statement class must be derived from PDOStatement");
503 			PDO_HANDLE_DBH_ERR();
504 			RETURN_FALSE;
505 		}
506 		if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
507 			pdo_raise_impl_error(dbh, NULL, "HY000",
508 				"user-supplied statement class cannot have a public constructor");
509 			PDO_HANDLE_DBH_ERR();
510 			RETURN_FALSE;
511 		}
512 		if ((item = zend_hash_index_find(Z_ARRVAL_P(opt), 1)) != NULL) {
513 			if (Z_TYPE_P(item) != IS_ARRAY) {
514 				pdo_raise_impl_error(dbh, NULL, "HY000",
515 					"PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
516 					"ctor_args must be an array"
517 				);
518 				PDO_HANDLE_DBH_ERR();
519 				RETURN_FALSE;
520 			}
521 			ZVAL_COPY_VALUE(&ctor_args, item);
522 		} else {
523 			ZVAL_UNDEF(&ctor_args);
524 		}
525 	} else {
526 		dbstmt_ce = dbh->def_stmt_ce;
527 		ZVAL_COPY_VALUE(&ctor_args, &dbh->def_stmt_ctor_args);
528 	}
529 
530 	if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, &ctor_args)) {
531 		if (EXPECTED(!EG(exception))) {
532 			pdo_raise_impl_error(dbh, NULL, "HY000",
533 				"failed to instantiate user-supplied statement class"
534 				);
535 		}
536 		PDO_HANDLE_DBH_ERR();
537 		RETURN_FALSE;
538 	}
539 	stmt = Z_PDO_STMT_P(return_value);
540 
541 	/* unconditionally keep this for later reference */
542 	stmt->query_string = estrndup(statement, statement_len);
543 	stmt->query_stringlen = statement_len;
544 	stmt->default_fetch_type = dbh->default_fetch_type;
545 	stmt->dbh = dbh;
546 	/* give it a reference to me */
547 	ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std);
548 	Z_ADDREF(stmt->database_object_handle);
549 	/* we haven't created a lazy object yet */
550 	ZVAL_UNDEF(&stmt->lazy_object_ref);
551 
552 	if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options)) {
553 		pdo_stmt_construct(execute_data, stmt, return_value, dbstmt_ce, &ctor_args);
554 		return;
555 	}
556 
557 	PDO_HANDLE_DBH_ERR();
558 
559 	/* kill the object handle for the stmt here */
560 	zval_dtor(return_value);
561 
562 	RETURN_FALSE;
563 }
564 /* }}} */
565 
566 /* {{{ proto bool PDO::beginTransaction()
567    Initiates a transaction */
PHP_METHOD(PDO,beginTransaction)568 static PHP_METHOD(PDO, beginTransaction)
569 {
570 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
571 
572 	if (zend_parse_parameters_none() == FAILURE) {
573 		return;
574 	}
575 	PDO_CONSTRUCT_CHECK;
576 
577 	if (dbh->in_txn) {
578 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is already an active transaction");
579 		RETURN_FALSE;
580 	}
581 
582 	if (!dbh->methods->begin) {
583 		/* TODO: this should be an exception; see the auto-commit mode
584 		 * comments below */
585 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "This driver doesn't support transactions");
586 		RETURN_FALSE;
587 	}
588 
589 	if (dbh->methods->begin(dbh)) {
590 		dbh->in_txn = 1;
591 		RETURN_TRUE;
592 	}
593 
594 	PDO_HANDLE_DBH_ERR();
595 	RETURN_FALSE;
596 }
597 /* }}} */
598 
599 /* {{{ proto bool PDO::commit()
600    Commit a transaction */
PHP_METHOD(PDO,commit)601 static PHP_METHOD(PDO, commit)
602 {
603 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
604 
605 	if (zend_parse_parameters_none() == FAILURE) {
606 		return;
607 	}
608 	PDO_CONSTRUCT_CHECK;
609 
610 	if (!dbh->in_txn) {
611 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
612 		RETURN_FALSE;
613 	}
614 
615 	if (dbh->methods->commit(dbh)) {
616 		dbh->in_txn = 0;
617 		RETURN_TRUE;
618 	}
619 
620 	PDO_HANDLE_DBH_ERR();
621 	RETURN_FALSE;
622 }
623 /* }}} */
624 
625 /* {{{ proto bool PDO::rollBack()
626    roll back a transaction */
PHP_METHOD(PDO,rollBack)627 static PHP_METHOD(PDO, rollBack)
628 {
629 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
630 
631 	if (zend_parse_parameters_none() == FAILURE) {
632 		return;
633 	}
634 	PDO_CONSTRUCT_CHECK;
635 
636 	if (!dbh->in_txn) {
637 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
638 		RETURN_FALSE;
639 	}
640 
641 	if (dbh->methods->rollback(dbh)) {
642 		dbh->in_txn = 0;
643 		RETURN_TRUE;
644 	}
645 
646 	PDO_HANDLE_DBH_ERR();
647 	RETURN_FALSE;
648 }
649 /* }}} */
650 
651 /* {{{ proto bool PDO::inTransaction()
652    determine if inside a transaction */
PHP_METHOD(PDO,inTransaction)653 static PHP_METHOD(PDO, inTransaction)
654 {
655 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
656 
657 	if (zend_parse_parameters_none() == FAILURE) {
658 		return;
659 	}
660 	PDO_CONSTRUCT_CHECK;
661 
662 	if (!dbh->methods->in_transaction) {
663 		RETURN_BOOL(dbh->in_txn);
664 	}
665 
666 	RETURN_BOOL(dbh->methods->in_transaction(dbh));
667 }
668 /* }}} */
669 
pdo_dbh_attribute_set(pdo_dbh_t * dbh,zend_long attr,zval * value)670 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /* {{{ */
671 {
672 	zend_long lval;
673 
674 #define PDO_LONG_PARAM_CHECK \
675 	if (Z_TYPE_P(value) != IS_LONG && Z_TYPE_P(value) != IS_STRING && Z_TYPE_P(value) != IS_FALSE && Z_TYPE_P(value) != IS_TRUE) { \
676 		pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer"); \
677 		PDO_HANDLE_DBH_ERR(); \
678 		return FAILURE; \
679 	} \
680 
681 	switch (attr) {
682 		case PDO_ATTR_ERRMODE:
683 			PDO_LONG_PARAM_CHECK;
684 			lval = zval_get_long(value);
685 			switch (lval) {
686 				case PDO_ERRMODE_SILENT:
687 				case PDO_ERRMODE_WARNING:
688 				case PDO_ERRMODE_EXCEPTION:
689 					dbh->error_mode = lval;
690 					return SUCCESS;
691 				default:
692 					pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode");
693 					PDO_HANDLE_DBH_ERR();
694 					return FAILURE;
695 			}
696 			return FAILURE;
697 
698 		case PDO_ATTR_CASE:
699 			PDO_LONG_PARAM_CHECK;
700 			lval = zval_get_long(value);
701 			switch (lval) {
702 				case PDO_CASE_NATURAL:
703 				case PDO_CASE_UPPER:
704 				case PDO_CASE_LOWER:
705 					dbh->desired_case = lval;
706 					return SUCCESS;
707 				default:
708 					pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode");
709 					PDO_HANDLE_DBH_ERR();
710 					return FAILURE;
711 			}
712 			return FAILURE;
713 
714 		case PDO_ATTR_ORACLE_NULLS:
715 			PDO_LONG_PARAM_CHECK;
716 			dbh->oracle_nulls = zval_get_long(value);
717 			return SUCCESS;
718 
719 		case PDO_ATTR_DEFAULT_FETCH_MODE:
720 			if (Z_TYPE_P(value) == IS_ARRAY) {
721 				zval *tmp;
722 				if ((tmp = zend_hash_index_find(Z_ARRVAL_P(value), 0)) != NULL && Z_TYPE_P(tmp) == IS_LONG) {
723 					if (Z_LVAL_P(tmp) == PDO_FETCH_INTO || Z_LVAL_P(tmp) == PDO_FETCH_CLASS) {
724 						pdo_raise_impl_error(dbh, NULL, "HY000", "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes");
725 						return FAILURE;
726 					}
727 				}
728 			} else {
729 				PDO_LONG_PARAM_CHECK;
730 			}
731 			lval = zval_get_long(value);
732 			if (lval == PDO_FETCH_USE_DEFAULT) {
733 				pdo_raise_impl_error(dbh, NULL, "HY000", "invalid fetch mode type");
734 				return FAILURE;
735 			}
736 			dbh->default_fetch_type = lval;
737 			return SUCCESS;
738 
739 		case PDO_ATTR_STRINGIFY_FETCHES:
740 			PDO_LONG_PARAM_CHECK;
741 			dbh->stringify = zval_get_long(value) ? 1 : 0;
742 			return SUCCESS;
743 
744 		case PDO_ATTR_STATEMENT_CLASS: {
745 			/* array(string classname, array(mixed ctor_args)) */
746 			zend_class_entry *pce;
747 			zval *item;
748 
749 			if (dbh->is_persistent) {
750 				pdo_raise_impl_error(dbh, NULL, "HY000",
751 					"PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances"
752 					);
753 				PDO_HANDLE_DBH_ERR();
754 				return FAILURE;
755 			}
756 			if (Z_TYPE_P(value) != IS_ARRAY
757 				|| (item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL
758 				|| Z_TYPE_P(item) != IS_STRING
759 				|| (pce = zend_lookup_class(Z_STR_P(item))) == NULL
760 			) {
761 				pdo_raise_impl_error(dbh, NULL, "HY000",
762 					"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
763 					"the classname must be a string specifying an existing class"
764 					);
765 				PDO_HANDLE_DBH_ERR();
766 				return FAILURE;
767 			}
768 			if (!instanceof_function(pce, pdo_dbstmt_ce)) {
769 				pdo_raise_impl_error(dbh, NULL, "HY000",
770 					"user-supplied statement class must be derived from PDOStatement");
771 				PDO_HANDLE_DBH_ERR();
772 				return FAILURE;
773 			}
774 			if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
775 				pdo_raise_impl_error(dbh, NULL, "HY000",
776 					"user-supplied statement class cannot have a public constructor");
777 				PDO_HANDLE_DBH_ERR();
778 				return FAILURE;
779 			}
780 			dbh->def_stmt_ce = pce;
781 			if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
782 				zval_ptr_dtor(&dbh->def_stmt_ctor_args);
783 				ZVAL_UNDEF(&dbh->def_stmt_ctor_args);
784 			}
785 			if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) {
786 				if (Z_TYPE_P(item) != IS_ARRAY) {
787 					pdo_raise_impl_error(dbh, NULL, "HY000",
788 						"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
789 						"ctor_args must be an array"
790 					);
791 					PDO_HANDLE_DBH_ERR();
792 					return FAILURE;
793 				}
794 				ZVAL_COPY(&dbh->def_stmt_ctor_args, item);
795 			}
796 			return SUCCESS;
797 		}
798 
799 		default:
800 			;
801 	}
802 
803 	if (!dbh->methods->set_attribute) {
804 		goto fail;
805 	}
806 
807 	PDO_DBH_CLEAR_ERR();
808 	if (dbh->methods->set_attribute(dbh, attr, value)) {
809 		return SUCCESS;
810 	}
811 
812 fail:
813 	if (attr == PDO_ATTR_AUTOCOMMIT) {
814 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "The auto-commit mode cannot be changed for this driver");
815 	} else if (!dbh->methods->set_attribute) {
816 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes");
817 	} else {
818 		PDO_HANDLE_DBH_ERR();
819 	}
820 	return FAILURE;
821 }
822 /* }}} */
823 
824 /* {{{ proto bool PDO::setAttribute(long attribute, mixed value)
825    Set an attribute */
PHP_METHOD(PDO,setAttribute)826 static PHP_METHOD(PDO, setAttribute)
827 {
828 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
829 	zend_long attr;
830 	zval *value;
831 
832 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &attr, &value)) {
833 		RETURN_FALSE;
834 	}
835 
836 	PDO_DBH_CLEAR_ERR();
837 	PDO_CONSTRUCT_CHECK;
838 
839 	if (pdo_dbh_attribute_set(dbh, attr, value) != FAILURE) {
840  		RETURN_TRUE;
841  	}
842  	RETURN_FALSE;
843 }
844 /* }}} */
845 
846 /* {{{ proto mixed PDO::getAttribute(long attribute)
847    Get an attribute */
PHP_METHOD(PDO,getAttribute)848 static PHP_METHOD(PDO, getAttribute)
849 {
850 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
851 	zend_long attr;
852 
853 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr)) {
854 		RETURN_FALSE;
855 	}
856 
857 	PDO_DBH_CLEAR_ERR();
858 	PDO_CONSTRUCT_CHECK;
859 
860 	/* handle generic PDO-level attributes */
861 	switch (attr) {
862 		case PDO_ATTR_PERSISTENT:
863 			RETURN_BOOL(dbh->is_persistent);
864 
865 		case PDO_ATTR_CASE:
866 			RETURN_LONG(dbh->desired_case);
867 
868 		case PDO_ATTR_ORACLE_NULLS:
869 			RETURN_LONG(dbh->oracle_nulls);
870 
871 		case PDO_ATTR_ERRMODE:
872 			RETURN_LONG(dbh->error_mode);
873 
874 		case PDO_ATTR_DRIVER_NAME:
875 			RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len);
876 
877 		case PDO_ATTR_STATEMENT_CLASS:
878 			array_init(return_value);
879 			add_next_index_str(return_value, zend_string_copy(dbh->def_stmt_ce->name));
880 			if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
881 				if (Z_REFCOUNTED(dbh->def_stmt_ctor_args)) Z_ADDREF(dbh->def_stmt_ctor_args);
882 				add_next_index_zval(return_value, &dbh->def_stmt_ctor_args);
883 			}
884 			return;
885 		case PDO_ATTR_DEFAULT_FETCH_MODE:
886 			RETURN_LONG(dbh->default_fetch_type);
887 		default:
888 			break;
889 	}
890 
891 	if (!dbh->methods->get_attribute) {
892 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes");
893 		RETURN_FALSE;
894 	}
895 
896 	switch (dbh->methods->get_attribute(dbh, attr, return_value)) {
897 		case -1:
898 			PDO_HANDLE_DBH_ERR();
899 			RETURN_FALSE;
900 
901 		case 0:
902 			pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute");
903 			RETURN_FALSE;
904 
905 		default:
906 			return;
907 	}
908 }
909 /* }}} */
910 
911 /* {{{ proto long PDO::exec(string query)
912    Execute a query that does not return a row set, returning the number of affected rows */
PHP_METHOD(PDO,exec)913 static PHP_METHOD(PDO, exec)
914 {
915 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
916 	char *statement;
917 	size_t statement_len;
918 	zend_long ret;
919 
920 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &statement, &statement_len)) {
921 		RETURN_FALSE;
922 	}
923 
924 	if (!statement_len) {
925 		pdo_raise_impl_error(dbh, NULL, "HY000",  "trying to execute an empty query");
926 		RETURN_FALSE;
927 	}
928 	PDO_DBH_CLEAR_ERR();
929 	PDO_CONSTRUCT_CHECK;
930 	ret = dbh->methods->doer(dbh, statement, statement_len);
931 	if(ret == -1) {
932 		PDO_HANDLE_DBH_ERR();
933 		RETURN_FALSE;
934 	} else {
935 		RETURN_LONG(ret);
936 	}
937 }
938 /* }}} */
939 
940 /* {{{ proto string PDO::lastInsertId([string seqname])
941    Returns the id of the last row that we affected on this connection.  Some databases require a sequence or table name to be passed in.  Not always meaningful. */
PHP_METHOD(PDO,lastInsertId)942 static PHP_METHOD(PDO, lastInsertId)
943 {
944 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
945 	char *name = NULL;
946 	size_t namelen;
947 
948 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &name, &namelen)) {
949 		RETURN_FALSE;
950 	}
951 
952 	PDO_DBH_CLEAR_ERR();
953 	PDO_CONSTRUCT_CHECK;
954 	if (!dbh->methods->last_id) {
955 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()");
956 		RETURN_FALSE;
957 	} else {
958 		size_t id_len;
959 		char *id;
960 		id = dbh->methods->last_id(dbh, name, &id_len);
961 		if (!id) {
962 			PDO_HANDLE_DBH_ERR();
963 			RETURN_FALSE;
964 		} else {
965 			//??? use zend_string ?
966 			RETVAL_STRINGL(id, id_len);
967 			efree(id);
968 		}
969 	}
970 }
971 /* }}} */
972 
973 /* {{{ proto string PDO::errorCode()
974    Fetch the error code associated with the last operation on the database handle */
PHP_METHOD(PDO,errorCode)975 static PHP_METHOD(PDO, errorCode)
976 {
977 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
978 
979 	if (zend_parse_parameters_none() == FAILURE) {
980 		return;
981 	}
982 	PDO_CONSTRUCT_CHECK;
983 
984 	if (dbh->query_stmt) {
985 		RETURN_STRING(dbh->query_stmt->error_code);
986 	}
987 
988 	if (dbh->error_code[0] == '\0') {
989 		RETURN_NULL();
990 	}
991 
992 	/**
993 	 * Making sure that we fallback to the default implementation
994 	 * if the dbh->error_code is not null.
995 	 */
996 	RETURN_STRING(dbh->error_code);
997 }
998 /* }}} */
999 
1000 /* {{{ proto int PDO::errorInfo()
1001    Fetch extended error information associated with the last operation on the database handle */
PHP_METHOD(PDO,errorInfo)1002 static PHP_METHOD(PDO, errorInfo)
1003 {
1004 	int error_count;
1005 	int error_count_diff 	 = 0;
1006 	int error_expected_count = 3;
1007 
1008 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
1009 
1010 	if (zend_parse_parameters_none() == FAILURE) {
1011 		return;
1012 	}
1013 
1014 	PDO_CONSTRUCT_CHECK;
1015 
1016 	array_init(return_value);
1017 
1018 	if (dbh->query_stmt) {
1019 		add_next_index_string(return_value, dbh->query_stmt->error_code);
1020 		if(!strncmp(dbh->query_stmt->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE))) goto fill_array;
1021 	} else {
1022 		add_next_index_string(return_value, dbh->error_code);
1023 		if(!strncmp(dbh->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE))) goto fill_array;
1024 	}
1025 
1026 	if (dbh->methods->fetch_err) {
1027 		dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value);
1028 	}
1029 
1030 fill_array:
1031 	/**
1032 	 * In order to be consistent, we have to make sure we add the good amount
1033 	 * of nulls depending on the current number of elements. We make a simple
1034 	 * difference and add the needed elements
1035 	 */
1036 	error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1037 
1038 	if (error_expected_count > error_count) {
1039 		int current_index;
1040 
1041 		error_count_diff = error_expected_count - error_count;
1042 		for (current_index = 0; current_index < error_count_diff; current_index++) {
1043 			add_next_index_null(return_value);
1044 		}
1045 	}
1046 }
1047 /* }}} */
1048 
1049 /* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args])
1050    Prepare and execute $sql; returns the statement object for iteration */
PHP_METHOD(PDO,query)1051 static PHP_METHOD(PDO, query)
1052 {
1053 	pdo_stmt_t *stmt;
1054 	char *statement;
1055 	size_t statement_len;
1056 	pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis());
1057 	pdo_dbh_t *dbh = dbh_obj->inner;
1058 
1059 	/* Return a meaningful error when no parameters were passed */
1060 	if (!ZEND_NUM_ARGS()) {
1061 		zend_parse_parameters(0, "z|z", NULL, NULL);
1062 		RETURN_FALSE;
1063 	}
1064 
1065 	if (FAILURE == zend_parse_parameters(1, "s", &statement,
1066 			&statement_len)) {
1067 		RETURN_FALSE;
1068 	}
1069 
1070 	PDO_DBH_CLEAR_ERR();
1071 	PDO_CONSTRUCT_CHECK;
1072 
1073 	if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args)) {
1074 		if (EXPECTED(!EG(exception))) {
1075 			pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class");
1076 		}
1077 		return;
1078 	}
1079 	stmt = Z_PDO_STMT_P(return_value);
1080 
1081 	/* unconditionally keep this for later reference */
1082 	stmt->query_string = estrndup(statement, statement_len);
1083 	stmt->query_stringlen = statement_len;
1084 
1085 	stmt->default_fetch_type = dbh->default_fetch_type;
1086 	stmt->active_query_string = stmt->query_string;
1087 	stmt->active_query_stringlen = statement_len;
1088 	stmt->dbh = dbh;
1089 	/* give it a reference to me */
1090 	ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std);
1091 	Z_ADDREF(stmt->database_object_handle);
1092 	/* we haven't created a lazy object yet */
1093 	ZVAL_UNDEF(&stmt->lazy_object_ref);
1094 
1095 	if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
1096 		PDO_STMT_CLEAR_ERR();
1097 		if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
1098 
1099 			/* now execute the statement */
1100 			PDO_STMT_CLEAR_ERR();
1101 			if (stmt->methods->executer(stmt)) {
1102 				int ret = 1;
1103 				if (!stmt->executed) {
1104 					if (stmt->dbh->alloc_own_columns) {
1105 						ret = pdo_stmt_describe_columns(stmt);
1106 					}
1107 					stmt->executed = 1;
1108 				}
1109 				if (ret) {
1110 					pdo_stmt_construct(execute_data, stmt, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args);
1111 					return;
1112 				}
1113 			}
1114 		}
1115 		/* something broke */
1116 		dbh->query_stmt = stmt;
1117 		ZVAL_COPY_VALUE(&dbh->query_stmt_zval, return_value);
1118 		Z_DELREF(stmt->database_object_handle);
1119 		ZVAL_UNDEF(&stmt->database_object_handle);
1120 		PDO_HANDLE_STMT_ERR();
1121 	} else {
1122 		PDO_HANDLE_DBH_ERR();
1123 		zval_ptr_dtor(return_value);
1124 	}
1125 
1126 	RETURN_FALSE;
1127 }
1128 /* }}} */
1129 
1130 /* {{{ proto string PDO::quote(string string [, int paramtype])
1131    quotes string for use in a query.  The optional paramtype acts as a hint for drivers that have alternate quoting styles.  The default value is PDO_PARAM_STR */
PHP_METHOD(PDO,quote)1132 static PHP_METHOD(PDO, quote)
1133 {
1134 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
1135 	char *str;
1136 	size_t str_len;
1137 	zend_long paramtype = PDO_PARAM_STR;
1138 	char *qstr;
1139 	size_t qlen;
1140 
1141 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &paramtype)) {
1142 		RETURN_FALSE;
1143 	}
1144 
1145 	PDO_DBH_CLEAR_ERR();
1146 	PDO_CONSTRUCT_CHECK;
1147 	if (!dbh->methods->quoter) {
1148 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting");
1149 		RETURN_FALSE;
1150 	}
1151 
1152 	if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype)) {
1153 		RETVAL_STRINGL(qstr, qlen);
1154 		efree(qstr);
1155 		return;
1156 	}
1157 	PDO_HANDLE_DBH_ERR();
1158 	RETURN_FALSE;
1159 }
1160 /* }}} */
1161 
1162 /* {{{ proto int PDO::__wakeup()
1163    Prevents use of a PDO instance that has been unserialized */
PHP_METHOD(PDO,__wakeup)1164 static PHP_METHOD(PDO, __wakeup)
1165 {
1166 	zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDO instances");
1167 }
1168 /* }}} */
1169 
1170 /* {{{ proto int PDO::__sleep()
1171    Prevents serialization of a PDO instance */
PHP_METHOD(PDO,__sleep)1172 static PHP_METHOD(PDO, __sleep)
1173 {
1174 	zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDO instances");
1175 }
1176 /* }}} */
1177 
1178 /* {{{ proto array PDO::getAvailableDrivers()
1179    Return array of available PDO drivers */
PHP_METHOD(PDO,getAvailableDrivers)1180 static PHP_METHOD(PDO, getAvailableDrivers)
1181 {
1182 	pdo_driver_t *pdriver;
1183 
1184 	if (zend_parse_parameters_none() == FAILURE) {
1185 		return;
1186 	}
1187 
1188 	array_init(return_value);
1189 
1190 	ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
1191 		add_next_index_stringl(return_value, (char*)pdriver->driver_name, pdriver->driver_name_len);
1192 	} ZEND_HASH_FOREACH_END();
1193 }
1194 /* }}} */
1195 
1196 /* {{{ arginfo */
1197 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 1)
1198 	ZEND_ARG_INFO(0, dsn)
1199 	ZEND_ARG_INFO(0, username)
1200 	ZEND_ARG_INFO(0, passwd)
1201 	ZEND_ARG_INFO(0, options) /* array */
1202 ZEND_END_ARG_INFO()
1203 
1204 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_prepare, 0, 0, 1)
1205 	ZEND_ARG_INFO(0, statement)
1206 	ZEND_ARG_INFO(0, options) /* array */
1207 ZEND_END_ARG_INFO()
1208 
1209 ZEND_BEGIN_ARG_INFO(arginfo_pdo_setattribute, 0)
1210 	ZEND_ARG_INFO(0, attribute)
1211 	ZEND_ARG_INFO(0, value)
1212 ZEND_END_ARG_INFO()
1213 
1214 ZEND_BEGIN_ARG_INFO(arginfo_pdo_getattribute, 0)
1215 	ZEND_ARG_INFO(0, attribute)
1216 ZEND_END_ARG_INFO()
1217 
1218 ZEND_BEGIN_ARG_INFO(arginfo_pdo_exec, 0)
1219 	ZEND_ARG_INFO(0, query)
1220 ZEND_END_ARG_INFO()
1221 
1222 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_lastinsertid, 0, 0, 0)
1223 	ZEND_ARG_INFO(0, seqname)
1224 ZEND_END_ARG_INFO()
1225 
1226 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1)
1227 	ZEND_ARG_INFO(0, string)
1228 	ZEND_ARG_INFO(0, paramtype)
1229 ZEND_END_ARG_INFO()
1230 
1231 ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0)
1232 ZEND_END_ARG_INFO()
1233 /* }}} */
1234 
1235 const zend_function_entry pdo_dbh_functions[] = /* {{{ */ {
1236 	ZEND_MALIAS(PDO, __construct, dbh_constructor,	arginfo_pdo___construct,	ZEND_ACC_PUBLIC)
1237 	PHP_ME(PDO, prepare, 				arginfo_pdo_prepare,		ZEND_ACC_PUBLIC)
1238 	PHP_ME(PDO, beginTransaction,       arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1239 	PHP_ME(PDO, commit,                 arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1240 	PHP_ME(PDO, rollBack,               arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1241 	PHP_ME(PDO, inTransaction,          arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1242 	PHP_ME(PDO, setAttribute,	arginfo_pdo_setattribute,	ZEND_ACC_PUBLIC)
1243 	PHP_ME(PDO, exec,			arginfo_pdo_exec,		ZEND_ACC_PUBLIC)
1244 	PHP_ME(PDO, query,			NULL,					ZEND_ACC_PUBLIC)
1245 	PHP_ME(PDO, lastInsertId,	arginfo_pdo_lastinsertid,	ZEND_ACC_PUBLIC)
1246 	PHP_ME(PDO, errorCode,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1247 	PHP_ME(PDO, errorInfo,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1248 	PHP_ME(PDO, getAttribute,	arginfo_pdo_getattribute,	ZEND_ACC_PUBLIC)
1249 	PHP_ME(PDO, quote,			arginfo_pdo_quote,		ZEND_ACC_PUBLIC)
1250 	PHP_ME(PDO, __wakeup,               arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1251 	PHP_ME(PDO, __sleep,                arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1252 	PHP_ME(PDO, getAvailableDrivers,    arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1253 	{NULL, NULL, NULL}
1254 };
1255 /* }}} */
1256 
cls_method_dtor(zval * el)1257 static void cls_method_dtor(zval *el) /* {{{ */ {
1258 	zend_function *func = (zend_function*)Z_PTR_P(el);
1259 	if (func->common.function_name) {
1260 		zend_string_release(func->common.function_name);
1261 	}
1262 	efree(func);
1263 }
1264 /* }}} */
1265 
cls_method_pdtor(zval * el)1266 static void cls_method_pdtor(zval *el) /* {{{ */ {
1267 	zend_function *func = (zend_function*)Z_PTR_P(el);
1268 	if (func->common.function_name) {
1269 		zend_string_release(func->common.function_name);
1270 	}
1271 	pefree(func, 1);
1272 }
1273 /* }}} */
1274 
1275 /* {{{ overloaded object handlers for PDO class */
pdo_hash_methods(pdo_dbh_object_t * dbh_obj,int kind)1276 int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
1277 {
1278 	const zend_function_entry *funcs;
1279 	zend_internal_function func;
1280 	size_t namelen;
1281 	char *lc_name;
1282 	pdo_dbh_t *dbh = dbh_obj->inner;
1283 
1284 	if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) {
1285 		return 0;
1286 	}
1287 	funcs =	dbh->methods->get_driver_methods(dbh, kind);
1288 	if (!funcs) {
1289 		return 0;
1290 	}
1291 
1292 	if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) {
1293 		php_error_docref(NULL, E_ERROR, "out of memory while allocating PDO methods.");
1294 	}
1295 	zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL,
1296 			dbh->is_persistent? cls_method_pdtor : cls_method_dtor, dbh->is_persistent, 0);
1297 
1298 	memset(&func, 0, sizeof(func));
1299 
1300 	while (funcs->fname) {
1301 		func.type = ZEND_INTERNAL_FUNCTION;
1302 		func.handler = funcs->handler;
1303 		func.function_name = zend_string_init(funcs->fname, strlen(funcs->fname), dbh->is_persistent);
1304 		func.scope = dbh_obj->std.ce;
1305 		func.prototype = NULL;
1306 		if (funcs->flags) {
1307 			func.fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE;
1308 		} else {
1309 			func.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_NEVER_CACHE;
1310 		}
1311 		if (funcs->arg_info) {
1312 			zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info;
1313 
1314 			func.arg_info = (zend_internal_arg_info*)funcs->arg_info + 1;
1315 			func.num_args = funcs->num_args;
1316 			if (info->required_num_args == -1) {
1317 				func.required_num_args = funcs->num_args;
1318 			} else {
1319 				func.required_num_args = info->required_num_args;
1320 			}
1321 			if (info->return_reference) {
1322 				func.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1323 			}
1324 			if (funcs->arg_info[funcs->num_args].is_variadic) {
1325 				func.fn_flags |= ZEND_ACC_VARIADIC;
1326 				/* Don't count the variadic argument */
1327 				func.num_args--;
1328 			}
1329 		} else {
1330 			func.arg_info = NULL;
1331 			func.num_args = 0;
1332 			func.required_num_args = 0;
1333 		}
1334 		zend_set_function_arg_flags((zend_function*)&func);
1335 		namelen = strlen(funcs->fname);
1336 		lc_name = emalloc(namelen+1);
1337 		zend_str_tolower_copy(lc_name, funcs->fname, namelen);
1338 		zend_hash_str_add_mem(dbh->cls_methods[kind], lc_name, namelen, &func, sizeof(func));
1339 		efree(lc_name);
1340 		funcs++;
1341 	}
1342 
1343 	return 1;
1344 }
1345 
dbh_method_get(zend_object ** object,zend_string * method_name,const zval * key)1346 static union _zend_function *dbh_method_get(zend_object **object, zend_string *method_name, const zval *key)
1347 {
1348 	zend_function *fbc = NULL;
1349 	pdo_dbh_object_t *dbh_obj = php_pdo_dbh_fetch_object(*object);
1350 	zend_string *lc_method_name;
1351 
1352 	lc_method_name = zend_string_init(ZSTR_VAL(method_name), ZSTR_LEN(method_name), 0);
1353 	zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
1354 
1355 	if ((fbc = std_object_handlers.get_method(object, method_name, key)) == NULL) {
1356 		/* not a pre-defined method, nor a user-defined method; check
1357 		 * the driver specific methods */
1358 		if (!dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1359 			if (!pdo_hash_methods(dbh_obj,
1360 				PDO_DBH_DRIVER_METHOD_KIND_DBH)
1361 				|| !dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1362 				goto out;
1363 			}
1364 		}
1365 
1366 		fbc = zend_hash_find_ptr(dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], lc_method_name);
1367 	}
1368 
1369 out:
1370 	zend_string_release(lc_method_name);
1371 	return fbc;
1372 }
1373 
dbh_compare(zval * object1,zval * object2)1374 static int dbh_compare(zval *object1, zval *object2)
1375 {
1376 	return -1;
1377 }
1378 
dbh_get_gc(zval * object,zval ** gc_data,int * gc_count)1379 static HashTable *dbh_get_gc(zval *object, zval **gc_data, int *gc_count)
1380 {
1381 	pdo_dbh_t *dbh = Z_PDO_DBH_P(object);
1382 	*gc_data = &dbh->def_stmt_ctor_args;
1383 	*gc_count = 1;
1384 	return zend_std_get_properties(object);
1385 }
1386 
1387 static zend_object_handlers pdo_dbh_object_handlers;
1388 static void pdo_dbh_free_storage(zend_object *std);
1389 
pdo_dbh_init(void)1390 void pdo_dbh_init(void)
1391 {
1392 	zend_class_entry ce;
1393 
1394 	INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
1395 	pdo_dbh_ce = zend_register_internal_class(&ce);
1396 	pdo_dbh_ce->create_object = pdo_dbh_new;
1397 
1398 	memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1399 	pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std);
1400 	pdo_dbh_object_handlers.dtor_obj = zend_objects_destroy_object;
1401 	pdo_dbh_object_handlers.free_obj = pdo_dbh_free_storage;
1402 	pdo_dbh_object_handlers.get_method = dbh_method_get;
1403 	pdo_dbh_object_handlers.compare_objects = dbh_compare;
1404 	pdo_dbh_object_handlers.get_gc = dbh_get_gc;
1405 
1406 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL", (zend_long)PDO_PARAM_BOOL);
1407 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL", (zend_long)PDO_PARAM_NULL);
1408 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT",  (zend_long)PDO_PARAM_INT);
1409 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR",  (zend_long)PDO_PARAM_STR);
1410 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB",  (zend_long)PDO_PARAM_LOB);
1411 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (zend_long)PDO_PARAM_STMT);
1412 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (zend_long)PDO_PARAM_INPUT_OUTPUT);
1413 
1414 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC",		(zend_long)PDO_PARAM_EVT_ALLOC);
1415 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE",			(zend_long)PDO_PARAM_EVT_FREE);
1416 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_PRE",		(zend_long)PDO_PARAM_EVT_EXEC_PRE);
1417 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_POST",	(zend_long)PDO_PARAM_EVT_EXEC_POST);
1418 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_PRE",	(zend_long)PDO_PARAM_EVT_FETCH_PRE);
1419 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST",	(zend_long)PDO_PARAM_EVT_FETCH_POST);
1420 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE",	(zend_long)PDO_PARAM_EVT_NORMALIZE);
1421 
1422 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (zend_long)PDO_FETCH_LAZY);
1423 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC", (zend_long)PDO_FETCH_ASSOC);
1424 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM",  (zend_long)PDO_FETCH_NUM);
1425 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (zend_long)PDO_FETCH_BOTH);
1426 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ",  (zend_long)PDO_FETCH_OBJ);
1427 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND", (zend_long)PDO_FETCH_BOUND);
1428 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN", (zend_long)PDO_FETCH_COLUMN);
1429 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS", (zend_long)PDO_FETCH_CLASS);
1430 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO", (zend_long)PDO_FETCH_INTO);
1431 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC", (zend_long)PDO_FETCH_FUNC);
1432 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP", (zend_long)PDO_FETCH_GROUP);
1433 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE", (zend_long)PDO_FETCH_UNIQUE);
1434 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_KEY_PAIR", (zend_long)PDO_FETCH_KEY_PAIR);
1435 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE", (zend_long)PDO_FETCH_CLASSTYPE);
1436 
1437 #if PHP_VERSION_ID >= 50100
1438 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE",(zend_long)PDO_FETCH_SERIALIZE);
1439 #endif
1440 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_PROPS_LATE", (zend_long)PDO_FETCH_PROPS_LATE);
1441 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED", (zend_long)PDO_FETCH_NAMED);
1442 
1443 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT",	(zend_long)PDO_ATTR_AUTOCOMMIT);
1444 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH",		(zend_long)PDO_ATTR_PREFETCH);
1445 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT", 		(zend_long)PDO_ATTR_TIMEOUT);
1446 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE", 		(zend_long)PDO_ATTR_ERRMODE);
1447 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION",	(zend_long)PDO_ATTR_SERVER_VERSION);
1448 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION", 	(zend_long)PDO_ATTR_CLIENT_VERSION);
1449 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO",		(zend_long)PDO_ATTR_SERVER_INFO);
1450 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS", 	(zend_long)PDO_ATTR_CONNECTION_STATUS);
1451 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE",		 	(zend_long)PDO_ATTR_CASE);
1452 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME", 	(zend_long)PDO_ATTR_CURSOR_NAME);
1453 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR",	 	(zend_long)PDO_ATTR_CURSOR);
1454 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS",	(zend_long)PDO_ATTR_ORACLE_NULLS);
1455 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT",	(zend_long)PDO_ATTR_PERSISTENT);
1456 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS",		(zend_long)PDO_ATTR_STATEMENT_CLASS);
1457 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES",		(zend_long)PDO_ATTR_FETCH_TABLE_NAMES);
1458 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES",		(zend_long)PDO_ATTR_FETCH_CATALOG_NAMES);
1459 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME",		(zend_long)PDO_ATTR_DRIVER_NAME);
1460 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES", (zend_long)PDO_ATTR_STRINGIFY_FETCHES);
1461 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN", (zend_long)PDO_ATTR_MAX_COLUMN_LEN);
1462 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES", (zend_long)PDO_ATTR_EMULATE_PREPARES);
1463 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE", (zend_long)PDO_ATTR_DEFAULT_FETCH_MODE);
1464 
1465 	REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT",	(zend_long)PDO_ERRMODE_SILENT);
1466 	REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING",	(zend_long)PDO_ERRMODE_WARNING);
1467 	REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION",	(zend_long)PDO_ERRMODE_EXCEPTION);
1468 
1469 	REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL",	(zend_long)PDO_CASE_NATURAL);
1470 	REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER",	(zend_long)PDO_CASE_LOWER);
1471 	REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER",	(zend_long)PDO_CASE_UPPER);
1472 
1473 	REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL",	(zend_long)PDO_NULL_NATURAL);
1474 	REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING",	(zend_long)PDO_NULL_EMPTY_STRING);
1475 	REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING",	(zend_long)PDO_NULL_TO_STRING);
1476 
1477 	REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE",	PDO_ERR_NONE);
1478 
1479 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT", (zend_long)PDO_FETCH_ORI_NEXT);
1480 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR", (zend_long)PDO_FETCH_ORI_PRIOR);
1481 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST", (zend_long)PDO_FETCH_ORI_FIRST);
1482 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST", (zend_long)PDO_FETCH_ORI_LAST);
1483 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS", (zend_long)PDO_FETCH_ORI_ABS);
1484 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL", (zend_long)PDO_FETCH_ORI_REL);
1485 
1486 	REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (zend_long)PDO_CURSOR_FWDONLY);
1487 	REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (zend_long)PDO_CURSOR_SCROLL);
1488 
1489 #if 0
1490 	REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP", 		(zend_long)PDO_ERR_CANT_MAP);
1491 	REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX", 		(zend_long)PDO_ERR_SYNTAX);
1492 	REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT", 	(zend_long)PDO_ERR_CONSTRAINT);
1493 	REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND", 		(zend_long)PDO_ERR_NOT_FOUND);
1494 	REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS", 	(zend_long)PDO_ERR_ALREADY_EXISTS);
1495 	REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED", 	(zend_long)PDO_ERR_NOT_IMPLEMENTED);
1496 	REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH", 		(zend_long)PDO_ERR_MISMATCH);
1497 	REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED", 		(zend_long)PDO_ERR_TRUNCATED);
1498 	REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED", 	(zend_long)PDO_ERR_DISCONNECTED);
1499 	REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM",		(zend_long)PDO_ERR_NO_PERM);
1500 #endif
1501 
1502 }
1503 
dbh_free(pdo_dbh_t * dbh,zend_bool free_persistent)1504 static void dbh_free(pdo_dbh_t *dbh, zend_bool free_persistent)
1505 {
1506 	int i;
1507 
1508 	if (dbh->query_stmt) {
1509 		zval_ptr_dtor(&dbh->query_stmt_zval);
1510 		dbh->query_stmt = NULL;
1511 	}
1512 
1513 	if (dbh->is_persistent) {
1514 #if ZEND_DEBUG
1515 		ZEND_ASSERT(!free_persistent || (dbh->refcount == 1));
1516 #endif
1517 		if (!free_persistent && (--dbh->refcount)) {
1518 			return;
1519 		}
1520 	}
1521 
1522 	if (dbh->methods) {
1523 		dbh->methods->closer(dbh);
1524 	}
1525 
1526 	if (dbh->data_source) {
1527 		pefree((char *)dbh->data_source, dbh->is_persistent);
1528 	}
1529 	if (dbh->username) {
1530 		pefree(dbh->username, dbh->is_persistent);
1531 	}
1532 	if (dbh->password) {
1533 		pefree(dbh->password, dbh->is_persistent);
1534 	}
1535 
1536 	if (dbh->persistent_id) {
1537 		pefree((char *)dbh->persistent_id, dbh->is_persistent);
1538 	}
1539 
1540 	if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
1541 		zval_ptr_dtor(&dbh->def_stmt_ctor_args);
1542 	}
1543 
1544 	for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) {
1545 		if (dbh->cls_methods[i]) {
1546 			zend_hash_destroy(dbh->cls_methods[i]);
1547 			pefree(dbh->cls_methods[i], dbh->is_persistent);
1548 		}
1549 	}
1550 
1551 	pefree(dbh, dbh->is_persistent);
1552 }
1553 
pdo_dbh_free_storage(zend_object * std)1554 static void pdo_dbh_free_storage(zend_object *std)
1555 {
1556 	pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(std);
1557 	if (dbh->in_txn && dbh->methods && dbh->methods->rollback) {
1558 		dbh->methods->rollback(dbh);
1559 		dbh->in_txn = 0;
1560 	}
1561 
1562 	if (dbh->is_persistent && dbh->methods && dbh->methods->persistent_shutdown) {
1563 		dbh->methods->persistent_shutdown(dbh);
1564 	}
1565 	zend_object_std_dtor(std);
1566 	dbh_free(dbh, 0);
1567 }
1568 
pdo_dbh_new(zend_class_entry * ce)1569 zend_object *pdo_dbh_new(zend_class_entry *ce)
1570 {
1571 	pdo_dbh_object_t *dbh;
1572 
1573 	dbh = ecalloc(1, sizeof(pdo_dbh_object_t) + zend_object_properties_size(ce));
1574 	zend_object_std_init(&dbh->std, ce);
1575 	object_properties_init(&dbh->std, ce);
1576 	rebuild_object_properties(&dbh->std);
1577 	dbh->inner = ecalloc(1, sizeof(pdo_dbh_t));
1578 	dbh->inner->def_stmt_ce = pdo_dbstmt_ce;
1579 
1580 	dbh->std.handlers = &pdo_dbh_object_handlers;
1581 
1582 	return &dbh->std;
1583 }
1584 
1585 /* }}} */
1586 
ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor)1587 ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor) /* {{{ */
1588 {
1589 	if (res->ptr) {
1590 		pdo_dbh_t *dbh = (pdo_dbh_t*)res->ptr;
1591 		dbh_free(dbh, 1);
1592 		res->ptr = NULL;
1593 	}
1594 }
1595 /* }}} */
1596 
1597 /*
1598  * Local variables:
1599  * tab-width: 4
1600  * c-basic-offset: 4
1601  * End:
1602  * vim600: noet sw=4 ts=4 fdm=marker
1603  * vim<600: noet sw=4 ts=4
1604  */
1605