diff options
author | Lorry Tar Creator <lorry-tar-importer@baserock.org> | 2013-03-14 05:42:27 +0000 |
---|---|---|
committer | <> | 2013-04-03 16:25:08 +0000 |
commit | c4dd7a1a684490673e25aaf4fabec5df138854c4 (patch) | |
tree | 4d57c44caae4480efff02b90b9be86f44bf25409 /ext/interbase/interbase.c | |
download | php2-master.tar.gz |
Imported from /home/lorry/working-area/delta_php2/php-5.4.13.tar.bz2.HEADphp-5.4.13master
Diffstat (limited to 'ext/interbase/interbase.c')
-rw-r--r-- | ext/interbase/interbase.c | 1482 |
1 files changed, 1482 insertions, 0 deletions
diff --git a/ext/interbase/interbase.c b/ext/interbase/interbase.c new file mode 100644 index 0000000..132ad35 --- /dev/null +++ b/ext/interbase/interbase.c @@ -0,0 +1,1482 @@ +/* + +----------------------------------------------------------------------+ + | PHP Version 5 | + +----------------------------------------------------------------------+ + | Copyright (c) 1997-2013 The PHP Group | + +----------------------------------------------------------------------+ + | This source file is subject to version 3.01 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_01.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. | + +----------------------------------------------------------------------+ + | Authors: Jouni Ahto <jouni.ahto@exdec.fi> | + | Andrew Avdeev <andy@rsc.mv.ru> | + | Ard Biesheuvel <a.k.biesheuvel@ewi.tudelft.nl> | + +----------------------------------------------------------------------+ + */ + +/* $Id$ */ + +#ifdef HAVE_CONFIG_H +#include "config.h" +#endif + +#define _GNU_SOURCE + +#include "php.h" + +#if HAVE_IBASE + +#include "php_ini.h" +#include "ext/standard/php_standard.h" +#include "ext/standard/md5.h" +#include "php_interbase.h" +#include "php_ibase_includes.h" +#include "SAPI.h" + +#include <time.h> + +#define ROLLBACK 0 +#define COMMIT 1 +#define RETAIN 2 + +#define CHECK_LINK(link) { if (link==-1) { php_error_docref(NULL TSRMLS_CC, E_WARNING, "A link to the server could not be established"); RETURN_FALSE; } } + +ZEND_DECLARE_MODULE_GLOBALS(ibase) +static PHP_GINIT_FUNCTION(ibase); + +/* {{{ arginfo */ +ZEND_BEGIN_ARG_INFO(arginfo_ibase_errmsg, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO(arginfo_ibase_errcode, 0) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_connect, 0, 0, 1) + ZEND_ARG_INFO(0, database) + ZEND_ARG_INFO(0, username) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, charset) + ZEND_ARG_INFO(0, buffers) + ZEND_ARG_INFO(0, dialect) + ZEND_ARG_INFO(0, role) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_pconnect, 0, 0, 1) + ZEND_ARG_INFO(0, database) + ZEND_ARG_INFO(0, username) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, charset) + ZEND_ARG_INFO(0, buffers) + ZEND_ARG_INFO(0, dialect) + ZEND_ARG_INFO(0, role) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_close, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_drop_db, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_trans, 0, 0, 0) + ZEND_ARG_INFO(0, trans_args) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, trans_args) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_commit, 0, 0, 1) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_rollback, 0, 0, 1) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_commit_ret, 0, 0, 1) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_rollback_ret, 0, 0, 1) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_gen_id, 0, 0, 1) + ZEND_ARG_INFO(0, generator) + ZEND_ARG_INFO(0, increment) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_create, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_open, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, blob_id) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_add, 0, 0, 2) + ZEND_ARG_INFO(0, blob_handle) + ZEND_ARG_INFO(0, data) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_get, 0, 0, 2) + ZEND_ARG_INFO(0, blob_handle) + ZEND_ARG_INFO(0, len) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_close, 0, 0, 1) + ZEND_ARG_INFO(0, blob_handle) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_cancel, 0, 0, 1) + ZEND_ARG_INFO(0, blob_handle) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_info, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, blob_id) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_echo, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, blob_id) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_blob_import, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, file) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_query, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, query) + ZEND_ARG_INFO(0, bind_arg) + ZEND_ARG_INFO(0, bind_arg) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_affected_rows, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) +ZEND_END_ARG_INFO() + +#if abies_0 +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_num_rows, 0, 0, 1) + ZEND_ARG_INFO(0, result_identifier) +ZEND_END_ARG_INFO() +#endif + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_fetch_row, 0, 0, 1) + ZEND_ARG_INFO(0, result) + ZEND_ARG_INFO(0, fetch_flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_fetch_assoc, 0, 0, 1) + ZEND_ARG_INFO(0, result) + ZEND_ARG_INFO(0, fetch_flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_fetch_object, 0, 0, 1) + ZEND_ARG_INFO(0, result) + ZEND_ARG_INFO(0, fetch_flags) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_name_result, 0, 0, 2) + ZEND_ARG_INFO(0, result) + ZEND_ARG_INFO(0, name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_free_result, 0, 0, 1) + ZEND_ARG_INFO(0, result) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_prepare, 0, 0, 0) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, query) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_execute, 0, 0, 1) + ZEND_ARG_INFO(0, query) + ZEND_ARG_INFO(0, bind_arg) + ZEND_ARG_INFO(0, bind_arg) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_free_query, 0, 0, 1) + ZEND_ARG_INFO(0, query) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_num_fields, 0, 0, 1) + ZEND_ARG_INFO(0, query_result) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_field_info, 0, 0, 2) + ZEND_ARG_INFO(0, query_result) + ZEND_ARG_INFO(0, field_number) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_num_params, 0, 0, 1) + ZEND_ARG_INFO(0, query) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_param_info, 0, 0, 2) + ZEND_ARG_INFO(0, query) + ZEND_ARG_INFO(0, field_number) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_add_user, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, user_name) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, first_name) + ZEND_ARG_INFO(0, middle_name) + ZEND_ARG_INFO(0, last_name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_modify_user, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, user_name) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, first_name) + ZEND_ARG_INFO(0, middle_name) + ZEND_ARG_INFO(0, last_name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_delete_user, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, user_name) + ZEND_ARG_INFO(0, password) + ZEND_ARG_INFO(0, first_name) + ZEND_ARG_INFO(0, middle_name) + ZEND_ARG_INFO(0, last_name) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_service_attach, 0, 0, 3) + ZEND_ARG_INFO(0, host) + ZEND_ARG_INFO(0, dba_username) + ZEND_ARG_INFO(0, dba_password) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_service_detach, 0, 0, 1) + ZEND_ARG_INFO(0, service_handle) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_backup, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, source_db) + ZEND_ARG_INFO(0, dest_file) + ZEND_ARG_INFO(0, options) + ZEND_ARG_INFO(0, verbose) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_restore, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, source_file) + ZEND_ARG_INFO(0, dest_db) + ZEND_ARG_INFO(0, options) + ZEND_ARG_INFO(0, verbose) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_maintain_db, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, db) + ZEND_ARG_INFO(0, action) + ZEND_ARG_INFO(0, argument) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_db_info, 0, 0, 3) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, db) + ZEND_ARG_INFO(0, action) + ZEND_ARG_INFO(0, argument) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_server_info, 0, 0, 2) + ZEND_ARG_INFO(0, service_handle) + ZEND_ARG_INFO(0, action) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_wait_event, 0, 0, 1) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, event) + ZEND_ARG_INFO(0, event2) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_set_event_handler, 0, 0, 2) + ZEND_ARG_INFO(0, link_identifier) + ZEND_ARG_INFO(0, handler) + ZEND_ARG_INFO(0, event) + ZEND_ARG_INFO(0, event2) +ZEND_END_ARG_INFO() + +ZEND_BEGIN_ARG_INFO_EX(arginfo_ibase_free_event_handler, 0, 0, 1) + ZEND_ARG_INFO(0, event) +ZEND_END_ARG_INFO() +/* }}} */ + +/* {{{ extension definition structures */ +const zend_function_entry ibase_functions[] = { + PHP_FE(ibase_connect, arginfo_ibase_connect) + PHP_FE(ibase_pconnect, arginfo_ibase_pconnect) + PHP_FE(ibase_close, arginfo_ibase_close) + PHP_FE(ibase_drop_db, arginfo_ibase_drop_db) + PHP_FE(ibase_query, arginfo_ibase_query) + PHP_FE(ibase_fetch_row, arginfo_ibase_fetch_row) + PHP_FE(ibase_fetch_assoc, arginfo_ibase_fetch_assoc) + PHP_FE(ibase_fetch_object, arginfo_ibase_fetch_object) + PHP_FE(ibase_free_result, arginfo_ibase_free_result) + PHP_FE(ibase_name_result, arginfo_ibase_name_result) + PHP_FE(ibase_prepare, arginfo_ibase_prepare) + PHP_FE(ibase_execute, arginfo_ibase_execute) + PHP_FE(ibase_free_query, arginfo_ibase_free_query) + PHP_FE(ibase_gen_id, arginfo_ibase_gen_id) + PHP_FE(ibase_num_fields, arginfo_ibase_num_fields) + PHP_FE(ibase_num_params, arginfo_ibase_num_params) +#if abies_0 + PHP_FE(ibase_num_rows, arginfo_ibase_num_rows) +#endif + PHP_FE(ibase_affected_rows, arginfo_ibase_affected_rows) + PHP_FE(ibase_field_info, arginfo_ibase_field_info) + PHP_FE(ibase_param_info, arginfo_ibase_param_info) + + PHP_FE(ibase_trans, arginfo_ibase_trans) + PHP_FE(ibase_commit, arginfo_ibase_commit) + PHP_FE(ibase_rollback, arginfo_ibase_rollback) + PHP_FE(ibase_commit_ret, arginfo_ibase_commit_ret) + PHP_FE(ibase_rollback_ret, arginfo_ibase_rollback_ret) + + PHP_FE(ibase_blob_info, arginfo_ibase_blob_info) + PHP_FE(ibase_blob_create, arginfo_ibase_blob_create) + PHP_FE(ibase_blob_add, arginfo_ibase_blob_add) + PHP_FE(ibase_blob_cancel, arginfo_ibase_blob_cancel) + PHP_FE(ibase_blob_close, arginfo_ibase_blob_close) + PHP_FE(ibase_blob_open, arginfo_ibase_blob_open) + PHP_FE(ibase_blob_get, arginfo_ibase_blob_get) + PHP_FE(ibase_blob_echo, arginfo_ibase_blob_echo) + PHP_FE(ibase_blob_import, arginfo_ibase_blob_import) + PHP_FE(ibase_errmsg, arginfo_ibase_errmsg) + PHP_FE(ibase_errcode, arginfo_ibase_errcode) + + PHP_FE(ibase_add_user, arginfo_ibase_add_user) + PHP_FE(ibase_modify_user, arginfo_ibase_modify_user) + PHP_FE(ibase_delete_user, arginfo_ibase_delete_user) + + PHP_FE(ibase_service_attach, arginfo_ibase_service_attach) + PHP_FE(ibase_service_detach, arginfo_ibase_service_detach) + PHP_FE(ibase_backup, arginfo_ibase_backup) + PHP_FE(ibase_restore, arginfo_ibase_restore) + PHP_FE(ibase_maintain_db, arginfo_ibase_maintain_db) + PHP_FE(ibase_db_info, arginfo_ibase_db_info) + PHP_FE(ibase_server_info, arginfo_ibase_server_info) + + PHP_FE(ibase_wait_event, arginfo_ibase_wait_event) + PHP_FE(ibase_set_event_handler, arginfo_ibase_set_event_handler) + PHP_FE(ibase_free_event_handler, arginfo_ibase_free_event_handler) + + /** + * These aliases are provided in order to maintain forward compatibility. As Firebird + * and InterBase are developed independently, functionality might be different between + * the two branches in future versions. + * Firebird users should use the aliases, so future InterBase-specific changes will + * not affect their code + */ + PHP_FALIAS(fbird_connect, ibase_connect, arginfo_ibase_connect) + PHP_FALIAS(fbird_pconnect, ibase_pconnect, arginfo_ibase_pconnect) + PHP_FALIAS(fbird_close, ibase_close, arginfo_ibase_close) + PHP_FALIAS(fbird_drop_db, ibase_drop_db, arginfo_ibase_drop_db) + PHP_FALIAS(fbird_query, ibase_query, arginfo_ibase_query) + PHP_FALIAS(fbird_fetch_row, ibase_fetch_row, arginfo_ibase_fetch_row) + PHP_FALIAS(fbird_fetch_assoc, ibase_fetch_assoc, arginfo_ibase_fetch_assoc) + PHP_FALIAS(fbird_fetch_object, ibase_fetch_object, arginfo_ibase_fetch_object) + PHP_FALIAS(fbird_free_result, ibase_free_result, arginfo_ibase_free_result) + PHP_FALIAS(fbird_name_result, ibase_name_result, arginfo_ibase_name_result) + PHP_FALIAS(fbird_prepare, ibase_prepare, arginfo_ibase_prepare) + PHP_FALIAS(fbird_execute, ibase_execute, arginfo_ibase_execute) + PHP_FALIAS(fbird_free_query, ibase_free_query, arginfo_ibase_free_query) + PHP_FALIAS(fbird_gen_id, ibase_gen_id, arginfo_ibase_gen_id) + PHP_FALIAS(fbird_num_fields, ibase_num_fields, arginfo_ibase_num_fields) + PHP_FALIAS(fbird_num_params, ibase_num_params, arginfo_ibase_num_params) +#if abies_0 + PHP_FALIAS(fbird_num_rows, ibase_num_rows, arginfo_ibase_num_rows) +#endif + PHP_FALIAS(fbird_affected_rows, ibase_affected_rows, arginfo_ibase_affected_rows) + PHP_FALIAS(fbird_field_info, ibase_field_info, arginfo_ibase_field_info) + PHP_FALIAS(fbird_param_info, ibase_param_info, arginfo_ibase_param_info) + + PHP_FALIAS(fbird_trans, ibase_trans, arginfo_ibase_trans) + PHP_FALIAS(fbird_commit, ibase_commit, arginfo_ibase_commit) + PHP_FALIAS(fbird_rollback, ibase_rollback, arginfo_ibase_rollback) + PHP_FALIAS(fbird_commit_ret, ibase_commit_ret, arginfo_ibase_commit_ret) + PHP_FALIAS(fbird_rollback_ret, ibase_rollback_ret, arginfo_ibase_rollback_ret) + + PHP_FALIAS(fbird_blob_info, ibase_blob_info, arginfo_ibase_blob_info) + PHP_FALIAS(fbird_blob_create, ibase_blob_create, arginfo_ibase_blob_create) + PHP_FALIAS(fbird_blob_add, ibase_blob_add, arginfo_ibase_blob_add) + PHP_FALIAS(fbird_blob_cancel, ibase_blob_cancel, arginfo_ibase_blob_cancel) + PHP_FALIAS(fbird_blob_close, ibase_blob_close, arginfo_ibase_blob_close) + PHP_FALIAS(fbird_blob_open, ibase_blob_open, arginfo_ibase_blob_open) + PHP_FALIAS(fbird_blob_get, ibase_blob_get, arginfo_ibase_blob_get) + PHP_FALIAS(fbird_blob_echo, ibase_blob_echo, arginfo_ibase_blob_echo) + PHP_FALIAS(fbird_blob_import, ibase_blob_import, arginfo_ibase_blob_import) + PHP_FALIAS(fbird_errmsg, ibase_errmsg, arginfo_ibase_errmsg) + PHP_FALIAS(fbird_errcode, ibase_errcode, arginfo_ibase_errcode) + + PHP_FALIAS(fbird_add_user, ibase_add_user, arginfo_ibase_add_user) + PHP_FALIAS(fbird_modify_user, ibase_modify_user, arginfo_ibase_modify_user) + PHP_FALIAS(fbird_delete_user, ibase_delete_user, arginfo_ibase_delete_user) + + PHP_FALIAS(fbird_service_attach, ibase_service_attach, arginfo_ibase_service_attach) + PHP_FALIAS(fbird_service_detach, ibase_service_detach, arginfo_ibase_service_detach) + PHP_FALIAS(fbird_backup, ibase_backup, arginfo_ibase_backup) + PHP_FALIAS(fbird_restore, ibase_restore, arginfo_ibase_restore) + PHP_FALIAS(fbird_maintain_db, ibase_maintain_db, arginfo_ibase_maintain_db) + PHP_FALIAS(fbird_db_info, ibase_db_info, arginfo_ibase_db_info) + PHP_FALIAS(fbird_server_info, ibase_server_info, arginfo_ibase_server_info) + + PHP_FALIAS(fbird_wait_event, ibase_wait_event, arginfo_ibase_wait_event) + PHP_FALIAS(fbird_set_event_handler, ibase_set_event_handler, arginfo_ibase_set_event_handler) + PHP_FALIAS(fbird_free_event_handler, ibase_free_event_handler, arginfo_ibase_free_event_handler) + PHP_FE_END +}; + +zend_module_entry ibase_module_entry = { + STANDARD_MODULE_HEADER, + "interbase", + ibase_functions, + PHP_MINIT(ibase), + PHP_MSHUTDOWN(ibase), + NULL, + PHP_RSHUTDOWN(ibase), + PHP_MINFO(ibase), + NO_VERSION_YET, + PHP_MODULE_GLOBALS(ibase), + PHP_GINIT(ibase), + NULL, + NULL, + STANDARD_MODULE_PROPERTIES_EX +}; + +#ifdef COMPILE_DL_INTERBASE +ZEND_GET_MODULE(ibase) +#endif + +/* True globals, no need for thread safety */ +int le_link, le_plink, le_trans; + +/* }}} */ + +/* error handling ---------------------------- */ + +/* {{{ proto string ibase_errmsg(void) + Return error message */ +PHP_FUNCTION(ibase_errmsg) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (IBG(sql_code) != 0) { + RETURN_STRING(IBG(errmsg), 1); + } + + RETURN_FALSE; +} +/* }}} */ + +/* {{{ proto int ibase_errcode(void) + Return error code */ +PHP_FUNCTION(ibase_errcode) +{ + if (zend_parse_parameters_none() == FAILURE) { + return; + } + + if (IBG(sql_code) != 0) { + RETURN_LONG(IBG(sql_code)); + } + RETURN_FALSE; +} +/* }}} */ + +/* print interbase error and save it for ibase_errmsg() */ +void _php_ibase_error(TSRMLS_D) /* {{{ */ +{ + char *s = IBG(errmsg); + ISC_STATUS *statusp = IB_STATUS; + + IBG(sql_code) = isc_sqlcode(IB_STATUS); + + while ((s - IBG(errmsg)) < MAX_ERRMSG - (IBASE_MSGSIZE + 2) && isc_interprete(s, &statusp)) { + strcat(IBG(errmsg), " "); + s = IBG(errmsg) + strlen(IBG(errmsg)); + } + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg)); +} +/* }}} */ + +/* print php interbase module error and save it for ibase_errmsg() */ +void _php_ibase_module_error(char *msg TSRMLS_DC, ...) /* {{{ */ +{ + va_list ap; + +#ifdef ZTS + va_start(ap, TSRMLS_C); +#else + va_start(ap, msg); +#endif + + /* vsnprintf NUL terminates the buf and writes at most n-1 chars+NUL */ + vsnprintf(IBG(errmsg), MAX_ERRMSG, msg, ap); + va_end(ap); + + IBG(sql_code) = -999; /* no SQL error */ + + php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", IBG(errmsg)); +} +/* }}} */ + +/* {{{ internal macros, functions and structures */ +typedef struct { + isc_db_handle *db_ptr; + long tpb_len; + char *tpb_ptr; +} ISC_TEB; + +/* }}} */ + +/* Fill ib_link and trans with the correct database link and transaction. */ +void _php_ibase_get_link_trans(INTERNAL_FUNCTION_PARAMETERS, /* {{{ */ + zval **link_id, ibase_db_link **ib_link, ibase_trans **trans) +{ + int type; + + IBDEBUG("Transaction or database link?"); + if (zend_list_find(Z_LVAL_PP(link_id), &type)) { + if (type == le_trans) { + /* Transaction resource: make sure it refers to one link only, then + fetch it; database link is stored in ib_trans->db_link[]. */ + IBDEBUG("Type is le_trans"); + ZEND_FETCH_RESOURCE(*trans, ibase_trans *, link_id, -1, LE_TRANS, le_trans); + if ((*trans)->link_cnt > 1) { + _php_ibase_module_error("Link id is ambiguous: transaction spans multiple connections." + TSRMLS_CC); + return; + } + *ib_link = (*trans)->db_link[0]; + return; + } + } + IBDEBUG("Type is le_[p]link or id not found"); + /* Database link resource, use default transaction. */ + *trans = NULL; + ZEND_FETCH_RESOURCE2(*ib_link, ibase_db_link *, link_id, -1, LE_LINK, le_link, le_plink); +} +/* }}} */ + +/* destructors ---------------------- */ + +static void _php_ibase_commit_link(ibase_db_link *link TSRMLS_DC) /* {{{ */ +{ + unsigned short i = 0, j; + ibase_tr_list *l; + ibase_event *e; + IBDEBUG("Checking transactions to close..."); + + for (l = link->tr_list; l != NULL; ++i) { + ibase_tr_list *p = l; + if (p->trans != NULL) { + if (i == 0) { + if (p->trans->handle != NULL) { + IBDEBUG("Committing default transaction..."); + if (isc_commit_transaction(IB_STATUS, &p->trans->handle)) { + _php_ibase_error(TSRMLS_C); + } + } + efree(p->trans); /* default transaction is not a registered resource: clean up */ + } else { + if (p->trans->handle != NULL) { + /* non-default trans might have been rolled back by other call of this dtor */ + IBDEBUG("Rolling back other transactions..."); + if (isc_rollback_transaction(IB_STATUS, &p->trans->handle)) { + _php_ibase_error(TSRMLS_C); + } + } + /* set this link pointer to NULL in the transaction */ + for (j = 0; j < p->trans->link_cnt; ++j) { + if (p->trans->db_link[j] == link) { + p->trans->db_link[j] = NULL; + break; + } + } + } + } + l = l->next; + efree(p); + } + link->tr_list = NULL; + + for (e = link->event_head; e; e = e->event_next) { + _php_ibase_free_event(e TSRMLS_CC); + e->link = NULL; + } +} + +/* }}} */ + +static void php_ibase_commit_link_rsrc(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_db_link *link = (ibase_db_link *) rsrc->ptr; + + _php_ibase_commit_link(link TSRMLS_CC); +} +/* }}} */ + +static void _php_ibase_close_link(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_db_link *link = (ibase_db_link *) rsrc->ptr; + + _php_ibase_commit_link(link TSRMLS_CC); + if (link->handle != NULL) { + IBDEBUG("Closing normal link..."); + isc_detach_database(IB_STATUS, &link->handle); + } + IBG(num_links)--; + efree(link); +} +/* }}} */ + +static void _php_ibase_close_plink(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_db_link *link = (ibase_db_link *) rsrc->ptr; + + _php_ibase_commit_link(link TSRMLS_CC); + IBDEBUG("Closing permanent link..."); + if (link->handle != NULL) { + isc_detach_database(IB_STATUS, &link->handle); + } + IBG(num_persistent)--; + IBG(num_links)--; + free(link); +} +/* }}} */ + +static void _php_ibase_free_trans(zend_rsrc_list_entry *rsrc TSRMLS_DC) /* {{{ */ +{ + ibase_trans *trans = (ibase_trans *)rsrc->ptr; + unsigned short i; + + IBDEBUG("Cleaning up transaction resource..."); + if (trans->handle != NULL) { + IBDEBUG("Rolling back unhandled transaction..."); + if (isc_rollback_transaction(IB_STATUS, &trans->handle)) { + _php_ibase_error(TSRMLS_C); + } + } + + /* now remove this transaction from all the connection-transaction lists */ + for (i = 0; i < trans->link_cnt; ++i) { + if (trans->db_link[i] != NULL) { + ibase_tr_list **l; + for (l = &trans->db_link[i]->tr_list; *l != NULL; l = &(*l)->next) { + if ( (*l)->trans == trans) { + ibase_tr_list *p = *l; + *l = p->next; + efree(p); + break; + } + } + } + } + efree(trans); +} +/* }}} */ + +/* TODO this function should be part of either Zend or PHP API */ +static PHP_INI_DISP(php_ibase_password_displayer_cb) +{ + TSRMLS_FETCH(); + + if ((type == PHP_INI_DISPLAY_ORIG && ini_entry->orig_value) + || (type == PHP_INI_DISPLAY_ACTIVE && ini_entry->value)) { + PUTS("********"); + } else if (!sapi_module.phpinfo_as_text) { + PUTS("<i>no value</i>"); + } else { + PUTS("no value"); + } +} + +/* {{{ startup, shutdown and info functions */ +PHP_INI_BEGIN() + PHP_INI_ENTRY_EX("ibase.allow_persistent", "1", PHP_INI_SYSTEM, NULL, zend_ini_boolean_displayer_cb) + PHP_INI_ENTRY_EX("ibase.max_persistent", "-1", PHP_INI_SYSTEM, NULL, display_link_numbers) + PHP_INI_ENTRY_EX("ibase.max_links", "-1", PHP_INI_SYSTEM, NULL, display_link_numbers) + PHP_INI_ENTRY("ibase.default_db", NULL, PHP_INI_SYSTEM, NULL) + PHP_INI_ENTRY("ibase.default_user", NULL, PHP_INI_ALL, NULL) + PHP_INI_ENTRY_EX("ibase.default_password", NULL, PHP_INI_ALL, NULL, php_ibase_password_displayer_cb) + PHP_INI_ENTRY("ibase.default_charset", NULL, PHP_INI_ALL, NULL) + PHP_INI_ENTRY("ibase.timestampformat", IB_DEF_DATE_FMT " " IB_DEF_TIME_FMT, PHP_INI_ALL, NULL) + PHP_INI_ENTRY("ibase.dateformat", IB_DEF_DATE_FMT, PHP_INI_ALL, NULL) + PHP_INI_ENTRY("ibase.timeformat", IB_DEF_TIME_FMT, PHP_INI_ALL, NULL) +PHP_INI_END() + +static PHP_GINIT_FUNCTION(ibase) +{ + ibase_globals->num_persistent = ibase_globals->num_links = 0; + ibase_globals->sql_code = *ibase_globals->errmsg = 0; + ibase_globals->default_link = -1; +} + +PHP_MINIT_FUNCTION(ibase) +{ + REGISTER_INI_ENTRIES(); + + le_link = zend_register_list_destructors_ex(_php_ibase_close_link, NULL, LE_LINK, module_number); + le_plink = zend_register_list_destructors_ex(php_ibase_commit_link_rsrc, _php_ibase_close_plink, LE_PLINK, module_number); + le_trans = zend_register_list_destructors_ex(_php_ibase_free_trans, NULL, LE_TRANS, module_number); + + REGISTER_LONG_CONSTANT("IBASE_DEFAULT", PHP_IBASE_DEFAULT, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_CREATE", PHP_IBASE_CREATE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_TEXT", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT); /* deprecated, for BC only */ + REGISTER_LONG_CONSTANT("IBASE_FETCH_BLOBS", PHP_IBASE_FETCH_BLOBS, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_FETCH_ARRAYS", PHP_IBASE_FETCH_ARRAYS, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_UNIXTIME", PHP_IBASE_UNIXTIME, CONST_PERSISTENT); + + /* transactions */ + REGISTER_LONG_CONSTANT("IBASE_WRITE", PHP_IBASE_WRITE, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_READ", PHP_IBASE_READ, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_COMMITTED", PHP_IBASE_COMMITTED, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_CONSISTENCY", PHP_IBASE_CONSISTENCY, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_CONCURRENCY", PHP_IBASE_CONCURRENCY, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_REC_VERSION", PHP_IBASE_REC_VERSION, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_REC_NO_VERSION", PHP_IBASE_REC_NO_VERSION, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_NOWAIT", PHP_IBASE_NOWAIT, CONST_PERSISTENT); + REGISTER_LONG_CONSTANT("IBASE_WAIT", PHP_IBASE_WAIT, CONST_PERSISTENT); + + php_ibase_query_minit(INIT_FUNC_ARGS_PASSTHRU); + php_ibase_blobs_minit(INIT_FUNC_ARGS_PASSTHRU); + php_ibase_events_minit(INIT_FUNC_ARGS_PASSTHRU); + php_ibase_service_minit(INIT_FUNC_ARGS_PASSTHRU); + + return SUCCESS; +} + +PHP_MSHUTDOWN_FUNCTION(ibase) +{ +#ifndef PHP_WIN32 + /** + * When the Interbase client API library libgds.so is first loaded, it registers a call to + * gds__cleanup() with atexit(), in order to clean up after itself when the process exits. + * This means that the library is called at process shutdown, and cannot be unloaded beforehand. + * PHP tries to unload modules after every request [dl()'ed modules], and right before the + * process shuts down [modules loaded from php.ini]. This results in a segfault for this module. + * By NULLing the dlopen() handle in the module entry, Zend omits the call to dlclose(), + * ensuring that the module will remain present until the process exits. However, the functions + * and classes exported by the module will not be available until the module is 'reloaded'. + * When reloaded, dlopen() will return the handle of the already loaded module. The module will + * be unloaded automatically when the process exits. + */ + zend_module_entry *ibase_entry; + if (SUCCESS == zend_hash_find(&module_registry, ibase_module_entry.name, + strlen(ibase_module_entry.name) +1, (void*) &ibase_entry)) { + ibase_entry->handle = NULL; + } +#endif + UNREGISTER_INI_ENTRIES(); + return SUCCESS; +} + +PHP_RSHUTDOWN_FUNCTION(ibase) +{ + IBG(num_links) = IBG(num_persistent); + IBG(default_link)= -1; + + RESET_ERRMSG; + + return SUCCESS; +} + +PHP_MINFO_FUNCTION(ibase) +{ + char tmp[64], *s; + + php_info_print_table_start(); + php_info_print_table_row(2, "Firebird/InterBase Support", +#ifdef COMPILE_DL_INTERBASE + "dynamic"); +#else + "static"); +#endif + +#ifdef FB_API_VER + snprintf( (s = tmp), sizeof(tmp), "Firebird API version %d", FB_API_VER); +#elif (SQLDA_CURRENT_VERSION > 1) + s = "Interbase 7.0 and up"; +#elif !defined(DSC_null) + s = "Interbase 6"; +#else + s = "Firebird 1.0"; +#endif + php_info_print_table_row(2, "Compile-time Client Library Version", s); + +#if defined(__GNUC__) || defined(PHP_WIN32) + do { + info_func_t info_func = NULL; +#ifdef __GNUC__ + info_func = (info_func_t)dlsym(RTLD_DEFAULT, "isc_get_client_version"); +#else + HMODULE l = GetModuleHandle("fbclient"); + + if (!l && !(l = GetModuleHandle("gds32"))) { + break; + } + info_func = (info_func_t)GetProcAddress(l, "isc_get_client_version"); +#endif + if (info_func) { + info_func(s = tmp); + } else { + s = "Firebird 1.0/Interbase 6"; + } + php_info_print_table_row(2, "Run-time Client Library Version", s); + } while (0); +#endif + php_info_print_table_end(); + + DISPLAY_INI_ENTRIES(); + +} +/* }}} */ + +enum connect_args { DB = 0, USER = 1, PASS = 2, CSET = 3, ROLE = 4, BUF = 0, DLECT = 1, SYNC = 2 }; + +static char const dpb_args[] = { + 0, isc_dpb_user_name, isc_dpb_password, isc_dpb_lc_ctype, isc_dpb_sql_role_name, 0 +}; + +int _php_ibase_attach_db(char **args, int *len, long *largs, isc_db_handle *db TSRMLS_DC) +{ + short i, dpb_len, buf_len = 257-2; /* version byte at the front, and a null at the end */ + char dpb_buffer[257] = { isc_dpb_version1, 0 }, *dpb; + + dpb = dpb_buffer + 1; + + for (i = 0; i < sizeof(dpb_args); ++i) { + if (dpb_args[i] && args[i] && len[i] && buf_len > 0) { + dpb_len = slprintf(dpb, buf_len, "%c%c%s", dpb_args[i],(unsigned char)len[i],args[i]); + dpb += dpb_len; + buf_len -= dpb_len; + } + } + if (largs[BUF] && buf_len > 0) { + dpb_len = slprintf(dpb, buf_len, "%c\2%c%c", isc_dpb_num_buffers, + (char)(largs[BUF] >> 8), (char)(largs[BUF] & 0xff)); + dpb += dpb_len; + buf_len -= dpb_len; + } + if (largs[SYNC] && buf_len > 0) { + dpb_len = slprintf(dpb, buf_len, "%c\1%c", isc_dpb_force_write, largs[SYNC] == isc_spb_prp_wm_sync ? 1 : 0); + dpb += dpb_len; + buf_len -= dpb_len; + } + if (isc_attach_database(IB_STATUS, (short)len[DB], args[DB], db, (short)(dpb-dpb_buffer), dpb_buffer)) { + _php_ibase_error(TSRMLS_C); + return FAILURE; + } + return SUCCESS; +} +/* }}} */ + +static void _php_ibase_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent) /* {{{ */ +{ + char *c, hash[16], *args[] = { NULL, NULL, NULL, NULL, NULL }; + int i, len[] = { 0, 0, 0, 0, 0 }; + long largs[] = { 0, 0, 0 }; + PHP_MD5_CTX hash_context; + zend_rsrc_list_entry new_index_ptr, *le; + isc_db_handle db_handle = NULL; + ibase_db_link *ib_link; + + RESET_ERRMSG; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ssssllsl", + &args[DB], &len[DB], &args[USER], &len[USER], &args[PASS], &len[PASS], + &args[CSET], &len[CSET], &largs[BUF], &largs[DLECT], &args[ROLE], &len[ROLE], + &largs[SYNC])) { + RETURN_FALSE; + } + + /* restrict to the server/db in the .ini if in safe mode */ + if ((!len[DB] || PG(sql_safe_mode)) && (c = INI_STR("ibase.default_db"))) { + args[DB] = c; + len[DB] = strlen(c); + } + if (!len[USER] && (c = INI_STR("ibase.default_user"))) { + args[USER] = c; + len[USER] = strlen(c); + } + if (!len[PASS] && (c = INI_STR("ibase.default_password"))) { + args[PASS] = c; + len[PASS] = strlen(c); + } + if (!len[CSET] && (c = INI_STR("ibase.default_charset"))) { + args[CSET] = c; + len[CSET] = strlen(c); + } + + /* don't want usernames and passwords floating around */ + PHP_MD5Init(&hash_context); + for (i = 0; i < sizeof(args)/sizeof(char*); ++i) { + PHP_MD5Update(&hash_context,args[i],len[i]); + } + for (i = 0; i < sizeof(largs)/sizeof(long); ++i) { + PHP_MD5Update(&hash_context,(char*)&largs[i],sizeof(long)); + } + PHP_MD5Final(hash, &hash_context); + + /* try to reuse a connection */ + if (SUCCESS == zend_hash_find(&EG(regular_list), hash, sizeof(hash), (void *) &le)) { + long xlink; + int type; + + if (Z_TYPE_P(le) != le_index_ptr) { + RETURN_FALSE; + } + + xlink = (long) le->ptr; + if (zend_list_find(xlink, &type) && ((!persistent && type == le_link) || type == le_plink)) { + zend_list_addref(xlink); + RETURN_RESOURCE(IBG(default_link) = xlink); + } else { + zend_hash_del(&EG(regular_list), hash, sizeof(hash)); + } + } + + /* ... or a persistent one */ + switch (zend_hash_find(&EG(persistent_list), hash, sizeof(hash), (void *) &le)) { + long l; + + static char info[] = { isc_info_base_level, isc_info_end }; + char result[8]; + ISC_STATUS status[20]; + + case SUCCESS: + + if (Z_TYPE_P(le) != le_plink) { + RETURN_FALSE; + } + /* check if connection has timed out */ + ib_link = (ibase_db_link *) le->ptr; + if (!isc_database_info(status, &ib_link->handle, sizeof(info), info, sizeof(result), result)) { + ZEND_REGISTER_RESOURCE(return_value, ib_link, le_plink); + break; + } + zend_hash_del(&EG(persistent_list), hash, sizeof(hash)); + + default: + + /* no link found, so we have to open one */ + + if ((l = INI_INT("ibase.max_links")) != -1 && IBG(num_links) >= l) { + _php_ibase_module_error("Too many open links (%ld)" TSRMLS_CC, IBG(num_links)); + RETURN_FALSE; + } + + /* create the ib_link */ + if (FAILURE == _php_ibase_attach_db(args, len, largs, &db_handle TSRMLS_CC)) { + RETURN_FALSE; + } + + /* use non-persistent if allowed number of persistent links is exceeded */ + if (!persistent || ((l = INI_INT("ibase.max_persistent") != -1) && IBG(num_persistent) >= l)) { + ib_link = (ibase_db_link *) emalloc(sizeof(ibase_db_link)); + ZEND_REGISTER_RESOURCE(return_value, ib_link, le_link); + } else { + zend_rsrc_list_entry new_le; + + ib_link = (ibase_db_link *) malloc(sizeof(ibase_db_link)); + if (!ib_link) { + RETURN_FALSE; + } + + /* hash it up */ + Z_TYPE(new_le) = le_plink; + new_le.ptr = ib_link; + if (FAILURE == zend_hash_update(&EG(persistent_list), hash, sizeof(hash), + (void *) &new_le, sizeof(zend_rsrc_list_entry), NULL)) { + free(ib_link); + RETURN_FALSE; + } + ZEND_REGISTER_RESOURCE(return_value, ib_link, le_plink); + ++IBG(num_persistent); + } + ib_link->handle = db_handle; + ib_link->dialect = largs[DLECT] ? (unsigned short)largs[DLECT] : SQL_DIALECT_CURRENT; + ib_link->tr_list = NULL; + ib_link->event_head = NULL; + + ++IBG(num_links); + } + + /* add it to the hash */ + new_index_ptr.ptr = (void *) Z_LVAL_P(return_value); + Z_TYPE(new_index_ptr) = le_index_ptr; + if (FAILURE == zend_hash_update(&EG(regular_list), hash, sizeof(hash), + (void *) &new_index_ptr, sizeof(zend_rsrc_list_entry), NULL)) { + RETURN_FALSE; + } + zend_list_addref(IBG(default_link) = Z_LVAL_P(return_value)); +} +/* }}} */ + +/* {{{ proto resource ibase_connect(string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]]) + Open a connection to an InterBase database */ +PHP_FUNCTION(ibase_connect) +{ + _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0); +} +/* }}} */ + +/* {{{ proto resource ibase_pconnect(string database [, string username [, string password [, string charset [, int buffers [, int dialect [, string role]]]]]]) + Open a persistent connection to an InterBase database */ +PHP_FUNCTION(ibase_pconnect) +{ + _php_ibase_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, INI_INT("ibase.allow_persistent")); +} +/* }}} */ + +/* {{{ proto bool ibase_close([resource link_identifier]) + Close an InterBase connection */ +PHP_FUNCTION(ibase_close) +{ + zval *link_arg = NULL; + ibase_db_link *ib_link; + int link_id; + + RESET_ERRMSG; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &link_arg) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() == 0) { + link_id = IBG(default_link); + CHECK_LINK(link_id); + IBG(default_link) = -1; + } else { + link_id = Z_RESVAL_P(link_arg); + } + + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, link_id, LE_LINK, le_link, le_plink); + zend_list_delete(link_id); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool ibase_drop_db([resource link_identifier]) + Drop an InterBase database */ +PHP_FUNCTION(ibase_drop_db) +{ + zval *link_arg = NULL; + ibase_db_link *ib_link; + ibase_tr_list *l; + int link_id; + + RESET_ERRMSG; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &link_arg) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() == 0) { + link_id = IBG(default_link); + CHECK_LINK(link_id); + IBG(default_link) = -1; + } else { + link_id = Z_RESVAL_P(link_arg); + } + + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &link_arg, link_id, LE_LINK, le_link, le_plink); + + if (isc_drop_database(IB_STATUS, &ib_link->handle)) { + _php_ibase_error(TSRMLS_C); + RETURN_FALSE; + } + + /* isc_drop_database() doesn't invalidate the transaction handles */ + for (l = ib_link->tr_list; l != NULL; l = l->next) { + if (l->trans != NULL) l->trans->handle = NULL; + } + + zend_list_delete(link_id); + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto resource ibase_trans([int trans_args [, resource link_identifier [, ... ], int trans_args [, resource link_identifier [, ... ]] [, ...]]]) + Start a transaction over one or several databases */ + +#define TPB_MAX_SIZE (8*sizeof(char)) + +PHP_FUNCTION(ibase_trans) +{ + unsigned short i, link_cnt = 0, tpb_len = 0; + int argn; + char last_tpb[TPB_MAX_SIZE]; + ibase_db_link **ib_link = NULL; + ibase_trans *ib_trans; + isc_tr_handle tr_handle = NULL; + ISC_STATUS result; + + RESET_ERRMSG; + + argn = ZEND_NUM_ARGS(); + + /* (1+argn) is an upper bound for the number of links this trans connects to */ + ib_link = (ibase_db_link **) safe_emalloc(sizeof(ibase_db_link *),1+argn,0); + + if (argn > 0) { + long trans_argl = 0; + char *tpb; + ISC_TEB *teb; + zval ***args = NULL; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "+", &args, &argn) == FAILURE) { + efree(args); + efree(ib_link); + RETURN_FALSE; + } + + teb = (ISC_TEB *) safe_emalloc(sizeof(ISC_TEB),argn,0); + tpb = (char *) safe_emalloc(TPB_MAX_SIZE,argn,0); + + /* enumerate all the arguments: assume every non-resource argument + specifies modifiers for the link ids that follow it */ + for (i = 0; i < argn; ++i) { + + if (Z_TYPE_PP(args[i]) == IS_RESOURCE) { + + if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link[link_cnt], ibase_db_link *, args[i], -1, LE_LINK, le_link, le_plink)) { + efree(teb); + efree(tpb); + efree(ib_link); + efree(args); + RETURN_FALSE; + } + + /* copy the most recent modifier string into tbp[] */ + memcpy(&tpb[TPB_MAX_SIZE * link_cnt], last_tpb, TPB_MAX_SIZE); + + /* add a database handle to the TEB with the most recently specified set of modifiers */ + teb[link_cnt].db_ptr = &ib_link[link_cnt]->handle; + teb[link_cnt].tpb_len = tpb_len; + teb[link_cnt].tpb_ptr = &tpb[TPB_MAX_SIZE * link_cnt]; + + ++link_cnt; + + } else { + + tpb_len = 0; + + convert_to_long_ex(args[i]); + trans_argl = Z_LVAL_PP(args[i]); + + if (trans_argl != PHP_IBASE_DEFAULT) { + last_tpb[tpb_len++] = isc_tpb_version3; + + /* access mode */ + if (PHP_IBASE_READ == (trans_argl & PHP_IBASE_READ)) { + last_tpb[tpb_len++] = isc_tpb_read; + } else if (PHP_IBASE_WRITE == (trans_argl & PHP_IBASE_WRITE)) { + last_tpb[tpb_len++] = isc_tpb_write; + } + + /* isolation level */ + if (PHP_IBASE_COMMITTED == (trans_argl & PHP_IBASE_COMMITTED)) { + last_tpb[tpb_len++] = isc_tpb_read_committed; + if (PHP_IBASE_REC_VERSION == (trans_argl & PHP_IBASE_REC_VERSION)) { + last_tpb[tpb_len++] = isc_tpb_rec_version; + } else if (PHP_IBASE_REC_NO_VERSION == (trans_argl & PHP_IBASE_REC_NO_VERSION)) { + last_tpb[tpb_len++] = isc_tpb_no_rec_version; + } + } else if (PHP_IBASE_CONSISTENCY == (trans_argl & PHP_IBASE_CONSISTENCY)) { + last_tpb[tpb_len++] = isc_tpb_consistency; + } else if (PHP_IBASE_CONCURRENCY == (trans_argl & PHP_IBASE_CONCURRENCY)) { + last_tpb[tpb_len++] = isc_tpb_concurrency; + } + + /* lock resolution */ + if (PHP_IBASE_NOWAIT == (trans_argl & PHP_IBASE_NOWAIT)) { + last_tpb[tpb_len++] = isc_tpb_nowait; + } else if (PHP_IBASE_WAIT == (trans_argl & PHP_IBASE_WAIT)) { + last_tpb[tpb_len++] = isc_tpb_wait; + } + } + } + } + + if (link_cnt > 0) { + result = isc_start_multiple(IB_STATUS, &tr_handle, link_cnt, teb); + } + + efree(args); + efree(tpb); + efree(teb); + } + + if (link_cnt == 0) { + link_cnt = 1; + if (!ZEND_FETCH_RESOURCE2_NO_RETURN(ib_link[0], ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink)) { + efree(ib_link); + RETURN_FALSE; + } + result = isc_start_transaction(IB_STATUS, &tr_handle, 1, &ib_link[0]->handle, tpb_len, last_tpb); + } + + /* start the transaction */ + if (result) { + _php_ibase_error(TSRMLS_C); + efree(ib_link); + RETURN_FALSE; + } + + /* register the transaction in our own data structures */ + ib_trans = (ibase_trans *) safe_emalloc(link_cnt-1, sizeof(ibase_db_link *), sizeof(ibase_trans)); + ib_trans->handle = tr_handle; + ib_trans->link_cnt = link_cnt; + ib_trans->affected_rows = 0; + for (i = 0; i < link_cnt; ++i) { + ibase_tr_list **l; + ib_trans->db_link[i] = ib_link[i]; + + /* the first item in the connection-transaction list is reserved for the default transaction */ + if (ib_link[i]->tr_list == NULL) { + ib_link[i]->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); + ib_link[i]->tr_list->trans = NULL; + ib_link[i]->tr_list->next = NULL; + } + + /* link the transaction into the connection-transaction list */ + for (l = &ib_link[i]->tr_list; *l != NULL; l = &(*l)->next); + *l = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); + (*l)->trans = ib_trans; + (*l)->next = NULL; + } + efree(ib_link); + ZEND_REGISTER_RESOURCE(return_value, ib_trans, le_trans); +} +/* }}} */ + +int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans TSRMLS_DC) /* {{{ */ +{ + if (ib_link == NULL) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid database link"); + return FAILURE; + } + + /* the first item in the connection-transaction list is reserved for the default transaction */ + if (ib_link->tr_list == NULL) { + ib_link->tr_list = (ibase_tr_list *) emalloc(sizeof(ibase_tr_list)); + ib_link->tr_list->trans = NULL; + ib_link->tr_list->next = NULL; + } + + if (*trans == NULL) { + ibase_trans *tr = ib_link->tr_list->trans; + + if (tr == NULL) { + tr = (ibase_trans *) emalloc(sizeof(ibase_trans)); + tr->handle = NULL; + tr->link_cnt = 1; + tr->affected_rows = 0; + tr->db_link[0] = ib_link; + ib_link->tr_list->trans = tr; + } + if (tr->handle == NULL) { + if (isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL)) { + _php_ibase_error(TSRMLS_C); + return FAILURE; + } + } + *trans = tr; + } + return SUCCESS; +} +/* }}} */ + +static void _php_ibase_trans_end(INTERNAL_FUNCTION_PARAMETERS, int commit) /* {{{ */ +{ + ibase_trans *trans = NULL; + int res_id = 0; + ISC_STATUS result; + ibase_db_link *ib_link; + zval *arg = NULL; + int type; + + RESET_ERRMSG; + + if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg) == FAILURE) { + return; + } + + if (ZEND_NUM_ARGS() == 0) { + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, NULL, IBG(default_link), LE_LINK, le_link, le_plink); + if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { + /* this link doesn't have a default transaction */ + _php_ibase_module_error("Default link has no default transaction" TSRMLS_CC); + RETURN_FALSE; + } + trans = ib_link->tr_list->trans; + } else { + /* one id was passed, could be db or trans id */ + if (zend_list_find(Z_RESVAL_P(arg), &type) && type == le_trans) { + ZEND_FETCH_RESOURCE(trans, ibase_trans *, &arg, -1, LE_TRANS, le_trans); + res_id = Z_RESVAL_P(arg); + } else { + ZEND_FETCH_RESOURCE2(ib_link, ibase_db_link *, &arg, -1, LE_LINK, le_link, le_plink); + + if (ib_link->tr_list == NULL || ib_link->tr_list->trans == NULL) { + /* this link doesn't have a default transaction */ + _php_ibase_module_error("Link has no default transaction" TSRMLS_CC); + RETURN_FALSE; + } + trans = ib_link->tr_list->trans; + } + } + + switch (commit) { + default: /* == case ROLLBACK: */ + result = isc_rollback_transaction(IB_STATUS, &trans->handle); + break; + case COMMIT: + result = isc_commit_transaction(IB_STATUS, &trans->handle); + break; + case (ROLLBACK | RETAIN): + result = isc_rollback_retaining(IB_STATUS, &trans->handle); + break; + case (COMMIT | RETAIN): + result = isc_commit_retaining(IB_STATUS, &trans->handle); + break; + } + + if (result) { + _php_ibase_error(TSRMLS_C); + RETURN_FALSE; + } + + /* Don't try to destroy implicitly opened transaction from list... */ + if ((commit & RETAIN) == 0 && res_id != 0) { + zend_list_delete(res_id); + } + RETURN_TRUE; +} +/* }}} */ + +/* {{{ proto bool ibase_commit( resource link_identifier ) + Commit transaction */ +PHP_FUNCTION(ibase_commit) +{ + _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT); +} +/* }}} */ + +/* {{{ proto bool ibase_rollback( resource link_identifier ) + Rollback transaction */ +PHP_FUNCTION(ibase_rollback) +{ + _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK); +} +/* }}} */ + +/* {{{ proto bool ibase_commit_ret( resource link_identifier ) + Commit transaction and retain the transaction context */ +PHP_FUNCTION(ibase_commit_ret) +{ + _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, COMMIT | RETAIN); +} +/* }}} */ + +/* {{{ proto bool ibase_rollback_ret( resource link_identifier ) + Rollback transaction and retain the transaction context */ +PHP_FUNCTION(ibase_rollback_ret) +{ + _php_ibase_trans_end(INTERNAL_FUNCTION_PARAM_PASSTHRU, ROLLBACK | RETAIN); +} +/* }}} */ + +/* {{{ proto int ibase_gen_id(string generator [, int increment [, resource link_identifier ]]) + Increments the named generator and returns its new value */ +PHP_FUNCTION(ibase_gen_id) +{ + zval *link = NULL; + char query[128], *generator; + int gen_len; + long inc = 1; + ibase_db_link *ib_link; + ibase_trans *trans = NULL; + XSQLDA out_sqlda; + ISC_INT64 result; + + RESET_ERRMSG; + + if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|lr", &generator, &gen_len, + &inc, &link)) { + RETURN_FALSE; + } + + if (gen_len > 31) { + php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid generator name"); + RETURN_FALSE; + } + + PHP_IBASE_LINK_TRANS(link, ib_link, trans); + + snprintf(query, sizeof(query), "SELECT GEN_ID(%s,%ld) FROM rdb$database", generator, inc); + + /* allocate a minimal descriptor area */ + out_sqlda.sqln = out_sqlda.sqld = 1; + out_sqlda.version = SQLDA_CURRENT_VERSION; + + /* allocate the field for the result */ + out_sqlda.sqlvar[0].sqltype = SQL_INT64; + out_sqlda.sqlvar[0].sqlscale = 0; + out_sqlda.sqlvar[0].sqllen = sizeof(result); + out_sqlda.sqlvar[0].sqldata = (void*) &result; + + /* execute the query */ + if (isc_dsql_exec_immed2(IB_STATUS, &ib_link->handle, &trans->handle, 0, query, + SQL_DIALECT_CURRENT, NULL, &out_sqlda)) { + _php_ibase_error(TSRMLS_C); + RETURN_FALSE; + } + + /* don't return the generator value as a string unless it doesn't fit in a long */ +#if SIZEOF_LONG < 8 + if (result < LONG_MIN || result > LONG_MAX) { + char *res; + int l; + + l = spprintf(&res, 0, "%" LL_MASK "d", result); + RETURN_STRINGL(res, l, 0); + } +#endif + RETURN_LONG((long)result); +} + +/* }}} */ + +#endif /* HAVE_IBASE */ + +/* + * Local variables: + * tab-width: 4 + * c-basic-offset: 4 + * End: + * vim600: sw=4 ts=4 fdm=marker + * vim<600: sw=4 ts=4 + */ |