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>