xref: /PHP-7.1/ext/pdo/pdo_dbh.c (revision ccd4716e)
1 /*
2   +----------------------------------------------------------------------+
3   | PHP Version 7                                                        |
4   +----------------------------------------------------------------------+
5   | Copyright (c) 1997-2018 The PHP Group                                |
6   +----------------------------------------------------------------------+
7   | This source file is subject to version 3.01 of the PHP license,      |
8   | that is bundled with this package in the file LICENSE, and is        |
9   | available through the world-wide-web at the following url:           |
10   | http://www.php.net/license/3_01.txt                                  |
11   | If you did not receive a copy of the PHP license and are unable to   |
12   | obtain it through the world-wide-web, please send a note to          |
13   | license@php.net so we can mail you a copy immediately.               |
14   +----------------------------------------------------------------------+
15   | Author: Wez Furlong <wez@php.net>                                    |
16   |         Marcus Boerger <helly@php.net>                               |
17   |         Sterling Hughes <sterling@php.net>                           |
18   +----------------------------------------------------------------------+
19 */
20 
21 /* $Id$ */
22 
23 /* The PDO 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: " ZEND_LONG_FMT " %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 		ZVAL_UNDEF(&fci.function_name);
442 		fci.object = Z_OBJ_P(object);
443 		fci.retval = &retval;
444 		fci.param_count = 0;
445 		fci.params = NULL;
446 		fci.no_separation = 1;
447 
448 		zend_fcall_info_args(&fci, ctor_args);
449 
450 		fcc.initialized = 1;
451 		fcc.function_handler = dbstmt_ce->constructor;
452 		fcc.calling_scope = zend_get_executed_scope();
453 		fcc.called_scope = Z_OBJCE_P(object);
454 		fcc.object = Z_OBJ_P(object);
455 
456 		if (zend_call_function(&fci, &fcc) != FAILURE) {
457 			zval_ptr_dtor(&retval);
458 		}
459 
460 		zend_fcall_info_args_clear(&fci, 1);
461 	}
462 }
463 /* }}} */
464 
465 /* {{{ proto object PDO::prepare(string statement [, array options])
466    Prepares a statement for execution and returns a statement object */
PHP_METHOD(PDO,prepare)467 static PHP_METHOD(PDO, prepare)
468 {
469 	pdo_stmt_t *stmt;
470 	char *statement;
471 	size_t statement_len;
472 	zval *options = NULL, *opt, *item, ctor_args;
473 	zend_class_entry *dbstmt_ce, *pce;
474 	pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis());
475 	pdo_dbh_t *dbh = dbh_obj->inner;
476 
477 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|a", &statement,
478 			&statement_len, &options)) {
479 		RETURN_FALSE;
480 	}
481 
482 	PDO_DBH_CLEAR_ERR();
483 	PDO_CONSTRUCT_CHECK;
484 
485 	if (ZEND_NUM_ARGS() > 1 && (opt = zend_hash_index_find(Z_ARRVAL_P(options), PDO_ATTR_STATEMENT_CLASS)) != NULL) {
486 		if (Z_TYPE_P(opt) != IS_ARRAY || (item = zend_hash_index_find(Z_ARRVAL_P(opt), 0)) == NULL
487 			|| Z_TYPE_P(item) != IS_STRING
488 			|| (pce = zend_lookup_class(Z_STR_P(item))) == NULL
489 		) {
490 			pdo_raise_impl_error(dbh, NULL, "HY000",
491 				"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
492 				"the classname must be a string specifying an existing class"
493 				);
494 			PDO_HANDLE_DBH_ERR();
495 			RETURN_FALSE;
496 		}
497 		dbstmt_ce = pce;
498 		if (!instanceof_function(dbstmt_ce, pdo_dbstmt_ce)) {
499 			pdo_raise_impl_error(dbh, NULL, "HY000",
500 				"user-supplied statement class must be derived from PDOStatement");
501 			PDO_HANDLE_DBH_ERR();
502 			RETURN_FALSE;
503 		}
504 		if (dbstmt_ce->constructor && !(dbstmt_ce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
505 			pdo_raise_impl_error(dbh, NULL, "HY000",
506 				"user-supplied statement class cannot have a public constructor");
507 			PDO_HANDLE_DBH_ERR();
508 			RETURN_FALSE;
509 		}
510 		if ((item = zend_hash_index_find(Z_ARRVAL_P(opt), 1)) != NULL) {
511 			if (Z_TYPE_P(item) != IS_ARRAY) {
512 				pdo_raise_impl_error(dbh, NULL, "HY000",
513 					"PDO::ATTR_STATEMENT_CLASS requires format array(classname, ctor_args); "
514 					"ctor_args must be an array"
515 				);
516 				PDO_HANDLE_DBH_ERR();
517 				RETURN_FALSE;
518 			}
519 			ZVAL_COPY_VALUE(&ctor_args, item);
520 		} else {
521 			ZVAL_UNDEF(&ctor_args);
522 		}
523 	} else {
524 		dbstmt_ce = dbh->def_stmt_ce;
525 		ZVAL_COPY_VALUE(&ctor_args, &dbh->def_stmt_ctor_args);
526 	}
527 
528 	if (!pdo_stmt_instantiate(dbh, return_value, dbstmt_ce, &ctor_args)) {
529 		if (EXPECTED(!EG(exception))) {
530 			pdo_raise_impl_error(dbh, NULL, "HY000",
531 				"failed to instantiate user-supplied statement class"
532 				);
533 		}
534 		PDO_HANDLE_DBH_ERR();
535 		RETURN_FALSE;
536 	}
537 	stmt = Z_PDO_STMT_P(return_value);
538 
539 	/* unconditionally keep this for later reference */
540 	stmt->query_string = estrndup(statement, statement_len);
541 	stmt->query_stringlen = statement_len;
542 	stmt->default_fetch_type = dbh->default_fetch_type;
543 	stmt->dbh = dbh;
544 	/* give it a reference to me */
545 	ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std);
546 	Z_ADDREF(stmt->database_object_handle);
547 	/* we haven't created a lazy object yet */
548 	ZVAL_UNDEF(&stmt->lazy_object_ref);
549 
550 	if (dbh->methods->preparer(dbh, statement, statement_len, stmt, options)) {
551 		pdo_stmt_construct(execute_data, stmt, return_value, dbstmt_ce, &ctor_args);
552 		return;
553 	}
554 
555 	PDO_HANDLE_DBH_ERR();
556 
557 	/* kill the object handle for the stmt here */
558 	zval_dtor(return_value);
559 
560 	RETURN_FALSE;
561 }
562 /* }}} */
563 
564 /* {{{ proto bool PDO::beginTransaction()
565    Initiates a transaction */
PHP_METHOD(PDO,beginTransaction)566 static PHP_METHOD(PDO, beginTransaction)
567 {
568 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
569 
570 	if (zend_parse_parameters_none() == FAILURE) {
571 		return;
572 	}
573 	PDO_CONSTRUCT_CHECK;
574 
575 	if (dbh->in_txn) {
576 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is already an active transaction");
577 		RETURN_FALSE;
578 	}
579 
580 	if (!dbh->methods->begin) {
581 		/* TODO: this should be an exception; see the auto-commit mode
582 		 * comments below */
583 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "This driver doesn't support transactions");
584 		RETURN_FALSE;
585 	}
586 
587 	if (dbh->methods->begin(dbh)) {
588 		dbh->in_txn = 1;
589 		RETURN_TRUE;
590 	}
591 
592 	PDO_HANDLE_DBH_ERR();
593 	RETURN_FALSE;
594 }
595 /* }}} */
596 
597 /* {{{ proto bool PDO::commit()
598    Commit a transaction */
PHP_METHOD(PDO,commit)599 static PHP_METHOD(PDO, commit)
600 {
601 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
602 
603 	if (zend_parse_parameters_none() == FAILURE) {
604 		return;
605 	}
606 	PDO_CONSTRUCT_CHECK;
607 
608 	if (!dbh->in_txn) {
609 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
610 		RETURN_FALSE;
611 	}
612 
613 	if (dbh->methods->commit(dbh)) {
614 		dbh->in_txn = 0;
615 		RETURN_TRUE;
616 	}
617 
618 	PDO_HANDLE_DBH_ERR();
619 	RETURN_FALSE;
620 }
621 /* }}} */
622 
623 /* {{{ proto bool PDO::rollBack()
624    roll back a transaction */
PHP_METHOD(PDO,rollBack)625 static PHP_METHOD(PDO, rollBack)
626 {
627 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
628 
629 	if (zend_parse_parameters_none() == FAILURE) {
630 		return;
631 	}
632 	PDO_CONSTRUCT_CHECK;
633 
634 	if (!dbh->in_txn) {
635 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "There is no active transaction");
636 		RETURN_FALSE;
637 	}
638 
639 	if (dbh->methods->rollback(dbh)) {
640 		dbh->in_txn = 0;
641 		RETURN_TRUE;
642 	}
643 
644 	PDO_HANDLE_DBH_ERR();
645 	RETURN_FALSE;
646 }
647 /* }}} */
648 
649 /* {{{ proto bool PDO::inTransaction()
650    determine if inside a transaction */
PHP_METHOD(PDO,inTransaction)651 static PHP_METHOD(PDO, inTransaction)
652 {
653 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
654 
655 	if (zend_parse_parameters_none() == FAILURE) {
656 		return;
657 	}
658 	PDO_CONSTRUCT_CHECK;
659 
660 	if (!dbh->methods->in_transaction) {
661 		RETURN_BOOL(dbh->in_txn);
662 	}
663 
664 	RETURN_BOOL(dbh->methods->in_transaction(dbh));
665 }
666 /* }}} */
667 
pdo_dbh_attribute_set(pdo_dbh_t * dbh,zend_long attr,zval * value)668 static int pdo_dbh_attribute_set(pdo_dbh_t *dbh, zend_long attr, zval *value) /* {{{ */
669 {
670 	zend_long lval;
671 
672 #define PDO_LONG_PARAM_CHECK \
673 	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) { \
674 		pdo_raise_impl_error(dbh, NULL, "HY000", "attribute value must be an integer"); \
675 		PDO_HANDLE_DBH_ERR(); \
676 		return FAILURE; \
677 	} \
678 
679 	switch (attr) {
680 		case PDO_ATTR_ERRMODE:
681 			PDO_LONG_PARAM_CHECK;
682 			lval = zval_get_long(value);
683 			switch (lval) {
684 				case PDO_ERRMODE_SILENT:
685 				case PDO_ERRMODE_WARNING:
686 				case PDO_ERRMODE_EXCEPTION:
687 					dbh->error_mode = lval;
688 					return SUCCESS;
689 				default:
690 					pdo_raise_impl_error(dbh, NULL, "HY000", "invalid error mode");
691 					PDO_HANDLE_DBH_ERR();
692 					return FAILURE;
693 			}
694 			return FAILURE;
695 
696 		case PDO_ATTR_CASE:
697 			PDO_LONG_PARAM_CHECK;
698 			lval = zval_get_long(value);
699 			switch (lval) {
700 				case PDO_CASE_NATURAL:
701 				case PDO_CASE_UPPER:
702 				case PDO_CASE_LOWER:
703 					dbh->desired_case = lval;
704 					return SUCCESS;
705 				default:
706 					pdo_raise_impl_error(dbh, NULL, "HY000", "invalid case folding mode");
707 					PDO_HANDLE_DBH_ERR();
708 					return FAILURE;
709 			}
710 			return FAILURE;
711 
712 		case PDO_ATTR_ORACLE_NULLS:
713 			PDO_LONG_PARAM_CHECK;
714 			dbh->oracle_nulls = zval_get_long(value);
715 			return SUCCESS;
716 
717 		case PDO_ATTR_DEFAULT_FETCH_MODE:
718 			if (Z_TYPE_P(value) == IS_ARRAY) {
719 				zval *tmp;
720 				if ((tmp = zend_hash_index_find(Z_ARRVAL_P(value), 0)) != NULL && Z_TYPE_P(tmp) == IS_LONG) {
721 					if (Z_LVAL_P(tmp) == PDO_FETCH_INTO || Z_LVAL_P(tmp) == PDO_FETCH_CLASS) {
722 						pdo_raise_impl_error(dbh, NULL, "HY000", "FETCH_INTO and FETCH_CLASS are not yet supported as default fetch modes");
723 						return FAILURE;
724 					}
725 				}
726 			} else {
727 				PDO_LONG_PARAM_CHECK;
728 			}
729 			lval = zval_get_long(value);
730 			if (lval == PDO_FETCH_USE_DEFAULT) {
731 				pdo_raise_impl_error(dbh, NULL, "HY000", "invalid fetch mode type");
732 				return FAILURE;
733 			}
734 			dbh->default_fetch_type = lval;
735 			return SUCCESS;
736 
737 		case PDO_ATTR_STRINGIFY_FETCHES:
738 			PDO_LONG_PARAM_CHECK;
739 			dbh->stringify = zval_get_long(value) ? 1 : 0;
740 			return SUCCESS;
741 
742 		case PDO_ATTR_STATEMENT_CLASS: {
743 			/* array(string classname, array(mixed ctor_args)) */
744 			zend_class_entry *pce;
745 			zval *item;
746 
747 			if (dbh->is_persistent) {
748 				pdo_raise_impl_error(dbh, NULL, "HY000",
749 					"PDO::ATTR_STATEMENT_CLASS cannot be used with persistent PDO instances"
750 					);
751 				PDO_HANDLE_DBH_ERR();
752 				return FAILURE;
753 			}
754 			if (Z_TYPE_P(value) != IS_ARRAY
755 				|| (item = zend_hash_index_find(Z_ARRVAL_P(value), 0)) == NULL
756 				|| Z_TYPE_P(item) != IS_STRING
757 				|| (pce = zend_lookup_class(Z_STR_P(item))) == NULL
758 			) {
759 				pdo_raise_impl_error(dbh, NULL, "HY000",
760 					"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
761 					"the classname must be a string specifying an existing class"
762 					);
763 				PDO_HANDLE_DBH_ERR();
764 				return FAILURE;
765 			}
766 			if (!instanceof_function(pce, pdo_dbstmt_ce)) {
767 				pdo_raise_impl_error(dbh, NULL, "HY000",
768 					"user-supplied statement class must be derived from PDOStatement");
769 				PDO_HANDLE_DBH_ERR();
770 				return FAILURE;
771 			}
772 			if (pce->constructor && !(pce->constructor->common.fn_flags & (ZEND_ACC_PRIVATE|ZEND_ACC_PROTECTED))) {
773 				pdo_raise_impl_error(dbh, NULL, "HY000",
774 					"user-supplied statement class cannot have a public constructor");
775 				PDO_HANDLE_DBH_ERR();
776 				return FAILURE;
777 			}
778 			dbh->def_stmt_ce = pce;
779 			if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
780 				zval_ptr_dtor(&dbh->def_stmt_ctor_args);
781 				ZVAL_UNDEF(&dbh->def_stmt_ctor_args);
782 			}
783 			if ((item = zend_hash_index_find(Z_ARRVAL_P(value), 1)) != NULL) {
784 				if (Z_TYPE_P(item) != IS_ARRAY) {
785 					pdo_raise_impl_error(dbh, NULL, "HY000",
786 						"PDO::ATTR_STATEMENT_CLASS requires format array(classname, array(ctor_args)); "
787 						"ctor_args must be an array"
788 					);
789 					PDO_HANDLE_DBH_ERR();
790 					return FAILURE;
791 				}
792 				ZVAL_COPY(&dbh->def_stmt_ctor_args, item);
793 			}
794 			return SUCCESS;
795 		}
796 
797 		default:
798 			;
799 	}
800 
801 	if (!dbh->methods->set_attribute) {
802 		goto fail;
803 	}
804 
805 	PDO_DBH_CLEAR_ERR();
806 	if (dbh->methods->set_attribute(dbh, attr, value)) {
807 		return SUCCESS;
808 	}
809 
810 fail:
811 	if (attr == PDO_ATTR_AUTOCOMMIT) {
812 		zend_throw_exception_ex(php_pdo_get_exception(), 0, "The auto-commit mode cannot be changed for this driver");
813 	} else if (!dbh->methods->set_attribute) {
814 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support setting attributes");
815 	} else {
816 		PDO_HANDLE_DBH_ERR();
817 	}
818 	return FAILURE;
819 }
820 /* }}} */
821 
822 /* {{{ proto bool PDO::setAttribute(long attribute, mixed value)
823    Set an attribute */
PHP_METHOD(PDO,setAttribute)824 static PHP_METHOD(PDO, setAttribute)
825 {
826 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
827 	zend_long attr;
828 	zval *value;
829 
830 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "lz", &attr, &value)) {
831 		RETURN_FALSE;
832 	}
833 
834 	PDO_DBH_CLEAR_ERR();
835 	PDO_CONSTRUCT_CHECK;
836 
837 	if (pdo_dbh_attribute_set(dbh, attr, value) != FAILURE) {
838  		RETURN_TRUE;
839  	}
840  	RETURN_FALSE;
841 }
842 /* }}} */
843 
844 /* {{{ proto mixed PDO::getAttribute(long attribute)
845    Get an attribute */
PHP_METHOD(PDO,getAttribute)846 static PHP_METHOD(PDO, getAttribute)
847 {
848 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
849 	zend_long attr;
850 
851 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "l", &attr)) {
852 		RETURN_FALSE;
853 	}
854 
855 	PDO_DBH_CLEAR_ERR();
856 	PDO_CONSTRUCT_CHECK;
857 
858 	/* handle generic PDO-level attributes */
859 	switch (attr) {
860 		case PDO_ATTR_PERSISTENT:
861 			RETURN_BOOL(dbh->is_persistent);
862 
863 		case PDO_ATTR_CASE:
864 			RETURN_LONG(dbh->desired_case);
865 
866 		case PDO_ATTR_ORACLE_NULLS:
867 			RETURN_LONG(dbh->oracle_nulls);
868 
869 		case PDO_ATTR_ERRMODE:
870 			RETURN_LONG(dbh->error_mode);
871 
872 		case PDO_ATTR_DRIVER_NAME:
873 			RETURN_STRINGL((char*)dbh->driver->driver_name, dbh->driver->driver_name_len);
874 
875 		case PDO_ATTR_STATEMENT_CLASS:
876 			array_init(return_value);
877 			add_next_index_str(return_value, zend_string_copy(dbh->def_stmt_ce->name));
878 			if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
879 				if (Z_REFCOUNTED(dbh->def_stmt_ctor_args)) Z_ADDREF(dbh->def_stmt_ctor_args);
880 				add_next_index_zval(return_value, &dbh->def_stmt_ctor_args);
881 			}
882 			return;
883 		case PDO_ATTR_DEFAULT_FETCH_MODE:
884 			RETURN_LONG(dbh->default_fetch_type);
885 		default:
886 			break;
887 	}
888 
889 	if (!dbh->methods->get_attribute) {
890 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support getting attributes");
891 		RETURN_FALSE;
892 	}
893 
894 	switch (dbh->methods->get_attribute(dbh, attr, return_value)) {
895 		case -1:
896 			PDO_HANDLE_DBH_ERR();
897 			RETURN_FALSE;
898 
899 		case 0:
900 			pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support that attribute");
901 			RETURN_FALSE;
902 
903 		default:
904 			return;
905 	}
906 }
907 /* }}} */
908 
909 /* {{{ proto long PDO::exec(string query)
910    Execute a query that does not return a row set, returning the number of affected rows */
PHP_METHOD(PDO,exec)911 static PHP_METHOD(PDO, exec)
912 {
913 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
914 	char *statement;
915 	size_t statement_len;
916 	zend_long ret;
917 
918 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s", &statement, &statement_len)) {
919 		RETURN_FALSE;
920 	}
921 
922 	if (!statement_len) {
923 		pdo_raise_impl_error(dbh, NULL, "HY000",  "trying to execute an empty query");
924 		RETURN_FALSE;
925 	}
926 	PDO_DBH_CLEAR_ERR();
927 	PDO_CONSTRUCT_CHECK;
928 	ret = dbh->methods->doer(dbh, statement, statement_len);
929 	if(ret == -1) {
930 		PDO_HANDLE_DBH_ERR();
931 		RETURN_FALSE;
932 	} else {
933 		RETURN_LONG(ret);
934 	}
935 }
936 /* }}} */
937 
938 /* {{{ proto string PDO::lastInsertId([string seqname])
939    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)940 static PHP_METHOD(PDO, lastInsertId)
941 {
942 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
943 	char *name = NULL;
944 	size_t namelen;
945 
946 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|s!", &name, &namelen)) {
947 		RETURN_FALSE;
948 	}
949 
950 	PDO_DBH_CLEAR_ERR();
951 	PDO_CONSTRUCT_CHECK;
952 	if (!dbh->methods->last_id) {
953 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support lastInsertId()");
954 		RETURN_FALSE;
955 	} else {
956 		size_t id_len;
957 		char *id;
958 		id = dbh->methods->last_id(dbh, name, &id_len);
959 		if (!id) {
960 			PDO_HANDLE_DBH_ERR();
961 			RETURN_FALSE;
962 		} else {
963 			//??? use zend_string ?
964 			RETVAL_STRINGL(id, id_len);
965 			efree(id);
966 		}
967 	}
968 }
969 /* }}} */
970 
971 /* {{{ proto string PDO::errorCode()
972    Fetch the error code associated with the last operation on the database handle */
PHP_METHOD(PDO,errorCode)973 static PHP_METHOD(PDO, errorCode)
974 {
975 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
976 
977 	if (zend_parse_parameters_none() == FAILURE) {
978 		return;
979 	}
980 	PDO_CONSTRUCT_CHECK;
981 
982 	if (dbh->query_stmt) {
983 		RETURN_STRING(dbh->query_stmt->error_code);
984 	}
985 
986 	if (dbh->error_code[0] == '\0') {
987 		RETURN_NULL();
988 	}
989 
990 	/**
991 	 * Making sure that we fallback to the default implementation
992 	 * if the dbh->error_code is not null.
993 	 */
994 	RETURN_STRING(dbh->error_code);
995 }
996 /* }}} */
997 
998 /* {{{ proto int PDO::errorInfo()
999    Fetch extended error information associated with the last operation on the database handle */
PHP_METHOD(PDO,errorInfo)1000 static PHP_METHOD(PDO, errorInfo)
1001 {
1002 	int error_count;
1003 	int error_count_diff 	 = 0;
1004 	int error_expected_count = 3;
1005 
1006 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
1007 
1008 	if (zend_parse_parameters_none() == FAILURE) {
1009 		return;
1010 	}
1011 
1012 	PDO_CONSTRUCT_CHECK;
1013 
1014 	array_init(return_value);
1015 
1016 	if (dbh->query_stmt) {
1017 		add_next_index_string(return_value, dbh->query_stmt->error_code);
1018 		if(!strncmp(dbh->query_stmt->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE))) goto fill_array;
1019 	} else {
1020 		add_next_index_string(return_value, dbh->error_code);
1021 		if(!strncmp(dbh->error_code, PDO_ERR_NONE, sizeof(PDO_ERR_NONE))) goto fill_array;
1022 	}
1023 
1024 	if (dbh->methods->fetch_err) {
1025 		dbh->methods->fetch_err(dbh, dbh->query_stmt, return_value);
1026 	}
1027 
1028 fill_array:
1029 	/**
1030 	 * In order to be consistent, we have to make sure we add the good amount
1031 	 * of nulls depending on the current number of elements. We make a simple
1032 	 * difference and add the needed elements
1033 	 */
1034 	error_count = zend_hash_num_elements(Z_ARRVAL_P(return_value));
1035 
1036 	if (error_expected_count > error_count) {
1037 		int current_index;
1038 
1039 		error_count_diff = error_expected_count - error_count;
1040 		for (current_index = 0; current_index < error_count_diff; current_index++) {
1041 			add_next_index_null(return_value);
1042 		}
1043 	}
1044 }
1045 /* }}} */
1046 
1047 /* {{{ proto object PDO::query(string sql [, PDOStatement::setFetchMode() args])
1048    Prepare and execute $sql; returns the statement object for iteration */
PHP_METHOD(PDO,query)1049 static PHP_METHOD(PDO, query)
1050 {
1051 	pdo_stmt_t *stmt;
1052 	char *statement;
1053 	size_t statement_len;
1054 	pdo_dbh_object_t *dbh_obj = Z_PDO_OBJECT_P(getThis());
1055 	pdo_dbh_t *dbh = dbh_obj->inner;
1056 
1057 	/* Return a meaningful error when no parameters were passed */
1058 	if (!ZEND_NUM_ARGS()) {
1059 		zend_parse_parameters(0, "z|z", NULL, NULL);
1060 		RETURN_FALSE;
1061 	}
1062 
1063 	if (FAILURE == zend_parse_parameters(1, "s", &statement,
1064 			&statement_len)) {
1065 		RETURN_FALSE;
1066 	}
1067 
1068 	PDO_DBH_CLEAR_ERR();
1069 	PDO_CONSTRUCT_CHECK;
1070 
1071 	if (!pdo_stmt_instantiate(dbh, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args)) {
1072 		if (EXPECTED(!EG(exception))) {
1073 			pdo_raise_impl_error(dbh, NULL, "HY000", "failed to instantiate user supplied statement class");
1074 		}
1075 		return;
1076 	}
1077 	stmt = Z_PDO_STMT_P(return_value);
1078 
1079 	/* unconditionally keep this for later reference */
1080 	stmt->query_string = estrndup(statement, statement_len);
1081 	stmt->query_stringlen = statement_len;
1082 
1083 	stmt->default_fetch_type = dbh->default_fetch_type;
1084 	stmt->active_query_string = stmt->query_string;
1085 	stmt->active_query_stringlen = statement_len;
1086 	stmt->dbh = dbh;
1087 	/* give it a reference to me */
1088 	ZVAL_OBJ(&stmt->database_object_handle, &dbh_obj->std);
1089 	Z_ADDREF(stmt->database_object_handle);
1090 	/* we haven't created a lazy object yet */
1091 	ZVAL_UNDEF(&stmt->lazy_object_ref);
1092 
1093 	if (dbh->methods->preparer(dbh, statement, statement_len, stmt, NULL)) {
1094 		PDO_STMT_CLEAR_ERR();
1095 		if (ZEND_NUM_ARGS() == 1 || SUCCESS == pdo_stmt_setup_fetch_mode(INTERNAL_FUNCTION_PARAM_PASSTHRU, stmt, 1)) {
1096 
1097 			/* now execute the statement */
1098 			PDO_STMT_CLEAR_ERR();
1099 			if (stmt->methods->executer(stmt)) {
1100 				int ret = 1;
1101 				if (!stmt->executed) {
1102 					if (stmt->dbh->alloc_own_columns) {
1103 						ret = pdo_stmt_describe_columns(stmt);
1104 					}
1105 					stmt->executed = 1;
1106 				}
1107 				if (ret) {
1108 					pdo_stmt_construct(execute_data, stmt, return_value, dbh->def_stmt_ce, &dbh->def_stmt_ctor_args);
1109 					return;
1110 				}
1111 			}
1112 		}
1113 		/* something broke */
1114 		dbh->query_stmt = stmt;
1115 		ZVAL_COPY_VALUE(&dbh->query_stmt_zval, return_value);
1116 		Z_DELREF(stmt->database_object_handle);
1117 		ZVAL_UNDEF(&stmt->database_object_handle);
1118 		PDO_HANDLE_STMT_ERR();
1119 	} else {
1120 		PDO_HANDLE_DBH_ERR();
1121 		zval_ptr_dtor(return_value);
1122 	}
1123 
1124 	RETURN_FALSE;
1125 }
1126 /* }}} */
1127 
1128 /* {{{ proto string PDO::quote(string string [, int paramtype])
1129    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)1130 static PHP_METHOD(PDO, quote)
1131 {
1132 	pdo_dbh_t *dbh = Z_PDO_DBH_P(getThis());
1133 	char *str;
1134 	size_t str_len;
1135 	zend_long paramtype = PDO_PARAM_STR;
1136 	char *qstr;
1137 	size_t qlen;
1138 
1139 	if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "s|l", &str, &str_len, &paramtype)) {
1140 		RETURN_FALSE;
1141 	}
1142 
1143 	PDO_DBH_CLEAR_ERR();
1144 	PDO_CONSTRUCT_CHECK;
1145 	if (!dbh->methods->quoter) {
1146 		pdo_raise_impl_error(dbh, NULL, "IM001", "driver does not support quoting");
1147 		RETURN_FALSE;
1148 	}
1149 
1150 	if (dbh->methods->quoter(dbh, str, str_len, &qstr, &qlen, paramtype)) {
1151 		RETVAL_STRINGL(qstr, qlen);
1152 		efree(qstr);
1153 		return;
1154 	}
1155 	PDO_HANDLE_DBH_ERR();
1156 	RETURN_FALSE;
1157 }
1158 /* }}} */
1159 
1160 /* {{{ proto int PDO::__wakeup()
1161    Prevents use of a PDO instance that has been unserialized */
PHP_METHOD(PDO,__wakeup)1162 static PHP_METHOD(PDO, __wakeup)
1163 {
1164 	zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDO instances");
1165 }
1166 /* }}} */
1167 
1168 /* {{{ proto int PDO::__sleep()
1169    Prevents serialization of a PDO instance */
PHP_METHOD(PDO,__sleep)1170 static PHP_METHOD(PDO, __sleep)
1171 {
1172 	zend_throw_exception_ex(php_pdo_get_exception(), 0, "You cannot serialize or unserialize PDO instances");
1173 }
1174 /* }}} */
1175 
1176 /* {{{ proto array PDO::getAvailableDrivers()
1177    Return array of available PDO drivers */
PHP_METHOD(PDO,getAvailableDrivers)1178 static PHP_METHOD(PDO, getAvailableDrivers)
1179 {
1180 	pdo_driver_t *pdriver;
1181 
1182 	if (zend_parse_parameters_none() == FAILURE) {
1183 		return;
1184 	}
1185 
1186 	array_init(return_value);
1187 
1188 	ZEND_HASH_FOREACH_PTR(&pdo_driver_hash, pdriver) {
1189 		add_next_index_stringl(return_value, (char*)pdriver->driver_name, pdriver->driver_name_len);
1190 	} ZEND_HASH_FOREACH_END();
1191 }
1192 /* }}} */
1193 
1194 /* {{{ arginfo */
1195 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo___construct, 0, 0, 1)
1196 	ZEND_ARG_INFO(0, dsn)
1197 	ZEND_ARG_INFO(0, username)
1198 	ZEND_ARG_INFO(0, passwd)
1199 	ZEND_ARG_INFO(0, options) /* array */
1200 ZEND_END_ARG_INFO()
1201 
1202 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_prepare, 0, 0, 1)
1203 	ZEND_ARG_INFO(0, statement)
1204 	ZEND_ARG_INFO(0, options) /* array */
1205 ZEND_END_ARG_INFO()
1206 
1207 ZEND_BEGIN_ARG_INFO(arginfo_pdo_setattribute, 0)
1208 	ZEND_ARG_INFO(0, attribute)
1209 	ZEND_ARG_INFO(0, value)
1210 ZEND_END_ARG_INFO()
1211 
1212 ZEND_BEGIN_ARG_INFO(arginfo_pdo_getattribute, 0)
1213 	ZEND_ARG_INFO(0, attribute)
1214 ZEND_END_ARG_INFO()
1215 
1216 ZEND_BEGIN_ARG_INFO(arginfo_pdo_exec, 0)
1217 	ZEND_ARG_INFO(0, query)
1218 ZEND_END_ARG_INFO()
1219 
1220 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_lastinsertid, 0, 0, 0)
1221 	ZEND_ARG_INFO(0, seqname)
1222 ZEND_END_ARG_INFO()
1223 
1224 ZEND_BEGIN_ARG_INFO_EX(arginfo_pdo_quote, 0, 0, 1)
1225 	ZEND_ARG_INFO(0, string)
1226 	ZEND_ARG_INFO(0, paramtype)
1227 ZEND_END_ARG_INFO()
1228 
1229 ZEND_BEGIN_ARG_INFO(arginfo_pdo__void, 0)
1230 ZEND_END_ARG_INFO()
1231 /* }}} */
1232 
1233 const zend_function_entry pdo_dbh_functions[] = /* {{{ */ {
1234 	ZEND_MALIAS(PDO, __construct, dbh_constructor,	arginfo_pdo___construct,	ZEND_ACC_PUBLIC)
1235 	PHP_ME(PDO, prepare, 				arginfo_pdo_prepare,		ZEND_ACC_PUBLIC)
1236 	PHP_ME(PDO, beginTransaction,       arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1237 	PHP_ME(PDO, commit,                 arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1238 	PHP_ME(PDO, rollBack,               arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1239 	PHP_ME(PDO, inTransaction,          arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1240 	PHP_ME(PDO, setAttribute,	arginfo_pdo_setattribute,	ZEND_ACC_PUBLIC)
1241 	PHP_ME(PDO, exec,			arginfo_pdo_exec,		ZEND_ACC_PUBLIC)
1242 	PHP_ME(PDO, query,			NULL,					ZEND_ACC_PUBLIC)
1243 	PHP_ME(PDO, lastInsertId,	arginfo_pdo_lastinsertid,	ZEND_ACC_PUBLIC)
1244 	PHP_ME(PDO, errorCode,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1245 	PHP_ME(PDO, errorInfo,              arginfo_pdo__void,         ZEND_ACC_PUBLIC)
1246 	PHP_ME(PDO, getAttribute,	arginfo_pdo_getattribute,	ZEND_ACC_PUBLIC)
1247 	PHP_ME(PDO, quote,			arginfo_pdo_quote,		ZEND_ACC_PUBLIC)
1248 	PHP_ME(PDO, __wakeup,               arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1249 	PHP_ME(PDO, __sleep,                arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_FINAL)
1250 	PHP_ME(PDO, getAvailableDrivers,    arginfo_pdo__void,         ZEND_ACC_PUBLIC|ZEND_ACC_STATIC)
1251 	PHP_FE_END
1252 };
1253 /* }}} */
1254 
cls_method_dtor(zval * el)1255 static void cls_method_dtor(zval *el) /* {{{ */ {
1256 	zend_function *func = (zend_function*)Z_PTR_P(el);
1257 	if (func->common.function_name) {
1258 		zend_string_release(func->common.function_name);
1259 	}
1260 	efree(func);
1261 }
1262 /* }}} */
1263 
cls_method_pdtor(zval * el)1264 static void cls_method_pdtor(zval *el) /* {{{ */ {
1265 	zend_function *func = (zend_function*)Z_PTR_P(el);
1266 	if (func->common.function_name) {
1267 		zend_string_release(func->common.function_name);
1268 	}
1269 	pefree(func, 1);
1270 }
1271 /* }}} */
1272 
1273 /* {{{ overloaded object handlers for PDO class */
pdo_hash_methods(pdo_dbh_object_t * dbh_obj,int kind)1274 int pdo_hash_methods(pdo_dbh_object_t *dbh_obj, int kind)
1275 {
1276 	const zend_function_entry *funcs;
1277 	zend_internal_function func;
1278 	size_t namelen;
1279 	char *lc_name;
1280 	pdo_dbh_t *dbh = dbh_obj->inner;
1281 
1282 	if (!dbh || !dbh->methods || !dbh->methods->get_driver_methods) {
1283 		return 0;
1284 	}
1285 	funcs =	dbh->methods->get_driver_methods(dbh, kind);
1286 	if (!funcs) {
1287 		return 0;
1288 	}
1289 
1290 	if (!(dbh->cls_methods[kind] = pemalloc(sizeof(HashTable), dbh->is_persistent))) {
1291 		php_error_docref(NULL, E_ERROR, "out of memory while allocating PDO methods.");
1292 	}
1293 	zend_hash_init_ex(dbh->cls_methods[kind], 8, NULL,
1294 			dbh->is_persistent? cls_method_pdtor : cls_method_dtor, dbh->is_persistent, 0);
1295 
1296 	memset(&func, 0, sizeof(func));
1297 
1298 	while (funcs->fname) {
1299 		func.type = ZEND_INTERNAL_FUNCTION;
1300 		func.handler = funcs->handler;
1301 		func.function_name = zend_string_init(funcs->fname, strlen(funcs->fname), dbh->is_persistent);
1302 		func.scope = dbh_obj->std.ce;
1303 		func.prototype = NULL;
1304 		if (funcs->flags) {
1305 			func.fn_flags = funcs->flags | ZEND_ACC_NEVER_CACHE;
1306 		} else {
1307 			func.fn_flags = ZEND_ACC_PUBLIC | ZEND_ACC_NEVER_CACHE;
1308 		}
1309 		if (funcs->arg_info) {
1310 			zend_internal_function_info *info = (zend_internal_function_info*)funcs->arg_info;
1311 
1312 			func.arg_info = (zend_internal_arg_info*)funcs->arg_info + 1;
1313 			func.num_args = funcs->num_args;
1314 			if (info->required_num_args == (uint32_t)-1) {
1315 				func.required_num_args = funcs->num_args;
1316 			} else {
1317 				func.required_num_args = info->required_num_args;
1318 			}
1319 			if (info->return_reference) {
1320 				func.fn_flags |= ZEND_ACC_RETURN_REFERENCE;
1321 			}
1322 			if (funcs->arg_info[funcs->num_args].is_variadic) {
1323 				func.fn_flags |= ZEND_ACC_VARIADIC;
1324 				/* Don't count the variadic argument */
1325 				func.num_args--;
1326 			}
1327 		} else {
1328 			func.arg_info = NULL;
1329 			func.num_args = 0;
1330 			func.required_num_args = 0;
1331 		}
1332 		zend_set_function_arg_flags((zend_function*)&func);
1333 		namelen = strlen(funcs->fname);
1334 		lc_name = emalloc(namelen+1);
1335 		zend_str_tolower_copy(lc_name, funcs->fname, namelen);
1336 		zend_hash_str_add_mem(dbh->cls_methods[kind], lc_name, namelen, &func, sizeof(func));
1337 		efree(lc_name);
1338 		funcs++;
1339 	}
1340 
1341 	return 1;
1342 }
1343 
dbh_method_get(zend_object ** object,zend_string * method_name,const zval * key)1344 static union _zend_function *dbh_method_get(zend_object **object, zend_string *method_name, const zval *key)
1345 {
1346 	zend_function *fbc = NULL;
1347 	pdo_dbh_object_t *dbh_obj = php_pdo_dbh_fetch_object(*object);
1348 	zend_string *lc_method_name;
1349 
1350 	lc_method_name = zend_string_init(ZSTR_VAL(method_name), ZSTR_LEN(method_name), 0);
1351 	zend_str_tolower_copy(ZSTR_VAL(lc_method_name), ZSTR_VAL(method_name), ZSTR_LEN(method_name));
1352 
1353 	if ((fbc = std_object_handlers.get_method(object, method_name, key)) == NULL) {
1354 		/* not a pre-defined method, nor a user-defined method; check
1355 		 * the driver specific methods */
1356 		if (!dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1357 			if (!pdo_hash_methods(dbh_obj,
1358 				PDO_DBH_DRIVER_METHOD_KIND_DBH)
1359 				|| !dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH]) {
1360 				goto out;
1361 			}
1362 		}
1363 
1364 		fbc = zend_hash_find_ptr(dbh_obj->inner->cls_methods[PDO_DBH_DRIVER_METHOD_KIND_DBH], lc_method_name);
1365 	}
1366 
1367 out:
1368 	zend_string_release(lc_method_name);
1369 	return fbc;
1370 }
1371 
dbh_compare(zval * object1,zval * object2)1372 static int dbh_compare(zval *object1, zval *object2)
1373 {
1374 	return -1;
1375 }
1376 
dbh_get_gc(zval * object,zval ** gc_data,int * gc_count)1377 static HashTable *dbh_get_gc(zval *object, zval **gc_data, int *gc_count)
1378 {
1379 	pdo_dbh_t *dbh = Z_PDO_DBH_P(object);
1380 	*gc_data = &dbh->def_stmt_ctor_args;
1381 	*gc_count = 1;
1382 	return zend_std_get_properties(object);
1383 }
1384 
1385 static zend_object_handlers pdo_dbh_object_handlers;
1386 static void pdo_dbh_free_storage(zend_object *std);
1387 
pdo_dbh_init(void)1388 void pdo_dbh_init(void)
1389 {
1390 	zend_class_entry ce;
1391 
1392 	INIT_CLASS_ENTRY(ce, "PDO", pdo_dbh_functions);
1393 	pdo_dbh_ce = zend_register_internal_class(&ce);
1394 	pdo_dbh_ce->create_object = pdo_dbh_new;
1395 
1396 	memcpy(&pdo_dbh_object_handlers, &std_object_handlers, sizeof(zend_object_handlers));
1397 	pdo_dbh_object_handlers.offset = XtOffsetOf(pdo_dbh_object_t, std);
1398 	pdo_dbh_object_handlers.dtor_obj = zend_objects_destroy_object;
1399 	pdo_dbh_object_handlers.free_obj = pdo_dbh_free_storage;
1400 	pdo_dbh_object_handlers.get_method = dbh_method_get;
1401 	pdo_dbh_object_handlers.compare_objects = dbh_compare;
1402 	pdo_dbh_object_handlers.get_gc = dbh_get_gc;
1403 
1404 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_BOOL", (zend_long)PDO_PARAM_BOOL);
1405 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_NULL", (zend_long)PDO_PARAM_NULL);
1406 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_INT",  (zend_long)PDO_PARAM_INT);
1407 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_STR",  (zend_long)PDO_PARAM_STR);
1408 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_LOB",  (zend_long)PDO_PARAM_LOB);
1409 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_STMT", (zend_long)PDO_PARAM_STMT);
1410 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_INPUT_OUTPUT", (zend_long)PDO_PARAM_INPUT_OUTPUT);
1411 
1412 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_ALLOC",		(zend_long)PDO_PARAM_EVT_ALLOC);
1413 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FREE",			(zend_long)PDO_PARAM_EVT_FREE);
1414 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_PRE",		(zend_long)PDO_PARAM_EVT_EXEC_PRE);
1415 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_EXEC_POST",	(zend_long)PDO_PARAM_EVT_EXEC_POST);
1416 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_PRE",	(zend_long)PDO_PARAM_EVT_FETCH_PRE);
1417 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_FETCH_POST",	(zend_long)PDO_PARAM_EVT_FETCH_POST);
1418 	REGISTER_PDO_CLASS_CONST_LONG("PARAM_EVT_NORMALIZE",	(zend_long)PDO_PARAM_EVT_NORMALIZE);
1419 
1420 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_LAZY", (zend_long)PDO_FETCH_LAZY);
1421 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ASSOC", (zend_long)PDO_FETCH_ASSOC);
1422 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_NUM",  (zend_long)PDO_FETCH_NUM);
1423 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOTH", (zend_long)PDO_FETCH_BOTH);
1424 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_OBJ",  (zend_long)PDO_FETCH_OBJ);
1425 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_BOUND", (zend_long)PDO_FETCH_BOUND);
1426 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_COLUMN", (zend_long)PDO_FETCH_COLUMN);
1427 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASS", (zend_long)PDO_FETCH_CLASS);
1428 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_INTO", (zend_long)PDO_FETCH_INTO);
1429 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_FUNC", (zend_long)PDO_FETCH_FUNC);
1430 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_GROUP", (zend_long)PDO_FETCH_GROUP);
1431 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_UNIQUE", (zend_long)PDO_FETCH_UNIQUE);
1432 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_KEY_PAIR", (zend_long)PDO_FETCH_KEY_PAIR);
1433 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_CLASSTYPE", (zend_long)PDO_FETCH_CLASSTYPE);
1434 
1435 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_SERIALIZE",(zend_long)PDO_FETCH_SERIALIZE);
1436 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_PROPS_LATE", (zend_long)PDO_FETCH_PROPS_LATE);
1437 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_NAMED", (zend_long)PDO_FETCH_NAMED);
1438 
1439 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_AUTOCOMMIT",	(zend_long)PDO_ATTR_AUTOCOMMIT);
1440 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_PREFETCH",		(zend_long)PDO_ATTR_PREFETCH);
1441 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_TIMEOUT", 		(zend_long)PDO_ATTR_TIMEOUT);
1442 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_ERRMODE", 		(zend_long)PDO_ATTR_ERRMODE);
1443 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_VERSION",	(zend_long)PDO_ATTR_SERVER_VERSION);
1444 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CLIENT_VERSION", 	(zend_long)PDO_ATTR_CLIENT_VERSION);
1445 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_SERVER_INFO",		(zend_long)PDO_ATTR_SERVER_INFO);
1446 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CONNECTION_STATUS", 	(zend_long)PDO_ATTR_CONNECTION_STATUS);
1447 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CASE",		 	(zend_long)PDO_ATTR_CASE);
1448 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR_NAME", 	(zend_long)PDO_ATTR_CURSOR_NAME);
1449 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_CURSOR",	 	(zend_long)PDO_ATTR_CURSOR);
1450 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_ORACLE_NULLS",	(zend_long)PDO_ATTR_ORACLE_NULLS);
1451 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_PERSISTENT",	(zend_long)PDO_ATTR_PERSISTENT);
1452 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_STATEMENT_CLASS",		(zend_long)PDO_ATTR_STATEMENT_CLASS);
1453 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_TABLE_NAMES",		(zend_long)PDO_ATTR_FETCH_TABLE_NAMES);
1454 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_FETCH_CATALOG_NAMES",		(zend_long)PDO_ATTR_FETCH_CATALOG_NAMES);
1455 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_DRIVER_NAME",		(zend_long)PDO_ATTR_DRIVER_NAME);
1456 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_STRINGIFY_FETCHES", (zend_long)PDO_ATTR_STRINGIFY_FETCHES);
1457 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_MAX_COLUMN_LEN", (zend_long)PDO_ATTR_MAX_COLUMN_LEN);
1458 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_EMULATE_PREPARES", (zend_long)PDO_ATTR_EMULATE_PREPARES);
1459 	REGISTER_PDO_CLASS_CONST_LONG("ATTR_DEFAULT_FETCH_MODE", (zend_long)PDO_ATTR_DEFAULT_FETCH_MODE);
1460 
1461 	REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_SILENT",	(zend_long)PDO_ERRMODE_SILENT);
1462 	REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_WARNING",	(zend_long)PDO_ERRMODE_WARNING);
1463 	REGISTER_PDO_CLASS_CONST_LONG("ERRMODE_EXCEPTION",	(zend_long)PDO_ERRMODE_EXCEPTION);
1464 
1465 	REGISTER_PDO_CLASS_CONST_LONG("CASE_NATURAL",	(zend_long)PDO_CASE_NATURAL);
1466 	REGISTER_PDO_CLASS_CONST_LONG("CASE_LOWER",	(zend_long)PDO_CASE_LOWER);
1467 	REGISTER_PDO_CLASS_CONST_LONG("CASE_UPPER",	(zend_long)PDO_CASE_UPPER);
1468 
1469 	REGISTER_PDO_CLASS_CONST_LONG("NULL_NATURAL",	(zend_long)PDO_NULL_NATURAL);
1470 	REGISTER_PDO_CLASS_CONST_LONG("NULL_EMPTY_STRING",	(zend_long)PDO_NULL_EMPTY_STRING);
1471 	REGISTER_PDO_CLASS_CONST_LONG("NULL_TO_STRING",	(zend_long)PDO_NULL_TO_STRING);
1472 
1473 	REGISTER_PDO_CLASS_CONST_STRING("ERR_NONE",	PDO_ERR_NONE);
1474 
1475 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_NEXT", (zend_long)PDO_FETCH_ORI_NEXT);
1476 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_PRIOR", (zend_long)PDO_FETCH_ORI_PRIOR);
1477 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_FIRST", (zend_long)PDO_FETCH_ORI_FIRST);
1478 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_LAST", (zend_long)PDO_FETCH_ORI_LAST);
1479 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_ABS", (zend_long)PDO_FETCH_ORI_ABS);
1480 	REGISTER_PDO_CLASS_CONST_LONG("FETCH_ORI_REL", (zend_long)PDO_FETCH_ORI_REL);
1481 
1482 	REGISTER_PDO_CLASS_CONST_LONG("CURSOR_FWDONLY", (zend_long)PDO_CURSOR_FWDONLY);
1483 	REGISTER_PDO_CLASS_CONST_LONG("CURSOR_SCROLL", (zend_long)PDO_CURSOR_SCROLL);
1484 
1485 #if 0
1486 	REGISTER_PDO_CLASS_CONST_LONG("ERR_CANT_MAP", 		(zend_long)PDO_ERR_CANT_MAP);
1487 	REGISTER_PDO_CLASS_CONST_LONG("ERR_SYNTAX", 		(zend_long)PDO_ERR_SYNTAX);
1488 	REGISTER_PDO_CLASS_CONST_LONG("ERR_CONSTRAINT", 	(zend_long)PDO_ERR_CONSTRAINT);
1489 	REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_FOUND", 		(zend_long)PDO_ERR_NOT_FOUND);
1490 	REGISTER_PDO_CLASS_CONST_LONG("ERR_ALREADY_EXISTS", 	(zend_long)PDO_ERR_ALREADY_EXISTS);
1491 	REGISTER_PDO_CLASS_CONST_LONG("ERR_NOT_IMPLEMENTED", 	(zend_long)PDO_ERR_NOT_IMPLEMENTED);
1492 	REGISTER_PDO_CLASS_CONST_LONG("ERR_MISMATCH", 		(zend_long)PDO_ERR_MISMATCH);
1493 	REGISTER_PDO_CLASS_CONST_LONG("ERR_TRUNCATED", 		(zend_long)PDO_ERR_TRUNCATED);
1494 	REGISTER_PDO_CLASS_CONST_LONG("ERR_DISCONNECTED", 	(zend_long)PDO_ERR_DISCONNECTED);
1495 	REGISTER_PDO_CLASS_CONST_LONG("ERR_NO_PERM",		(zend_long)PDO_ERR_NO_PERM);
1496 #endif
1497 
1498 }
1499 
dbh_free(pdo_dbh_t * dbh,zend_bool free_persistent)1500 static void dbh_free(pdo_dbh_t *dbh, zend_bool free_persistent)
1501 {
1502 	int i;
1503 
1504 	if (dbh->query_stmt) {
1505 		zval_ptr_dtor(&dbh->query_stmt_zval);
1506 		dbh->query_stmt = NULL;
1507 	}
1508 
1509 	if (dbh->is_persistent) {
1510 #if ZEND_DEBUG
1511 		ZEND_ASSERT(!free_persistent || (dbh->refcount == 1));
1512 #endif
1513 		if (!free_persistent && (--dbh->refcount)) {
1514 			return;
1515 		}
1516 	}
1517 
1518 	if (dbh->methods) {
1519 		dbh->methods->closer(dbh);
1520 	}
1521 
1522 	if (dbh->data_source) {
1523 		pefree((char *)dbh->data_source, dbh->is_persistent);
1524 	}
1525 	if (dbh->username) {
1526 		pefree(dbh->username, dbh->is_persistent);
1527 	}
1528 	if (dbh->password) {
1529 		pefree(dbh->password, dbh->is_persistent);
1530 	}
1531 
1532 	if (dbh->persistent_id) {
1533 		pefree((char *)dbh->persistent_id, dbh->is_persistent);
1534 	}
1535 
1536 	if (!Z_ISUNDEF(dbh->def_stmt_ctor_args)) {
1537 		zval_ptr_dtor(&dbh->def_stmt_ctor_args);
1538 	}
1539 
1540 	for (i = 0; i < PDO_DBH_DRIVER_METHOD_KIND__MAX; i++) {
1541 		if (dbh->cls_methods[i]) {
1542 			zend_hash_destroy(dbh->cls_methods[i]);
1543 			pefree(dbh->cls_methods[i], dbh->is_persistent);
1544 		}
1545 	}
1546 
1547 	pefree(dbh, dbh->is_persistent);
1548 }
1549 
pdo_dbh_free_storage(zend_object * std)1550 static void pdo_dbh_free_storage(zend_object *std)
1551 {
1552 	pdo_dbh_t *dbh = php_pdo_dbh_fetch_inner(std);
1553 	if (dbh->in_txn && dbh->methods && dbh->methods->rollback) {
1554 		dbh->methods->rollback(dbh);
1555 		dbh->in_txn = 0;
1556 	}
1557 
1558 	if (dbh->is_persistent && dbh->methods && dbh->methods->persistent_shutdown) {
1559 		dbh->methods->persistent_shutdown(dbh);
1560 	}
1561 	zend_object_std_dtor(std);
1562 	dbh_free(dbh, 0);
1563 }
1564 
pdo_dbh_new(zend_class_entry * ce)1565 zend_object *pdo_dbh_new(zend_class_entry *ce)
1566 {
1567 	pdo_dbh_object_t *dbh;
1568 
1569 	dbh = ecalloc(1, sizeof(pdo_dbh_object_t) + zend_object_properties_size(ce));
1570 	zend_object_std_init(&dbh->std, ce);
1571 	object_properties_init(&dbh->std, ce);
1572 	rebuild_object_properties(&dbh->std);
1573 	dbh->inner = ecalloc(1, sizeof(pdo_dbh_t));
1574 	dbh->inner->def_stmt_ce = pdo_dbstmt_ce;
1575 
1576 	dbh->std.handlers = &pdo_dbh_object_handlers;
1577 
1578 	return &dbh->std;
1579 }
1580 
1581 /* }}} */
1582 
ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor)1583 ZEND_RSRC_DTOR_FUNC(php_pdo_pdbh_dtor) /* {{{ */
1584 {
1585 	if (res->ptr) {
1586 		pdo_dbh_t *dbh = (pdo_dbh_t*)res->ptr;
1587 		dbh_free(dbh, 1);
1588 		res->ptr = NULL;
1589 	}
1590 }
1591 /* }}} */
1592 
1593 /*
1594  * Local variables:
1595  * tab-width: 4
1596  * c-basic-offset: 4
1597  * End:
1598  * vim600: noet sw=4 ts=4 fdm=marker
1599  * vim<600: noet sw=4 ts=4
1600  */
1601