Annotation of embedaddon/php/ext/pdo_firebird/firebird_driver.c, revision 1.1

1.1     ! misho       1: /*
        !             2:   +----------------------------------------------------------------------+
        !             3:   | PHP Version 5                                                        |
        !             4:   +----------------------------------------------------------------------+
        !             5:   | Copyright (c) 1997-2012 The PHP Group                                |
        !             6:   +----------------------------------------------------------------------+
        !             7:   | This source file is subject to version 3.01 of the PHP license,      |
        !             8:   | that is bundled with this package in the file LICENSE, and is        |
        !             9:   | available through the world-wide-web at the following url:           |
        !            10:   | http://www.php.net/license/3_01.txt                                  |
        !            11:   | If you did not receive a copy of the PHP license and are unable to   |
        !            12:   | obtain it through the world-wide-web, please send a note to          |
        !            13:   | license@php.net so we can mail you a copy immediately.               |
        !            14:   +----------------------------------------------------------------------+
        !            15:   | Author: Ard Biesheuvel <abies@php.net>                               |
        !            16:   +----------------------------------------------------------------------+
        !            17: */
        !            18: 
        !            19: /* $Id: firebird_driver.c 321634 2012-01-01 13:15:04Z felipe $ */
        !            20: 
        !            21: #ifdef HAVE_CONFIG_H
        !            22: #include "config.h"
        !            23: #endif
        !            24: 
        !            25: #define _GNU_SOURCE
        !            26: 
        !            27: #include "php.h"
        !            28: #ifdef ZEND_ENGINE_2
        !            29: # include "zend_exceptions.h"
        !            30: #endif
        !            31: #include "php_ini.h"
        !            32: #include "ext/standard/info.h"
        !            33: #include "pdo/php_pdo.h"
        !            34: #include "pdo/php_pdo_driver.h"
        !            35: #include "php_pdo_firebird.h"
        !            36: #include "php_pdo_firebird_int.h"
        !            37: 
        !            38: static int firebird_alloc_prepare_stmt(pdo_dbh_t*, const char*, long, XSQLDA*, isc_stmt_handle*,
        !            39:        HashTable* TSRMLS_DC);
        !            40: 
        !            41: /* map driver specific error message to PDO error */
        !            42: void _firebird_error(pdo_dbh_t *dbh, pdo_stmt_t *stmt, char const *file, long line TSRMLS_DC) /* {{{ */
        !            43: {
        !            44: #if 0
        !            45:        pdo_firebird_db_handle *H = stmt ? ((pdo_firebird_stmt *)stmt->driver_data)->H 
        !            46:                : (pdo_firebird_db_handle *)dbh->driver_data;
        !            47: #endif
        !            48:        pdo_error_type *const error_code = stmt ? &stmt->error_code : &dbh->error_code;
        !            49:        
        !            50: #if 0
        !            51:        switch (isc_sqlcode(H->isc_status)) {
        !            52: 
        !            53:                case 0:
        !            54:                        *error_code = PDO_ERR_NONE;
        !            55:                        break;
        !            56:                default:
        !            57:                        *error_code = PDO_ERR_CANT_MAP;
        !            58:                        break;
        !            59:                case -104:
        !            60:                        *error_code = PDO_ERR_SYNTAX;
        !            61:                        break;
        !            62:                case -530:
        !            63:                case -803:
        !            64:                        *error_code = PDO_ERR_CONSTRAINT;
        !            65:                        break;
        !            66:                case -204:
        !            67:                case -205:
        !            68:                case -206:
        !            69:                case -829:
        !            70:                        *error_code = PDO_ERR_NOT_FOUND;
        !            71:                        break;
        !            72: 
        !            73:                        *error_code = PDO_ERR_ALREADY_EXISTS;
        !            74:                        break;
        !            75:                
        !            76:                        *error_code = PDO_ERR_NOT_IMPLEMENTED;
        !            77:                        break;
        !            78:                case -313:
        !            79:                case -804:
        !            80:                        *error_code = PDO_ERR_MISMATCH;
        !            81:                        break;
        !            82:                case -303:
        !            83:                case -314:      
        !            84:                case -413:
        !            85:                        *error_code = PDO_ERR_TRUNCATED;
        !            86:                        break;
        !            87:                        
        !            88:                        *error_code = PDO_ERR_DISCONNECTED;
        !            89:                        break;
        !            90:        }
        !            91: #else
        !            92:        strcpy(*error_code, "HY000");
        !            93: #endif
        !            94: }
        !            95: /* }}} */
        !            96: 
        !            97: #define RECORD_ERROR(dbh) _firebird_error(dbh, NULL, __FILE__, __LINE__ TSRMLS_CC)
        !            98: 
        !            99: /* called by PDO to close a db handle */
        !           100: static int firebird_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
        !           101: {
        !           102:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           103:        
        !           104:        if (dbh->in_txn) {
        !           105:                if (dbh->auto_commit) {
        !           106:                        if (isc_commit_transaction(H->isc_status, &H->tr)) {
        !           107:                                RECORD_ERROR(dbh);
        !           108:                        }
        !           109:                } else {
        !           110:                        if (isc_rollback_transaction(H->isc_status, &H->tr)) {
        !           111:                                RECORD_ERROR(dbh);
        !           112:                        }
        !           113:                }
        !           114:        }
        !           115:        
        !           116:        if (isc_detach_database(H->isc_status, &H->db)) {
        !           117:                RECORD_ERROR(dbh);
        !           118:        }
        !           119: 
        !           120:        if (H->date_format) {
        !           121:                efree(H->date_format);
        !           122:        }
        !           123:        if (H->time_format) {
        !           124:                efree(H->time_format);
        !           125:        }
        !           126:        if (H->timestamp_format) {
        !           127:                efree(H->timestamp_format);
        !           128:        }
        !           129:        
        !           130:        pefree(H, dbh->is_persistent);
        !           131: 
        !           132:        return 0;
        !           133: }
        !           134: /* }}} */
        !           135: 
        !           136: /* called by PDO to prepare an SQL query */
        !           137: static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, /* {{{ */
        !           138:        pdo_stmt_t *stmt, zval *driver_options TSRMLS_DC)
        !           139: {
        !           140:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           141:        pdo_firebird_stmt *S = NULL;
        !           142:        HashTable *np;
        !           143: 
        !           144:        do {
        !           145:                isc_stmt_handle s = NULL;
        !           146:                XSQLDA num_sqlda;
        !           147:                static char const info[] = { isc_info_sql_stmt_type };
        !           148:                char result[8];
        !           149: 
        !           150:                num_sqlda.version = PDO_FB_SQLDA_VERSION;
        !           151:                num_sqlda.sqln = 1;
        !           152: 
        !           153:                ALLOC_HASHTABLE(np);
        !           154:                zend_hash_init(np, 8, NULL, NULL, 0);
        !           155:                
        !           156:                /* allocate and prepare statement */
        !           157:                if (!firebird_alloc_prepare_stmt(dbh, sql, sql_len, &num_sqlda, &s, np TSRMLS_CC)) {
        !           158:                        break;
        !           159:                }
        !           160:        
        !           161:                /* allocate a statement handle struct of the right size (struct out_sqlda is inlined) */
        !           162:                S = ecalloc(1, sizeof(*S)-sizeof(XSQLDA) + XSQLDA_LENGTH(num_sqlda.sqld));
        !           163:                S->H = H;
        !           164:                S->stmt = s;
        !           165:                S->fetch_buf = ecalloc(1,sizeof(char*) * num_sqlda.sqld);
        !           166:                S->out_sqlda.version = PDO_FB_SQLDA_VERSION;
        !           167:                S->out_sqlda.sqln = stmt->column_count = num_sqlda.sqld;
        !           168:                S->named_params = np;
        !           169: 
        !           170:                /* determine the statement type */
        !           171:                if (isc_dsql_sql_info(H->isc_status, &s, sizeof(info), const_cast(info), sizeof(result),
        !           172:                                result)) {
        !           173:                        break;
        !           174:                }
        !           175:                S->statement_type = result[3];  
        !           176:                
        !           177:                /* fill the output sqlda with information about the prepared query */
        !           178:                if (isc_dsql_describe(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &S->out_sqlda)) {
        !           179:                        RECORD_ERROR(dbh);
        !           180:                        break;
        !           181:                }
        !           182:                
        !           183:                /* allocate the input descriptors */
        !           184:                if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, &num_sqlda)) {
        !           185:                        break;
        !           186:                }
        !           187:                
        !           188:                if (num_sqlda.sqld) {
        !           189:                        S->in_sqlda = ecalloc(1,XSQLDA_LENGTH(num_sqlda.sqld));
        !           190:                        S->in_sqlda->version = PDO_FB_SQLDA_VERSION;
        !           191:                        S->in_sqlda->sqln = num_sqlda.sqld;
        !           192:                
        !           193:                        if (isc_dsql_describe_bind(H->isc_status, &s, PDO_FB_SQLDA_VERSION, S->in_sqlda)) {
        !           194:                                break;
        !           195:                        }
        !           196:                }
        !           197:        
        !           198:                stmt->driver_data = S;
        !           199:                stmt->methods = &firebird_stmt_methods;
        !           200:                stmt->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL;
        !           201:        
        !           202:                return 1;
        !           203: 
        !           204:        } while (0);
        !           205: 
        !           206:        RECORD_ERROR(dbh);
        !           207:        
        !           208:        zend_hash_destroy(np);
        !           209:        FREE_HASHTABLE(np);
        !           210:        
        !           211:        if (S) {
        !           212:                if (S->in_sqlda) {
        !           213:                        efree(S->in_sqlda);
        !           214:                }
        !           215:                efree(S);
        !           216:        }
        !           217:        
        !           218:        return 0;
        !           219: }
        !           220: /* }}} */
        !           221: 
        !           222: /* called by PDO to execute a statement that doesn't produce a result set */
        !           223: static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) /* {{{ */
        !           224: {
        !           225:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           226:        isc_stmt_handle stmt = NULL;
        !           227:        static char const info_count[] = { isc_info_sql_records };
        !           228:        char result[64];
        !           229:        int ret = 0;
        !           230:        XSQLDA in_sqlda, out_sqlda;
        !           231:                
        !           232:        /* TODO no placeholders in exec() for now */
        !           233:        in_sqlda.version = out_sqlda.version = PDO_FB_SQLDA_VERSION;
        !           234:        in_sqlda.sqld = out_sqlda.sqld = 0;
        !           235:        out_sqlda.sqln = 1;
        !           236:        
        !           237:        /* allocate and prepare statement */
        !           238:        if (!firebird_alloc_prepare_stmt(dbh, sql, sql_len, &out_sqlda, &stmt, 0 TSRMLS_CC)) {
        !           239:                return -1;
        !           240:        }
        !           241: 
        !           242:        /* execute the statement */
        !           243:        if (isc_dsql_execute2(H->isc_status, &H->tr, &stmt, PDO_FB_SQLDA_VERSION, &in_sqlda, &out_sqlda)) {
        !           244:                RECORD_ERROR(dbh);
        !           245:                return -1;
        !           246:        }
        !           247:        
        !           248:        /* find out how many rows were affected */
        !           249:        if (isc_dsql_sql_info(H->isc_status, &stmt, sizeof(info_count), const_cast(info_count),
        !           250:                        sizeof(result), result)) {
        !           251:                RECORD_ERROR(dbh);
        !           252:                return -1;
        !           253:        }
        !           254: 
        !           255:        if (result[0] == isc_info_sql_records) {
        !           256:                unsigned i = 3, result_size = isc_vax_integer(&result[1],2);
        !           257: 
        !           258:                while (result[i] != isc_info_end && i < result_size) {
        !           259:                        short len = (short)isc_vax_integer(&result[i+1],2);
        !           260:                        if (result[i] != isc_info_req_select_count) {
        !           261:                                ret += isc_vax_integer(&result[i+3],len);
        !           262:                        }
        !           263:                        i += len+3;
        !           264:                }
        !           265:        }
        !           266:        
        !           267:        /* commit if we're in auto_commit mode */
        !           268:        if (dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) {
        !           269:                RECORD_ERROR(dbh);
        !           270:        }
        !           271: 
        !           272:        return ret;
        !           273: }
        !           274: /* }}} */
        !           275: 
        !           276: /* called by the PDO SQL parser to add quotes to values that are copied into SQL */
        !           277: static int firebird_handle_quoter(pdo_dbh_t *dbh, const char *unquoted, int unquotedlen, /* {{{ */
        !           278:        char **quoted, int *quotedlen, enum pdo_param_type paramtype TSRMLS_DC)
        !           279: {
        !           280:        int qcount = 0;
        !           281:        char const *co, *l, *r;
        !           282:        char *c;
        !           283:        
        !           284:        if (!unquotedlen) {
        !           285:                *quotedlen = 2;
        !           286:                *quoted = emalloc(*quotedlen+1);
        !           287:                strcpy(*quoted, "''");
        !           288:                return 1;
        !           289:        }
        !           290:                        
        !           291:        /* Firebird only requires single quotes to be doubled if string lengths are used */
        !           292:        /* count the number of ' characters */
        !           293:        for (co = unquoted; (co = strchr(co,'\'')); qcount++, co++);
        !           294:        
        !           295:        *quotedlen = unquotedlen + qcount + 2;
        !           296:        *quoted = c = emalloc(*quotedlen+1);            
        !           297:        *c++ = '\'';
        !           298:        
        !           299:        /* foreach (chunk that ends in a quote) */
        !           300:        for (l = unquoted; (r = strchr(l,'\'')); l = r+1) {                     
        !           301:                strncpy(c, l, r-l+1);
        !           302:                c += (r-l+1);                   
        !           303:                /* add the second quote */
        !           304:                *c++ = '\'';
        !           305:        }
        !           306:                
        !           307:        /* copy the remainder */
        !           308:        strncpy(c, l, *quotedlen-(c-*quoted)-1);
        !           309:        (*quoted)[*quotedlen-1] = '\''; 
        !           310:        (*quoted)[*quotedlen]   = '\0';
        !           311:        
        !           312:        return 1;
        !           313: }
        !           314: /* }}} */
        !           315: 
        !           316: /* called by PDO to start a transaction */
        !           317: static int firebird_handle_begin(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
        !           318: {
        !           319:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           320:        char tpb[8] = { isc_tpb_version3 }, *ptpb = tpb+1;
        !           321: #if abies_0    
        !           322:        if (dbh->transaction_flags & PDO_TRANS_ISOLATION_LEVEL) {
        !           323:                if (dbh->transaction_flags & PDO_TRANS_READ_UNCOMMITTED) {
        !           324:                        /* this is a poor fit, but it's all we have */
        !           325:                        *ptpb++ = isc_tpb_read_committed;
        !           326:                        *ptpb++ = isc_tpb_rec_version;
        !           327:                        dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_UNCOMMITTED);
        !           328:                } else if (dbh->transaction_flags & PDO_TRANS_READ_COMMITTED) {
        !           329:                        *ptpb++ = isc_tpb_read_committed;
        !           330:                        *ptpb++ = isc_tpb_no_rec_version;
        !           331:                        dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_READ_COMMITTED);
        !           332:                } else if (dbh->transaction_flags & PDO_TRANS_REPEATABLE_READ) {
        !           333:                        *ptpb++ = isc_tpb_concurrency;
        !           334:                        dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_REPEATABLE_READ);
        !           335:                } else {
        !           336:                        *ptpb++ = isc_tpb_consistency;
        !           337:                        dbh->transaction_flags &= ~(PDO_TRANS_ISOLATION_LEVEL^PDO_TRANS_SERIALIZABLE);
        !           338:                }
        !           339:        }
        !           340:                
        !           341:        if (dbh->transaction_flags & PDO_TRANS_ACCESS_MODE) {
        !           342:                if (dbh->transaction_flags & PDO_TRANS_READONLY) {
        !           343:                        *ptpb++ = isc_tpb_read;
        !           344:                        dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READONLY);
        !           345:                } else {
        !           346:                        *ptpb++ = isc_tpb_write;
        !           347:                        dbh->transaction_flags &= ~(PDO_TRANS_ACCESS_MODE^PDO_TRANS_READWRITE);
        !           348:                }
        !           349:        }
        !           350: 
        !           351:        if (dbh->transaction_flags & PDO_TRANS_CONFLICT_RESOLUTION) {
        !           352:                if (dbh->transaction_flags & PDO_TRANS_RETRY) {
        !           353:                        *ptpb++ = isc_tpb_wait;
        !           354:                        dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_RETRY);
        !           355:                } else {
        !           356:                        *ptpb++ = isc_tpb_nowait;
        !           357:                        dbh->transaction_flags &= ~(PDO_TRANS_CONFLICT_RESOLUTION^PDO_TRANS_ABORT);
        !           358:                }
        !           359:        }
        !           360: #endif
        !           361:        if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, (unsigned short)(ptpb-tpb), tpb)) {
        !           362:                RECORD_ERROR(dbh);
        !           363:                return 0;
        !           364:        }
        !           365:        return 1;
        !           366: }
        !           367: /* }}} */
        !           368: 
        !           369: /* called by PDO to commit a transaction */
        !           370: static int firebird_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
        !           371: {
        !           372:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           373: 
        !           374:        if (isc_commit_transaction(H->isc_status, &H->tr)) {
        !           375:                RECORD_ERROR(dbh);
        !           376:                return 0;
        !           377:        }
        !           378:        return 1;
        !           379: }
        !           380: /* }}} */
        !           381: 
        !           382: /* called by PDO to rollback a transaction */
        !           383: static int firebird_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */
        !           384: {
        !           385:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           386: 
        !           387:        if (isc_rollback_transaction(H->isc_status, &H->tr)) {
        !           388:                RECORD_ERROR(dbh);
        !           389:                return 0;
        !           390:        }
        !           391:        return 1;
        !           392: }
        !           393: /* }}} */
        !           394: 
        !           395: /* used by prepare and exec to allocate a statement handle and prepare the SQL */
        !           396: static int firebird_alloc_prepare_stmt(pdo_dbh_t *dbh, const char *sql, long sql_len, /* {{{ */
        !           397:        XSQLDA *out_sqlda, isc_stmt_handle *s, HashTable *named_params TSRMLS_DC)
        !           398: {
        !           399:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           400:        char *c, *new_sql, in_quote, in_param, pname[64], *ppname;
        !           401:        long l, pindex = -1;
        !           402:                
        !           403:        /* Firebird allows SQL statements up to 64k, so bail if it doesn't fit */
        !           404:        if (sql_len > SHORT_MAX) {
        !           405:                strcpy(dbh->error_code, "01004");
        !           406:                return 0;
        !           407:        }
        !           408:        
        !           409:        /* start a new transaction implicitly if auto_commit is enabled and no transaction is open */
        !           410:        if (dbh->auto_commit && !dbh->in_txn) {
        !           411:                /* dbh->transaction_flags = PDO_TRANS_READ_UNCOMMITTED; */
        !           412: 
        !           413:                if (!firebird_handle_begin(dbh TSRMLS_CC)) {
        !           414:                        return 0;
        !           415:                }
        !           416:                dbh->in_txn = 1;
        !           417:        }
        !           418:        
        !           419:        /* allocate the statement */
        !           420:        if (isc_dsql_allocate_statement(H->isc_status, &H->db, s)) {
        !           421:                RECORD_ERROR(dbh);
        !           422:                return 0;
        !           423:        }
        !           424:        
        !           425:        /* in order to support named params, which Firebird itself doesn't, 
        !           426:           we need to replace :foo by ?, and store the name we just replaced */
        !           427:        new_sql = c = emalloc(sql_len+1);
        !           428:        
        !           429:        for (l = in_quote = in_param = 0; l <= sql_len; ++l) {
        !           430:                if ( !(in_quote ^= (sql[l] == '\''))) {
        !           431:                        if (!in_param) {
        !           432:                                switch (sql[l]) {
        !           433:                                        case ':':
        !           434:                                                in_param = 1;
        !           435:                                                ppname = pname;
        !           436:                                                *ppname++ = sql[l];
        !           437:                                        case '?':
        !           438:                                                *c++ = '?';
        !           439:                                                ++pindex;
        !           440:                                        continue;
        !           441:                                }
        !           442:                        } else {
        !           443:                                 if ((in_param &= ((sql[l] >= 'A' && sql[l] <= 'Z') || (sql[l] >= 'a' && sql[l] <= 'z')
        !           444:                                         || (sql[l] >= '0' && sql[l] <= '9') || sql[l] == '_' || sql[l] == '-'))) { 
        !           445: 
        !           446:                                        
        !           447:                                        *ppname++ = sql[l];
        !           448:                                        continue;
        !           449:                                } else {
        !           450:                                        *ppname++ = 0;
        !           451:                                        if (named_params) {
        !           452:                                                zend_hash_update(named_params, pname, (unsigned int)(ppname-pname),
        !           453:                                                        (void*)&pindex, sizeof(long)+1,NULL);
        !           454:                                        }
        !           455:                                }
        !           456:                        }
        !           457:                }
        !           458:                *c++ = sql[l];
        !           459:        }
        !           460: 
        !           461:        /* prepare the statement */
        !           462:        if (isc_dsql_prepare(H->isc_status, &H->tr, s, 0, new_sql, PDO_FB_DIALECT, out_sqlda)) {
        !           463:                RECORD_ERROR(dbh);
        !           464:                efree(new_sql);
        !           465:                return 0;
        !           466:        }
        !           467:        
        !           468:        efree(new_sql);
        !           469:        return 1;
        !           470: }
        !           471: /* }}} */
        !           472:        
        !           473: /* called by PDO to set a driver-specific dbh attribute */
        !           474: static int firebird_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
        !           475: {
        !           476:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           477: 
        !           478:        switch (attr) {
        !           479:                case PDO_ATTR_AUTOCOMMIT:
        !           480: 
        !           481:                        convert_to_boolean(val);
        !           482:        
        !           483:                        /* ignore if the new value equals the old one */                        
        !           484:                        if (dbh->auto_commit ^ Z_BVAL_P(val)) {
        !           485:                                if (dbh->in_txn) {
        !           486:                                        if (Z_BVAL_P(val)) {
        !           487:                                                /* turning on auto_commit with an open transaction is illegal, because
        !           488:                                                   we won't know what to do with it */
        !           489:                                                H->last_app_error = "Cannot enable auto-commit while a transaction is already open";
        !           490:                                                return 0;
        !           491:                                        } else {
        !           492:                                                /* close the transaction */
        !           493:                                                if (!firebird_handle_commit(dbh TSRMLS_CC)) {
        !           494:                                                        break;
        !           495:                                                }
        !           496:                                                dbh->in_txn = 0;
        !           497:                                        }
        !           498:                                }
        !           499:                                dbh->auto_commit = Z_BVAL_P(val);
        !           500:                        }
        !           501:                        return 1;
        !           502: 
        !           503:                case PDO_ATTR_FETCH_TABLE_NAMES:
        !           504:                        convert_to_boolean(val);
        !           505:                        H->fetch_table_names = Z_BVAL_P(val);
        !           506:                        return 1;
        !           507: 
        !           508:                case PDO_FB_ATTR_DATE_FORMAT:
        !           509:                        convert_to_string(val);
        !           510:                        if (H->date_format) {
        !           511:                                efree(H->date_format);
        !           512:                        }
        !           513:                        spprintf(&H->date_format, 0, "%s", Z_STRVAL_P(val)); 
        !           514:                        return 1;
        !           515: 
        !           516:                case PDO_FB_ATTR_TIME_FORMAT:
        !           517:                        convert_to_string(val);
        !           518:                        if (H->time_format) {
        !           519:                                efree(H->time_format);
        !           520:                        }
        !           521:                        spprintf(&H->time_format, 0, "%s", Z_STRVAL_P(val)); 
        !           522:                        return 1;
        !           523: 
        !           524:                case PDO_FB_ATTR_TIMESTAMP_FORMAT:
        !           525:                        convert_to_string(val);
        !           526:                        if (H->timestamp_format) {
        !           527:                                efree(H->timestamp_format);
        !           528:                        }
        !           529:                        spprintf(&H->timestamp_format, 0, "%s", Z_STRVAL_P(val)); 
        !           530:                        return 1;
        !           531:        }
        !           532:        return 0;
        !           533: }
        !           534: /* }}} */
        !           535: 
        !           536: /* callback to used to report database server info */
        !           537: static void firebird_info_cb(void *arg, char const *s) /* {{{ */
        !           538: {
        !           539:        if (arg) {
        !           540:                if (*(char*)arg) { /* second call */
        !           541:                        strcat(arg, " ");
        !           542:                }
        !           543:                strcat(arg, s);
        !           544:        }
        !           545: }
        !           546: /* }}} */
        !           547: 
        !           548: /* called by PDO to get a driver-specific dbh attribute */
        !           549: static int firebird_handle_get_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) /* {{{ */
        !           550: {
        !           551:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           552: 
        !           553:        switch (attr) {
        !           554:                char tmp[512];
        !           555:                
        !           556:                case PDO_ATTR_AUTOCOMMIT:
        !           557:                        ZVAL_LONG(val,dbh->auto_commit);
        !           558:                        return 1;
        !           559: 
        !           560:                case PDO_ATTR_CONNECTION_STATUS:
        !           561:                        ZVAL_BOOL(val, !isc_version(&H->db, firebird_info_cb, NULL));
        !           562:                        return 1;
        !           563: 
        !           564:                case PDO_ATTR_CLIENT_VERSION: {
        !           565: #if defined(__GNUC__) || defined(PHP_WIN32)
        !           566:                        info_func_t info_func = NULL;
        !           567: #ifdef __GNUC__
        !           568:                        info_func = (info_func_t)dlsym(RTLD_DEFAULT, "isc_get_client_version");
        !           569: #else
        !           570:                        HMODULE l = GetModuleHandle("fbclient");
        !           571: 
        !           572:                        if (!l && !(l = GetModuleHandle("gds32"))) {
        !           573:                                break;
        !           574:                        }
        !           575:                        info_func = (info_func_t)GetProcAddress(l, "isc_get_client_version");
        !           576: #endif
        !           577:                        if (info_func) {
        !           578:                                info_func(tmp);
        !           579:                                ZVAL_STRING(val,tmp,1);
        !           580:                        } else {
        !           581:                                ZVAL_STRING(val,"Firebird 1.0/Interbase 6",1);
        !           582:                        }
        !           583: #else
        !           584:                        ZVAL_NULL(val);
        !           585: #endif
        !           586:                        }
        !           587:                        return 1;
        !           588:                        
        !           589:                case PDO_ATTR_SERVER_VERSION:
        !           590:                case PDO_ATTR_SERVER_INFO:
        !           591:                        *tmp = 0;
        !           592:                        
        !           593:                        if (!isc_version(&H->db, firebird_info_cb, (void*)tmp)) {
        !           594:                                ZVAL_STRING(val,tmp,1);
        !           595:                                return 1;
        !           596:                        }
        !           597:                        
        !           598:                case PDO_ATTR_FETCH_TABLE_NAMES:
        !           599:                        ZVAL_BOOL(val, H->fetch_table_names);
        !           600:                        return 1;
        !           601:        }
        !           602:        return 0;
        !           603: }       
        !           604: /* }}} */
        !           605:         
        !           606: /* called by PDO to retrieve driver-specific information about an error that has occurred */
        !           607: static int pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) /* {{{ */
        !           608: {       
        !           609:        pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data;
        !           610:        ISC_STATUS *s = H->isc_status;
        !           611:        char buf[400];
        !           612:        long i = 0, l, sqlcode = isc_sqlcode(s);
        !           613: 
        !           614:        if (sqlcode) {
        !           615:                add_next_index_long(info, sqlcode);
        !           616: 
        !           617:                while ((l = isc_interprete(&buf[i],&s))) {
        !           618:                        i += l;
        !           619:                        strcpy(&buf[i++], " ");
        !           620:                }
        !           621:                add_next_index_string(info, buf, 1);
        !           622:        } else if (H->last_app_error) {
        !           623:                add_next_index_long(info, -999);
        !           624:                add_next_index_string(info, const_cast(H->last_app_error),1);
        !           625:        }
        !           626:        return 1;
        !           627: }
        !           628: /* }}} */
        !           629: 
        !           630: static struct pdo_dbh_methods firebird_methods = { /* {{{ */
        !           631:        firebird_handle_closer,
        !           632:        firebird_handle_preparer,
        !           633:        firebird_handle_doer,
        !           634:        firebird_handle_quoter,
        !           635:        firebird_handle_begin,
        !           636:        firebird_handle_commit,
        !           637:        firebird_handle_rollback,
        !           638:        firebird_handle_set_attribute,
        !           639:        NULL, /* last_id not supported */
        !           640:        pdo_firebird_fetch_error_func,
        !           641:        firebird_handle_get_attribute,
        !           642:        NULL /* check_liveness */
        !           643: };
        !           644: /* }}} */
        !           645: 
        !           646: /* the driver-specific PDO handle constructor */
        !           647: static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */
        !           648: {
        !           649:        struct pdo_data_src_parser vars[] = {
        !           650:                { "dbname", NULL, 0 },
        !           651:                { "charset",  NULL,     0 },
        !           652:                { "role", NULL, 0 }
        !           653:        };
        !           654:        int i, ret = 0;
        !           655:        short buf_len = 256, dpb_len;
        !           656: 
        !           657:        pdo_firebird_db_handle *H = dbh->driver_data = pecalloc(1,sizeof(*H),dbh->is_persistent);
        !           658: 
        !           659:        php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 3);
        !           660:        
        !           661:        do {
        !           662:                static char const dpb_flags[] = { 
        !           663:                        isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name };
        !           664:                char const *dpb_values[] = { dbh->username, dbh->password, vars[1].optval, vars[2].optval };
        !           665:                char dpb_buffer[256] = { isc_dpb_version1 }, *dpb;
        !           666:                
        !           667:                dpb = dpb_buffer + 1; 
        !           668: 
        !           669:                /* loop through all the provided arguments and set dpb fields accordingly */
        !           670:                for (i = 0; i < sizeof(dpb_flags); ++i) {
        !           671:                        if (dpb_values[i] && buf_len > 0) {
        !           672:                                dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_flags[i], (unsigned char)strlen(dpb_values[i]),
        !           673:                                        dpb_values[i]);
        !           674:                                dpb += dpb_len;
        !           675:                                buf_len -= dpb_len;
        !           676:                        }
        !           677:                }
        !           678:                
        !           679:                /* fire it up baby! */
        !           680:                if (isc_attach_database(H->isc_status, 0, vars[0].optval, &H->db,(short)(dpb-dpb_buffer), dpb_buffer)) {
        !           681:                        break;
        !           682:                }
        !           683:                
        !           684:                dbh->methods = &firebird_methods;
        !           685:                dbh->native_case = PDO_CASE_UPPER;
        !           686:                dbh->alloc_own_columns = 1;
        !           687:                
        !           688:                ret = 1;
        !           689:                
        !           690:        } while (0);
        !           691:                
        !           692:        for (i = 0; i < sizeof(vars)/sizeof(vars[0]); ++i) {
        !           693:                if (vars[i].freeme) {
        !           694:                        efree(vars[i].optval);
        !           695:                }
        !           696:        }
        !           697: 
        !           698:        if (!dbh->methods) {
        !           699:                char errmsg[512];
        !           700:                ISC_STATUS *s = H->isc_status;
        !           701:                isc_interprete(errmsg, &s);
        !           702:                zend_throw_exception_ex(php_pdo_get_exception(), H->isc_status[1] TSRMLS_CC, "SQLSTATE[%s] [%d] %s",
        !           703:                                "HY000", H->isc_status[1], errmsg);
        !           704:        }
        !           705: 
        !           706:        if (!ret) {
        !           707:                firebird_handle_closer(dbh TSRMLS_CC);
        !           708:        }
        !           709: 
        !           710:        return ret;
        !           711: }
        !           712: /* }}} */
        !           713: 
        !           714: 
        !           715: pdo_driver_t pdo_firebird_driver = { /* {{{ */
        !           716:        PDO_DRIVER_HEADER(firebird),
        !           717:        pdo_firebird_handle_factory
        !           718: };
        !           719: /* }}} */
        !           720: 
        !           721: /*
        !           722:  * Local variables:
        !           723:  * tab-width: 4
        !           724:  * c-basic-offset: 4
        !           725:  * End:
        !           726:  * vim600: noet sw=4 ts=4 fdm=marker
        !           727:  * vim<600: noet sw=4 ts=4
        !           728:  */

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