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

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

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