diff options
author | KoenigsKind <git@koenigskind.net> | 2017-04-07 20:40:40 +0200 |
---|---|---|
committer | Christopher Jones <christopher.jones@oracle.com> | 2017-06-20 14:32:52 +1000 |
commit | 1b797f7ad3da798827806012abd3fd2641c1bc14 (patch) | |
tree | 78f72e039d8abd4177245beb106971f3265c30fa /ext/oci8 | |
parent | a6c67a088a6e1bd249b215a7d0a6536e5fa8c3ce (diff) | |
download | php-git-1b797f7ad3da798827806012abd3fd2641c1bc14.tar.gz |
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
Diffstat (limited to 'ext/oci8')
-rw-r--r-- | ext/oci8/config.m4 | 4 | ||||
-rw-r--r-- | ext/oci8/config.w32 | 4 | ||||
-rw-r--r-- | ext/oci8/oci8.c | 38 | ||||
-rw-r--r-- | ext/oci8/oci8_failover.c | 162 | ||||
-rw-r--r-- | ext/oci8/oci8_interface.c | 36 | ||||
-rw-r--r-- | ext/oci8/php_oci8.h | 1 | ||||
-rw-r--r-- | ext/oci8/php_oci8_int.h | 9 |
7 files changed, 250 insertions, 4 deletions
diff --git a/ext/oci8/config.m4 b/ext/oci8/config.m4 index 14042401d5..efcc09b5de 100644 --- a/ext/oci8/config.m4 +++ b/ext/oci8/config.m4 @@ -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) diff --git a/ext/oci8/config.w32 b/ext/oci8/config.w32 index 74014648ff..234420de67 100644 --- a/ext/oci8/config.w32 +++ b/ext/oci8/config.w32 @@ -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); diff --git a/ext/oci8/oci8.c b/ext/oci8/oci8.c index 03698b2e9b..084655103f 100644 --- a/ext/oci8/oci8.c +++ b/ext/oci8/oci8.c @@ -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()) { diff --git a/ext/oci8/oci8_failover.c b/ext/oci8/oci8_failover.c new file mode 100644 index 0000000000..ab3ba4bd09 --- /dev/null +++ b/ext/oci8/oci8_failover.c @@ -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 + */ diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c index d91a132559..0649575b5b 100644 --- a/ext/oci8/oci8_interface.c +++ b/ext/oci8/oci8_interface.c @@ -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); */ diff --git a/ext/oci8/php_oci8.h b/ext/oci8/php_oci8.h index 4bce161eb5..2266e8c10c 100644 --- a/ext/oci8/php_oci8.h +++ b/ext/oci8/php_oci8.h @@ -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); diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h index 61bb2750fa..06a88f4c84 100644 --- a/ext/oci8/php_oci8_int.h +++ b/ext/oci8/php_oci8_int.h @@ -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 |