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, ¶mtype)) {
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