mirror of
https://github.com/php/php-src.git
synced 2025-08-16 05:58:45 +02:00
oci8 - Implementation of Oracle TAF Callback
Adds support for the Transparent Application Failover Callback. The php_oci_connection struct got a char* added which will contain the callback function, it should be set to PHP_OCI_TAF_DISABLE_CALLBACK at the end of a php request for permanent connections so that, if a TAF callback occurs, no userspace function will be called. Maybe add support for registering object functions (via array), currently the register function only accepts a string. I didn't know how to implement it correctly. As a failover occurs very rarely it might be better to not keep the cache when saving the zend_fcall_info. Things to do [ ] config.m4 needs to compile oci8_failover.c [ ] Check if correctly implemented (especially for multithreading) [ ] Add support for registering callback function via array
This commit is contained in:
parent
a6c67a088a
commit
1b797f7ad3
7 changed files with 250 additions and 4 deletions
|
@ -335,7 +335,7 @@ if test "$PHP_OCI8" != "no"; then
|
|||
|
||||
PHP_ADD_LIBRARY(clntsh, 1, OCI8_SHARED_LIBADD)
|
||||
PHP_ADD_LIBPATH($OCI8_DIR/$OCI8_LIB_DIR, OCI8_SHARED_LIBADD)
|
||||
PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c, $ext_shared)
|
||||
PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c oci8_failover.c, $ext_shared)
|
||||
AC_DEFINE(HAVE_OCI8,1,[Defined to 1 if the PHP OCI8 extension for Oracle Database is configured])
|
||||
|
||||
PHP_SUBST_OLD(OCI8_SHARED_LIBADD)
|
||||
|
@ -406,7 +406,7 @@ if test "$PHP_OCI8" != "no"; then
|
|||
|
||||
AC_DEFINE(HAVE_OCI_INSTANT_CLIENT,1,[Defined to 1 if OCI8 configuration located Oracle's Instant Client libraries])
|
||||
|
||||
PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c, $ext_shared)
|
||||
PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c oci8_failover.c, $ext_shared)
|
||||
AC_DEFINE(HAVE_OCI8,1,[Defined to 1 if the PHP OCI8 extension for Oracle Database is configured])
|
||||
|
||||
PHP_SUBST_OLD(OCI8_SHARED_LIBADD)
|
||||
|
|
|
@ -80,7 +80,7 @@ if (PHP_OCI8_11G != "no") {
|
|||
if (CHECK_HEADER_ADD_INCLUDE("oci.h", "CFLAGS_OCI8_11G", oci8_11g_inc_paths) &&
|
||||
CHECK_LIB("oci.lib", "oci8_11g", oci8_11g_lib_paths))
|
||||
{
|
||||
EXTENSION('oci8_11g', 'oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c', null, null, null, "ext\\oci8_11g")
|
||||
EXTENSION('oci8_11g', 'oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c oci8_failover.c', null, null, null, "ext\\oci8_11g")
|
||||
|
||||
AC_DEFINE('HAVE_OCI8', 1);
|
||||
AC_DEFINE('HAVE_OCI_INSTANT_CLIENT', 1);
|
||||
|
@ -115,7 +115,7 @@ if (PHP_OCI8_12C != "no") {
|
|||
if (CHECK_HEADER_ADD_INCLUDE("oci.h", "CFLAGS_OCI8_12C", oci8_12c_inc_paths) &&
|
||||
CHECK_LIB("oci.lib", "oci8_12c", oci8_12c_lib_paths))
|
||||
{
|
||||
EXTENSION('oci8_12c', 'oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c', null, null, null, "ext\\oci8_12c")
|
||||
EXTENSION('oci8_12c', 'oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c oci8_failover.c', null, null, null, "ext\\oci8_12c")
|
||||
|
||||
AC_DEFINE('HAVE_OCI8', 1);
|
||||
AC_DEFINE('HAVE_OCI_INSTANT_CLIENT', 1);
|
||||
|
|
|
@ -504,6 +504,11 @@ ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_new_collection, 0, 0, 2)
|
|||
ZEND_ARG_INFO(0, type_name)
|
||||
ZEND_ARG_INFO(0, schema_name)
|
||||
ZEND_END_ARG_INFO()
|
||||
|
||||
ZEND_BEGIN_ARG_INFO_EX(arginfo_oci_register_taf_callback, 0, 0, 1)
|
||||
ZEND_ARG_INFO(0, connection_resource)
|
||||
ZEND_ARG_INFO(0, function_name)
|
||||
ZEND_END_ARG_INFO()
|
||||
/* }}} */
|
||||
|
||||
/* {{{ LOB Method arginfo */
|
||||
|
@ -701,6 +706,7 @@ PHP_FUNCTION(oci_collection_assign);
|
|||
PHP_FUNCTION(oci_collection_size);
|
||||
PHP_FUNCTION(oci_collection_max);
|
||||
PHP_FUNCTION(oci_collection_trim);
|
||||
PHP_FUNCTION(oci_register_taf_callback);
|
||||
/* }}} */
|
||||
|
||||
/* {{{ extension definition structures
|
||||
|
@ -783,6 +789,7 @@ static const zend_function_entry php_oci_functions[] = {
|
|||
PHP_FE(oci_collection_max, arginfo_oci_collection_max)
|
||||
PHP_FE(oci_collection_trim, arginfo_oci_collection_trim)
|
||||
PHP_FE(oci_new_collection, arginfo_oci_new_collection)
|
||||
PHP_FE(oci_register_taf_callback, arginfo_oci_register_taf_callback)
|
||||
|
||||
PHP_FALIAS(oci_free_cursor, oci_free_statement, arginfo_oci_free_statement)
|
||||
PHP_FALIAS(ocifreecursor, oci_free_statement, arginfo_oci_free_statement)
|
||||
|
@ -1129,6 +1136,20 @@ PHP_MINIT_FUNCTION(oci)
|
|||
REGISTER_LONG_CONSTANT("OCI_TEMP_CLOB",OCI_TEMP_CLOB, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_TEMP_BLOB",OCI_TEMP_BLOB, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
/* for Transparent Application Failover */
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_END", OCI_FO_END, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_ABORT", OCI_FO_ABORT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_REAUTH", OCI_FO_REAUTH, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_BEGIN", OCI_FO_BEGIN, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_ERROR", OCI_FO_ERROR, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_NONE", OCI_FO_NONE, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_SESSION", OCI_FO_SESSION, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_SELECT", OCI_FO_SELECT, CONST_CS | CONST_PERSISTENT);
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_TXNAL", OCI_FO_TXNAL, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
REGISTER_LONG_CONSTANT("OCI_FO_RETRY", OCI_FO_RETRY, CONST_CS | CONST_PERSISTENT);
|
||||
|
||||
return SUCCESS;
|
||||
}
|
||||
|
||||
|
@ -1930,6 +1951,7 @@ php_oci_connection *php_oci_do_connect_ex(char *username, int username_len, char
|
|||
connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
|
||||
connection->hash_key = zend_string_dup(hashed_details.s, 0);
|
||||
connection->is_persistent = 0;
|
||||
ZVAL_UNDEF(&connection->taf_callback);
|
||||
#ifdef HAVE_OCI8_DTRACE
|
||||
connection->client_id = NULL;
|
||||
#endif
|
||||
|
@ -1944,6 +1966,7 @@ php_oci_connection *php_oci_do_connect_ex(char *username, int username_len, char
|
|||
return NULL;
|
||||
}
|
||||
connection->is_persistent = 1;
|
||||
ZVAL_UNDEF(&connection->taf_callback);
|
||||
#ifdef HAVE_OCI8_DTRACE
|
||||
connection->client_id = NULL;
|
||||
#endif
|
||||
|
@ -1952,6 +1975,7 @@ php_oci_connection *php_oci_do_connect_ex(char *username, int username_len, char
|
|||
connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
|
||||
connection->hash_key = zend_string_dup(hashed_details.s, 0);
|
||||
connection->is_persistent = 0;
|
||||
ZVAL_UNDEF(&connection->taf_callback);
|
||||
#ifdef HAVE_OCI8_DTRACE
|
||||
connection->client_id = NULL;
|
||||
#endif
|
||||
|
@ -2225,6 +2249,15 @@ static int php_oci_connection_close(php_oci_connection *connection)
|
|||
connection->client_id = NULL;
|
||||
}
|
||||
#endif /* HAVE_OCI8_DTRACE */
|
||||
|
||||
if (!Z_ISUNDEF(connection->taf_callback)) {
|
||||
/* If it's NULL, then its value should be freed already */
|
||||
if (!Z_ISNULL(connection->taf_callback)) {
|
||||
zval_ptr_dtor(&connection->taf_callback);
|
||||
}
|
||||
ZVAL_UNDEF(&connection->taf_callback);
|
||||
}
|
||||
|
||||
pefree(connection, connection->is_persistent);
|
||||
connection = NULL;
|
||||
OCI_G(in_call) = in_call_save;
|
||||
|
@ -2667,6 +2700,11 @@ static int php_oci_persistent_helper(zval *zv)
|
|||
if (le->type == le_pconnection) {
|
||||
connection = (php_oci_connection *)le->ptr;
|
||||
|
||||
/* Remove TAF callback function as it's bound to current request */
|
||||
if (connection->used_this_request && !Z_ISUNDEF(connection->taf_callback) && !Z_ISNULL(connection->taf_callback)) {
|
||||
php_oci_disable_taf_callback(connection);
|
||||
}
|
||||
|
||||
if (!connection->used_this_request && OCI_G(persistent_timeout) != -1) {
|
||||
#ifdef HAVE_OCI8_DTRACE
|
||||
if (DTRACE_OCI8_CONNECT_EXPIRY_ENABLED()) {
|
||||
|
|
162
ext/oci8/oci8_failover.c
Normal file
162
ext/oci8/oci8_failover.c
Normal file
|
@ -0,0 +1,162 @@
|
|||
/*
|
||||
+----------------------------------------------------------------------+
|
||||
| PHP Version 5 |
|
||||
+----------------------------------------------------------------------+
|
||||
| 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: Stig Sæther Bakken <ssb@php.net> |
|
||||
| Thies C. Arntzen <thies@thieso.net> |
|
||||
| |
|
||||
| Collection support by Andy Sautins <asautins@veripost.net> |
|
||||
| Temporary LOB support by David Benson <dbenson@mancala.com> |
|
||||
| ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at> |
|
||||
| |
|
||||
| Redesigned by: Antony Dovgal <antony@zend.com> |
|
||||
| Andi Gutmans <andi@zend.com> |
|
||||
| Wez Furlong <wez@omniti.com> |
|
||||
+----------------------------------------------------------------------+
|
||||
*/
|
||||
|
||||
|
||||
|
||||
#ifdef HAVE_CONFIG_H
|
||||
#include "config.h"
|
||||
#endif
|
||||
|
||||
#include "php.h"
|
||||
#include "ext/standard/info.h"
|
||||
#include "php_ini.h"
|
||||
|
||||
#if HAVE_OCI8
|
||||
|
||||
#include "php_oci8.h"
|
||||
#include "php_oci8_int.h"
|
||||
|
||||
/* {{{ callback_fn()
|
||||
OCI TAF callback function, calling userspace function */
|
||||
sb4 callback_fn(OCISvcCtx *svchp, OCIEnv *envhp, php_oci_connection *fo_ctx, ub4 fo_type, ub4 fo_event)
|
||||
{
|
||||
/* Create zval */
|
||||
zval retval, params[3];
|
||||
|
||||
/* Default return value */
|
||||
sb4 returnValue = 0;
|
||||
|
||||
/* Check if userspace callback function was disabled */
|
||||
if (Z_ISUNDEF(fo_ctx->taf_callback) || Z_ISNULL(fo_ctx->taf_callback)) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* Initialize zval */
|
||||
ZVAL_RES(¶ms[0], fo_ctx->id);
|
||||
ZVAL_LONG(¶ms[1], fo_event);
|
||||
ZVAL_LONG(¶ms[2], fo_type);
|
||||
|
||||
/* Call user function (if possible) */
|
||||
if (call_user_function(EG(function_table), NULL, &fo_ctx->taf_callback, &retval, 3, params) == FAILURE) {
|
||||
php_error_docref(NULL, E_WARNING, "Unable to call taf callback function, is it defined?");
|
||||
}
|
||||
|
||||
/* Set return value */
|
||||
if (Z_TYPE(retval) == IS_LONG) {
|
||||
returnValue = (sb4) Z_LVAL(retval);
|
||||
}
|
||||
|
||||
/* Setting params[0] to null so ressource isn't destroyed on zval_dtor */
|
||||
ZVAL_NULL(¶ms[0]);
|
||||
|
||||
/* Cleanup */
|
||||
zval_dtor(&retval);
|
||||
zval_dtor(¶ms[0]);
|
||||
zval_dtor(¶ms[1]);
|
||||
zval_dtor(¶ms[2]);
|
||||
|
||||
return returnValue;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_oci_disable_taf_callback()
|
||||
Disables the userspace callback function for Oracle TAF,
|
||||
while keeping the OCI callback alive */
|
||||
int php_oci_disable_taf_callback(php_oci_connection *connection)
|
||||
{
|
||||
return php_oci_register_taf_callback(connection, NULL);
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ php_oci_register_taf_callback()
|
||||
Register a callback function for Oracle TAF */
|
||||
int php_oci_register_taf_callback(php_oci_connection *connection, zval *callback)
|
||||
{
|
||||
sword errstatus;
|
||||
int registered = 0;
|
||||
|
||||
/* temporary failover callback structure */
|
||||
OCIFocbkStruct failover;
|
||||
|
||||
if (!callback) {
|
||||
/* Disable callback */
|
||||
if (Z_ISUNDEF(connection->taf_callback) || Z_ISNULL(connection->taf_callback)) {
|
||||
return 0; // Nothing to disable
|
||||
}
|
||||
|
||||
registered = 1;
|
||||
zval_ptr_dtor(&connection->taf_callback);
|
||||
ZVAL_NULL(&connection->taf_callback);
|
||||
} else {
|
||||
if (!Z_ISUNDEF(connection->taf_callback)) {
|
||||
registered = 1;
|
||||
if (!Z_ISNULL(connection->taf_callback)) {
|
||||
zval_ptr_dtor(&connection->taf_callback);
|
||||
ZVAL_NULL(&connection->taf_callback);
|
||||
}
|
||||
}
|
||||
|
||||
/* Set userspace callback function */
|
||||
ZVAL_COPY(&connection->taf_callback, callback);
|
||||
}
|
||||
|
||||
/* OCI callback function already registered */
|
||||
if (registered) {
|
||||
return 0;
|
||||
}
|
||||
|
||||
/* set context */
|
||||
failover.fo_ctx = connection;
|
||||
|
||||
/* set callback function */
|
||||
failover.callback_function = &callback_fn;
|
||||
|
||||
/* do the registration */
|
||||
PHP_OCI_CALL_RETURN(errstatus, OCIAttrSet, (connection->server, (ub4) OCI_HTYPE_SERVER, (void *) &failover, (ub4) 0, (ub4) OCI_ATTR_FOCBK, connection->err));
|
||||
|
||||
if (errstatus != OCI_SUCCESS) {
|
||||
zval_ptr_dtor(&connection->taf_callback);
|
||||
ZVAL_UNDEF(&connection->taf_callback);
|
||||
connection->errcode = php_oci_error(connection->err, errstatus);
|
||||
return 1;
|
||||
}
|
||||
|
||||
/* successful conclusion */
|
||||
return 0;
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
#endif /* HAVE_OCI8 */
|
||||
|
||||
/*
|
||||
* 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
|
||||
*/
|
|
@ -42,6 +42,39 @@
|
|||
#define OCI_STMT_CALL 10
|
||||
#endif
|
||||
|
||||
/* {{{ proto bool oci_register_taf_callback( resource connection [, mixed callback] )
|
||||
Register a callback function for Oracle Transparent Application Failover (TAF) */
|
||||
PHP_FUNCTION(oci_register_taf_callback)
|
||||
{
|
||||
zval *z_connection;
|
||||
php_oci_connection *connection;
|
||||
zval *callback;
|
||||
zend_string *callback_name;
|
||||
|
||||
if (zend_parse_parameters(ZEND_NUM_ARGS(), "r|z!", &z_connection, &callback) == FAILURE) {
|
||||
return;
|
||||
}
|
||||
|
||||
if (callback) {
|
||||
if (!zend_is_callable(callback, 0, &callback_name)) {
|
||||
php_error_docref(NULL, E_WARNING, "function '%s' is not callable", ZSTR_VAL(callback_name));
|
||||
zend_string_release(callback_name);
|
||||
RETURN_FALSE;
|
||||
}
|
||||
|
||||
zend_string_release(callback_name);
|
||||
}
|
||||
|
||||
PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
|
||||
|
||||
if (php_oci_register_taf_callback(connection, callback) == 0) {
|
||||
RETURN_TRUE;
|
||||
} else {
|
||||
RETURN_FALSE;
|
||||
}
|
||||
}
|
||||
/* }}} */
|
||||
|
||||
/* {{{ proto bool oci_define_by_name(resource stmt, string name, mixed &var [, int type])
|
||||
Define a PHP variable to an Oracle column by name */
|
||||
/* if you want to define a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE defining!!! */
|
||||
|
@ -1553,6 +1586,9 @@ PHP_FUNCTION(oci_close)
|
|||
internally Zend engine increments
|
||||
RefCount value by 1 */
|
||||
zend_list_close(connection->id);
|
||||
|
||||
/* Disable Oracle TAF */
|
||||
php_oci_disable_taf_callback(connection);
|
||||
|
||||
/* ZVAL_NULL(z_connection); */
|
||||
|
||||
|
|
|
@ -48,6 +48,7 @@
|
|||
extern zend_module_entry oci8_module_entry;
|
||||
#define phpext_oci8_ptr &oci8_module_entry
|
||||
#define phpext_oci8_11g_ptr &oci8_module_entry
|
||||
#define phpext_oci8_12c_ptr &oci8_module_entry
|
||||
|
||||
|
||||
PHP_MINIT_FUNCTION(oci);
|
||||
|
|
|
@ -164,6 +164,8 @@ typedef struct {
|
|||
#ifdef HAVE_OCI8_DTRACE
|
||||
char *client_id; /* The oci_set_client_identifier() value */
|
||||
#endif
|
||||
|
||||
zval taf_callback; /* The Oracle TAF callback function in the userspace */
|
||||
} php_oci_connection;
|
||||
/* }}} */
|
||||
|
||||
|
@ -531,6 +533,13 @@ ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ Module globals */
|
|||
char *edition;
|
||||
ZEND_END_MODULE_GLOBALS(oci) /* }}} */
|
||||
|
||||
/* {{{ transparent failover related prototypes */
|
||||
|
||||
int php_oci_register_taf_callback(php_oci_connection *connection, zval *callback);
|
||||
int php_oci_disable_taf_callback(php_oci_connection *connection);
|
||||
|
||||
/* }}} */
|
||||
|
||||
#ifdef ZTS
|
||||
#define OCI_G(v) TSRMG(oci_globals_id, zend_oci_globals *, v)
|
||||
#else
|
||||
|
|
Loading…
Add table
Add a link
Reference in a new issue