diff options
Diffstat (limited to 'ext/pdo_firebird/firebird_driver.c')
| -rw-r--r-- | ext/pdo_firebird/firebird_driver.c | 309 |
1 files changed, 309 insertions, 0 deletions
diff --git a/ext/pdo_firebird/firebird_driver.c b/ext/pdo_firebird/firebird_driver.c new file mode 100644 index 0000000000..4215b34a4c --- /dev/null +++ b/ext/pdo_firebird/firebird_driver.c @@ -0,0 +1,309 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2004 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.0 of the PHP license, | + | that is bundled with this package in the file LICENSE, and is | + | available through the world-wide-web at the following url: | + | http://www.php.net/license/3_0.txt. | + | If you did not receive a copy of the PHP license and are unable to | + | obtain it through the world-wide-web, please send a note to | + | license@php.net so we can mail you a copy immediately. | + +----------------------------------------------------------------------+ + | Author: Ard Biesheuvel <abies@php.net> | + +----------------------------------------------------------------------+ +*/ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#include "php.h" +#include "php_ini.h" +#include "ext/standard/info.h" +#include "pdo/php_pdo.h" +#include "pdo/php_pdo_driver.h" +#include "php_pdo_firebird.h" +#include "php_pdo_firebird_int.h" + +static int pdo_firebird_fetch_error_func(pdo_dbh_t *dbh, pdo_stmt_t *stmt, zval *info TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + ISC_STATUS *s = H->isc_status; + char buf[128]; + + add_next_index_long(info, isc_sqlcode(s)); + + while (isc_interprete(buf,&s)) { + add_next_index_string(info, buf, 1); + } + + return 1; +} + +static int firebird_handle_closer(pdo_dbh_t *dbh TSRMLS_DC) /* {{{ */ +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + if (dbh->in_txn) { + if (dbh->auto_commit) { + if (isc_commit_transaction(H->isc_status, &H->tr)) { + /* error */ + } + } else { + if (isc_rollback_transaction(H->isc_status, &H->tr)) { + /* error */ + } + } + } + + if (isc_detach_database(H->isc_status, &H->db)) { + /* error */ + } + + pefree(H, dbh->is_persistent); + + return 0; +} +/* }}} */ + +static int firebird_handle_preparer(pdo_dbh_t *dbh, const char *sql, long sql_len, pdo_stmt_t *stmt, + long options, zval *driver_options TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + pdo_firebird_stmt *S = NULL; + + do { + isc_stmt_handle s = NULL; + XSQLDA num_sqlda; + + num_sqlda.version = PDO_FB_SQLDA_VERSION; + num_sqlda.sqln = 1; + + /* prepare the statement */ + if (isc_dsql_prepare(H->isc_status, &H->tr, &s, (short)sql_len, /* sigh */ (char*) sql, + PDO_FB_DIALECT, &num_sqlda)) { + /* error */ + break; + } + + /* allocate a statement handle of the right size */ + S = ecalloc(1, sizeof(*S)-sizeof(XSQLDA) + XSQLDA_LENGTH(num_sqlda.sqld)); + S->H = H; + S->stmt = s; + + if (isc_dsql_describe(H->isc_status, &s, PDO_FB_SQLDA_VERSION, S->out_sqlda)) { + /* error */ + break; + } + + /* TODO what about input params */ + + stmt->driver_data = S; + stmt->methods = &firebird_stmt_methods; + + return 1; + + } while (0); + + if (S) { + efree(S); + } + + return 0; +} + +static long firebird_handle_doer(pdo_dbh_t *dbh, const char *sql, long sql_len TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + isc_stmt_handle stmt = NULL; + static char info_count[] = { isc_info_sql_records }; + char result[64]; + int ret = 0; + + if (dbh->auto_commit && !dbh->in_txn) { + if (isc_start_transaction(H->isc_status, &H->tr, 1, &H->db, 0, NULL)) { + /* error */ + return -1; + } + dbh->in_txn = 1; + } + + /* prepare */ + if (isc_dsql_prepare(H->isc_status, &H->tr, &stmt, 0, (char*) sql, PDO_FB_DIALECT, NULL)) { + /* error */ + return -1; + } + + /* execute */ + if (isc_dsql_execute2(H->isc_status, &H->tr, &stmt, PDO_FB_SQLDA_VERSION, NULL, NULL)) { + /* error */ + return -1; + } + + /* return the number of affected rows */ + if (isc_dsql_sql_info(H->isc_status, &stmt, sizeof(info_count), info_count, sizeof(result), + result)) { + /* error */ + return -1; + } + + if (result[0] == isc_info_sql_records) { + unsigned i = 3, result_size = isc_vax_integer(&result[1],2); + + while (result[i] != isc_info_end && i < result_size) { + short len = (short)isc_vax_integer(&result[i+1],2); + if (result[i] != isc_info_req_select_count) { + ret += isc_vax_integer(&result[i+3],len); + } + i += len+3; + } + } + + /* commit? */ + if (dbh->auto_commit && isc_commit_retaining(H->isc_status, &H->tr)) { + /* error */ + } + + return ret; +} + +static int firebird_handle_commit(pdo_dbh_t *dbh TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + if (isc_commit_transaction(H->isc_status, &H->tr)) { + /* error */ + return 0; + } + return 1; +} + +static int firebird_handle_rollback(pdo_dbh_t *dbh TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + if (isc_rollback_transaction(H->isc_status, &H->tr)) { + /* error */ + return 0; + } + return 1; +} + +static int firebird_handle_set_attribute(pdo_dbh_t *dbh, long attr, zval *val TSRMLS_DC) +{ + pdo_firebird_db_handle *H = (pdo_firebird_db_handle *)dbh->driver_data; + + switch (attr) { + + case PDO_ATTR_AUTOCOMMIT: + + if (dbh->in_txn) { + /* Assume they want to commit whatever is outstanding */ + if (isc_commit_retaining(H->isc_status, &H->tr)) { + /* error */ + return 0; + } + dbh->in_txn = 0; + } + + convert_to_long(val); + + dbh->auto_commit = Z_LVAL_P(val); + + return 1; + + default: + + return 0; + } +} + +static struct pdo_dbh_methods firebird_methods = { + firebird_handle_closer, + firebird_handle_preparer, + firebird_handle_doer, + NULL, + NULL, + firebird_handle_commit, + firebird_handle_rollback, + firebird_handle_set_attribute, + NULL, + pdo_firebird_fetch_error_func, +}; + +static int pdo_firebird_handle_factory(pdo_dbh_t *dbh, zval *driver_options TSRMLS_DC) /* {{{ */ +{ + struct pdo_data_src_parser vars[] = { + { "dbname", NULL, 0 }, + { "charset", NULL, 0 }, + { "role", NULL, 0 } + }; + int i, ret = 0; + pdo_firebird_db_handle *H = dbh->driver_data = pecalloc(1,sizeof(*H),dbh->is_persistent); + + php_pdo_parse_data_source(dbh->data_source, dbh->data_source_len, vars, 2); + + do { + static char const dpb_flags[] = { + isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name }; + char const *dpb_values[] = { dbh->username, dbh->password, vars[1].optval, vars[2].optval }; + char dpb_buffer[256] = { isc_dpb_version1 }, *dpb; + short len; + + dpb = dpb_buffer + 1; + + /* loop through all the provided arguments and set dpb fields accordingly */ + for (i = 0; i < sizeof(dpb_flags); ++i) { + if (dpb_values[i]) { + dpb += sprintf(dpb, "%c%c%s", dpb_flags[i], (unsigned char)strlen(dpb_values[i]), + dpb_values[i]); + } + } + + /* fire it up baby! */ + if (isc_attach_database(H->isc_status, 0, vars[0].optval, &H->db,(short)(dpb-dpb_buffer), + dpb_buffer)) { + break; + } + + dbh->methods = &firebird_methods; + dbh->alloc_own_columns = 0; + dbh->supports_placeholders = PDO_PLACEHOLDER_POSITIONAL; + dbh->native_case = PDO_CASE_UPPER; + + ret = 1; + + } while (0); + + for (i = 0; i < sizeof(vars)/sizeof(vars[0]); ++i) { + if (vars[i].freeme) { + efree(vars[i].optval); + } + } + + if (!ret) { + firebird_handle_closer(dbh TSRMLS_CC); + } + + return ret; +} +/* }}} */ + +pdo_driver_t pdo_firebird_driver = { + PDO_DRIVER_HEADER(firebird), + pdo_firebird_handle_factory +}; + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: noet sw=4 ts=4 fdm=marker + * vim<600: noet sw=4 ts=4 + */ |
