summaryrefslogtreecommitdiff
diff options
context:
space:
mode:
authorKoenigsKind <git@koenigskind.net>2017-04-07 20:40:40 +0200
committerChristopher Jones <christopher.jones@oracle.com>2017-06-20 14:32:52 +1000
commit1b797f7ad3da798827806012abd3fd2641c1bc14 (patch)
tree78f72e039d8abd4177245beb106971f3265c30fa
parenta6c67a088a6e1bd249b215a7d0a6536e5fa8c3ce (diff)
downloadphp-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
-rw-r--r--ext/oci8/config.m44
-rw-r--r--ext/oci8/config.w324
-rw-r--r--ext/oci8/oci8.c38
-rw-r--r--ext/oci8/oci8_failover.c162
-rw-r--r--ext/oci8/oci8_interface.c36
-rw-r--r--ext/oci8/php_oci8.h1
-rw-r--r--ext/oci8/php_oci8_int.h9
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(&params[0], fo_ctx->id);
+ ZVAL_LONG(&params[1], fo_event);
+ ZVAL_LONG(&params[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(&params[0]);
+
+ /* Cleanup */
+ zval_dtor(&retval);
+ zval_dtor(&params[0]);
+ zval_dtor(&params[1]);
+ zval_dtor(&params[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