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