Annotation of embedaddon/php/ext/pdo/pdo_dbh.c, revision 1.1.1.1

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

FreeBSD-CVSweb <freebsd-cvsweb@FreeBSD.org>