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

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

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