php-src/ext/interbase/interbase.c
Kalle Sommer Nielsen 197051f3ab Remove sql.safe_mode
This is one of the last old and odd deprecated settings we still have in PHP, it was never fully implemented in all the database extensions and should probably have been gone back in 5.4, along with safe_mode. Although if my memory strikes me right, mysql was also supporting it back then, but not mysqli.

So far only interbase was supporting this feature, and the removal of it causes two effects for interbase:
 - CREATE DATABASE is now allowed no matter
 - The default database set by php.ini (ibase.default_db) is no longer forced

http://php.net/ini.core#ini.sql.safe-mode
2016-08-11 05:06:55 +02:00

1483 lines
45 KiB
C

/*
+----------------------------------------------------------------------+
| PHP Version 7 |
+----------------------------------------------------------------------+
| Copyright (c) 1997-2016 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> |
+----------------------------------------------------------------------+
*/
#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==NULL) { php_error_docref(NULL, 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),
PHP_INTERBASE_VERSION,
PHP_MODULE_GLOBALS(ibase),
PHP_GINIT(ibase),
NULL,
NULL,
STANDARD_MODULE_PROPERTIES_EX
};
#ifdef COMPILE_DL_INTERBASE
#ifdef ZTS
ZEND_TSRMLS_CACHE_DEFINE()
#endif
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));
}
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(void) /* {{{ */
{
char *s = IBG(errmsg);
const ISC_STATUS *statusp = IB_STATUS;
IBG(sql_code) = isc_sqlcode(IB_STATUS);
while ((s - IBG(errmsg)) < MAX_ERRMSG && fb_interpret(s, MAX_ERRMSG - strlen(IBG(errmsg)) - 1, &statusp)) {
strcat(IBG(errmsg), " ");
s = IBG(errmsg) + strlen(IBG(errmsg));
}
php_error_docref(NULL, E_WARNING, "%s", IBG(errmsg));
}
/* }}} */
/* print php interbase module error and save it for ibase_errmsg() */
void _php_ibase_module_error(char *msg, ...) /* {{{ */
{
va_list ap;
va_start(ap, msg);
/* 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, E_WARNING, "%s", IBG(errmsg));
}
/* }}} */
/* {{{ internal macros, functions and structures */
typedef struct {
isc_db_handle *db_ptr;
zend_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)
{
IBDEBUG("Transaction or database link?");
if (Z_RES_P(link_id)->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");
*trans = (ibase_trans *)zend_fetch_resource_ex(link_id, LE_TRANS, le_trans);
if ((*trans)->link_cnt > 1) {
_php_ibase_module_error("Link id is ambiguous: transaction spans multiple connections."
);
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;
*ib_link = (ibase_db_link *)zend_fetch_resource2_ex(link_id, LE_LINK, le_link, le_plink);
}
/* }}} */
/* destructors ---------------------- */
static void _php_ibase_commit_link(ibase_db_link *link) /* {{{ */
{
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 != 0) {
if (i == 0) {
if (p->trans->handle != 0) {
IBDEBUG("Committing default transaction...");
if (isc_commit_transaction(IB_STATUS, &p->trans->handle)) {
_php_ibase_error();
}
}
efree(p->trans); /* default transaction is not a registered resource: clean up */
} else {
if (p->trans->handle != 0) {
/* 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();
}
}
/* 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);
e->link = NULL;
}
}
/* }}} */
static void php_ibase_commit_link_rsrc(zend_resource *rsrc) /* {{{ */
{
ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
_php_ibase_commit_link(link);
}
/* }}} */
static void _php_ibase_close_link(zend_resource *rsrc) /* {{{ */
{
ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
_php_ibase_commit_link(link);
if (link->handle != 0) {
IBDEBUG("Closing normal link...");
isc_detach_database(IB_STATUS, &link->handle);
}
IBG(num_links)--;
efree(link);
}
/* }}} */
static void _php_ibase_close_plink(zend_resource *rsrc) /* {{{ */
{
ibase_db_link *link = (ibase_db_link *) rsrc->ptr;
_php_ibase_commit_link(link);
IBDEBUG("Closing permanent link...");
if (link->handle != 0) {
isc_detach_database(IB_STATUS, &link->handle);
}
IBG(num_persistent)--;
IBG(num_links)--;
free(link);
}
/* }}} */
static void _php_ibase_free_trans(zend_resource *rsrc) /* {{{ */
{
ibase_trans *trans = (ibase_trans *)rsrc->ptr;
unsigned short i;
IBDEBUG("Cleaning up transaction resource...");
if (trans->handle != 0) {
IBDEBUG("Rolling back unhandled transaction...");
if (isc_rollback_transaction(IB_STATUS, &trans->handle)) {
_php_ibase_error();
}
}
/* 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)
{
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)
{
#if defined(COMPILE_DL_INTERBASE) && defined(ZTS)
ZEND_TSRMLS_CACHE_UPDATE();
#endif
ibase_globals->num_persistent = ibase_globals->num_links = 0;
ibase_globals->sql_code = *ibase_globals->errmsg = 0;
ibase_globals->default_link = NULL;
}
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 ((ibase_entry = zend_hash_str_find_ptr(&module_registry, ibase_module_entry.name,
strlen(ibase_module_entry.name))) != NULL) {
ibase_entry->handle = 0;
}
#endif
UNREGISTER_INI_ENTRIES();
return SUCCESS;
}
PHP_RSHUTDOWN_FUNCTION(ibase)
{
IBG(num_links) = IBG(num_persistent);
IBG(default_link)= NULL;
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";
#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);
}
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, size_t *len, zend_long *largs, isc_db_handle *db) /* {{{ */
{
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();
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;
size_t len[] = { 0, 0, 0, 0, 0 };
zend_long largs[] = { 0, 0, 0 };
PHP_MD5_CTX hash_context;
zend_resource new_index_ptr, *le;
isc_db_handle db_handle = 0;
ibase_db_link *ib_link;
RESET_ERRMSG;
if (FAILURE == zend_parse_parameters(ZEND_NUM_ARGS(), "|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] && (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(zend_long); ++i) {
PHP_MD5Update(&hash_context,(char*)&largs[i],sizeof(zend_long));
}
PHP_MD5Final((unsigned char*)hash, &hash_context);
/* try to reuse a connection */
if ((le = zend_hash_str_find_ptr(&EG(regular_list), hash, sizeof(hash)-1)) != NULL) {
zend_resource *xlink;
if (le->type != le_index_ptr) {
RETURN_FALSE;
}
xlink = (zend_resource*) le->ptr;
if ((!persistent && xlink->type == le_link) || xlink->type == le_plink) {
if (IBG(default_link)) {
zend_list_close(IBG(default_link));
}
xlink->gc.refcount++;
xlink->gc.refcount++;
IBG(default_link) = xlink;
RETVAL_RES(xlink);
} else {
zend_hash_str_del(&EG(regular_list), hash, sizeof(hash)-1);
}
}
/* ... or a persistent one */
do {
zend_long l;
static char info[] = { isc_info_base_level, isc_info_end };
char result[8];
ISC_STATUS status[20];
if ((le = zend_hash_str_find_ptr(&EG(persistent_list), hash, sizeof(hash)-1)) != NULL) {
if (le->type != 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)) {
RETVAL_RES(zend_register_resource(ib_link, le_plink));
break;
}
zend_hash_str_del(&EG(persistent_list), hash, sizeof(hash)-1);
}
/* 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)", IBG(num_links));
RETURN_FALSE;
}
/* create the ib_link */
if (FAILURE == _php_ibase_attach_db(args, len, largs, &db_handle)) {
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));
RETVAL_RES(zend_register_resource(ib_link, le_link));
} else {
zend_resource new_le;
ib_link = (ibase_db_link *) malloc(sizeof(ibase_db_link));
if (!ib_link) {
RETURN_FALSE;
}
/* hash it up */
new_le.type = le_plink;
new_le.ptr = ib_link;
if (zend_hash_str_update_mem(&EG(persistent_list), hash, sizeof(hash)-1,
(void *) &new_le, sizeof(zend_resource)) == NULL) {
free(ib_link);
RETURN_FALSE;
}
RETVAL_RES(zend_register_resource(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);
} while (0);
/* add it to the hash */
new_index_ptr.ptr = (void *) Z_RES_P(return_value);
new_index_ptr.type = le_index_ptr;
if (zend_hash_str_update_mem(&EG(regular_list), hash, sizeof(hash)-1,
(void *) &new_index_ptr, sizeof(zend_resource)) == NULL) {
RETURN_FALSE;
}
if (IBG(default_link)) {
zend_list_delete(IBG(default_link));
}
IBG(default_link) = Z_RES_P(return_value);
Z_TRY_ADDREF_P(return_value);
Z_TRY_ADDREF_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;
zend_resource *link_res;
RESET_ERRMSG;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link_arg) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() == 0) {
link_res = IBG(default_link);
CHECK_LINK(link_res);
IBG(default_link) = NULL;
} else {
link_res = Z_RES_P(link_arg);
}
/* we have at least 3 additional references to this resource ??? */
if (GC_REFCOUNT(link_res) < 4) {
zend_list_close(link_res);
} else {
zend_list_delete(link_res);
}
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;
zend_resource *link_res;
RESET_ERRMSG;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &link_arg) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() == 0) {
link_res = IBG(default_link);
CHECK_LINK(link_res);
IBG(default_link) = NULL;
} else {
link_res = Z_RES_P(link_arg);
}
ib_link = (ibase_db_link *)zend_fetch_resource2(link_res, LE_LINK, le_link, le_plink);
if (!ib_link) {
RETURN_FALSE;
}
if (isc_drop_database(IB_STATUS, &ib_link->handle)) {
_php_ibase_error();
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 = 0;
}
zend_list_delete(link_res);
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 = 0;
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) {
zend_long trans_argl = 0;
char *tpb;
ISC_TEB *teb;
zval *args = NULL;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "+", &args, &argn) == FAILURE) {
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(args[i]) == IS_RESOURCE) {
if ((ib_link[link_cnt] = (ibase_db_link *)zend_fetch_resource2_ex(&args[i], LE_LINK, le_link, le_plink)) == NULL) {
efree(teb);
efree(tpb);
efree(ib_link);
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(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(tpb);
efree(teb);
}
if (link_cnt == 0) {
link_cnt = 1;
if ((ib_link[0] = (ibase_db_link *)zend_fetch_resource2(IBG(default_link), LE_LINK, le_link, le_plink)) == NULL) {
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();
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);
RETVAL_RES(zend_register_resource(ib_trans, le_trans));
Z_TRY_ADDREF_P(return_value);
}
/* }}} */
int _php_ibase_def_trans(ibase_db_link *ib_link, ibase_trans **trans) /* {{{ */
{
if (ib_link == NULL) {
php_error_docref(NULL, 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 = 0;
tr->link_cnt = 1;
tr->affected_rows = 0;
tr->db_link[0] = ib_link;
ib_link->tr_list->trans = tr;
}
if (tr->handle == 0) {
if (isc_start_transaction(IB_STATUS, &tr->handle, 1, &ib_link->handle, 0, NULL)) {
_php_ibase_error();
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;
RESET_ERRMSG;
if (zend_parse_parameters(ZEND_NUM_ARGS(), "|r", &arg) == FAILURE) {
return;
}
if (ZEND_NUM_ARGS() == 0) {
ib_link = (ibase_db_link *)zend_fetch_resource2(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");
RETURN_FALSE;
}
trans = ib_link->tr_list->trans;
} else {
/* one id was passed, could be db or trans id */
if (Z_RES_P(arg)->type == le_trans) {
trans = (ibase_trans *)zend_fetch_resource_ex(arg, LE_TRANS, le_trans);
res_id = Z_RES_P(arg)->handle;
} else {
ib_link = (ibase_db_link *)zend_fetch_resource2_ex(arg, 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");
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();
RETURN_FALSE;
}
/* Don't try to destroy implicitly opened transaction from list... */
if ((commit & RETAIN) == 0 && res_id != 0) {
zend_list_delete(Z_RES_P(arg));
}
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;
size_t gen_len;
zend_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(), "s|lr", &generator, &gen_len,
&inc, &link)) {
RETURN_FALSE;
}
if (gen_len > 31) {
php_error_docref(NULL, 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();
RETURN_FALSE;
}
/* don't return the generator value as a string unless it doesn't fit in a long */
#if SIZEOF_ZEND_LONG < 8
if (result < ZEND_LONG_MIN || result > ZEND_LONG_MAX) {
char *res;
int l;
l = spprintf(&res, 0, "%" LL_MASK "d", result);
RETURN_STRINGL(res, l);
}
#endif
RETURN_LONG((zend_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
*/