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

LTP GCOV extension - code coverage report
Current view: directory - pdo - pdo_dbh.c
Test: PHP Code Coverage
Date: 2009-11-21 Instrumented lines: 766
Code covered: 83.4 % Executed lines: 639
Legend: not executed executed

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

Generated by: LTP GCOV extension version 1.5

Generated at Sat, 21 Nov 2009 12:27:05 +0000 (3 days ago)

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