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

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

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