PHP  
 PHP: Test and Code Coverage Analysis
downloads | QA | documentation | faq | getting help | mailing lists | reporting bugs | php.net sites | links | my php.net 
 

LCOV - code coverage report
Current view: top level - ext/pdo - pdo_dbh.c (source / functions) Hit Total Coverage
Test: PHP Code Coverage Lines: 652 786 83.0 %
Date: 2014-12-20 Functions: 30 33 90.9 %
Legend: Lines: hit not hit

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

Generated by: LCOV version 1.10

Generated at Sun, 21 Dec 2014 04:58:54 +0000 (25 hours ago)

Copyright © 2005-2014 The PHP Group
All rights reserved.