]> granicus.if.org Git - php/commitdiff
Cleaned up whitespace
authorChristopher Jones <sixd@php.net>
Wed, 12 Mar 2008 01:25:13 +0000 (01:25 +0000)
committerChristopher Jones <sixd@php.net>
Wed, 12 Mar 2008 01:25:13 +0000 (01:25 +0000)
Fixed bug #44372 (compilation with Oracle 10gR1 libraries)
http://bugs.php.net/bug.php?id=44372

Updated updated error number list to improve re-connection
behavior after a database restart.

Guard against potential internal list corruption after ping
removes old oci_pconnect() information.

Fix ini_set("oci8.connection_class", "abc") to get an appropriate
persistent connection.

Ping at oci8.ping_interval for oci_connect() and oci_new_connect()
when DRCP connections are used. This improves non-persistent
connection reliability if a database gets restarted.

ext/oci8/README
ext/oci8/oci8.c
ext/oci8/php_oci8_int.h
ext/oci8/tests/drcp_cclass1.phpt [new file with mode: 0644]

index 2caf22509fba6421f9efc9e0c6d0b37c406d81d7..796de78cc5052d5fbb5c78e75b244c73bedbd4f4 100644 (file)
@@ -166,7 +166,7 @@ directory will contain logs of any failures.
 6. DRCP and FAN Support
 -----------------------
 
-The PHP OCI8 Beta extension has support for the Oracle Database
+The PHP OCI8 Beta extension has support for the Oracle Database
 Resident Connection Pool (DRCP) and Fast Application Notification
 (FAN).
 
@@ -205,6 +205,25 @@ contains background information on DRCP.
 After building PHP with the OCI8 extension and 11g libraries, follow
 these steps:
 
+6.2.0 Important: if Oracle Database 11.1.0.6 with DRCP connections is
+    used, then the Oracle database patch for bug 6474441 must be
+    applied (see section 6.5) or a workaround below used.  Without
+    this patch, "ORA-01000: maximum open cursors exceeded", "ORA-01001
+    invalid cursor" or "ORA-01002 fetch out of sequence" errors may
+    occur.
+
+    If the Oracle 11.1.0.6 database patch cannot be applied, one of
+    the following three workarounds can be used to disable statement
+    caching instead:
+
+    (i) Connect using Oracle dedicated or shared servers instead of DRCP.
+
+    (ii) Set PHP's oci8.statement_cache_size to 0.
+
+    (iii) Set an event in the database initialization parameter file:
+    event="56699 trace name context forever, level 128".
+
+
 6.2.1. As a privileged database administrator, use a program like
        SQL*Plus to start the connection pool in the database:
 
@@ -298,55 +317,15 @@ To enable FAN support in PHP, after building PHP with Oracle 10gR2 or
 6.3.4. Run your application, connecting to a 10gR2 or 11g database.
 
 
-6.4. Changes in this release from PECL OCI8 1.3.0 Beta
-
-The initial release of OCI8 with DRCP and FAN support was PECL OCI8
-1.3.0 Beta.  This section documents differences from that release.
-
-6.4.1 Statement caching has been re-enabled.
-
-Important: if Oracle Database 11.1.0.6 with DRCP connections is used,
-then the Oracle database patch for bug 6474441 must be applied (see
-section 6.5) or a workaround below used.  Without this patch,
-"ORA-01000: maximum open cursors exceeded", "ORA-01001 invalid cursor"
-or "ORA-01002 fetch out of sequence" errors may occur.
-
-If the Oracle 11.1.0.6 database patch cannot be applied, one of the
-following three workarounds can be used to disable statement caching
-instead:
-
-(i) Connect using Oracle dedicated or shared servers instead of DRCP.
-
-(ii) Set PHP's oci8.statement_cache_size to 0.
-
-(iii) Set an event in the database initialization parameter file:
-event="56699 trace name context forever, level 128".
-
-6.4.2 Changing Password for non-DRCP connections has been re-enabled.
-
-When oci_password_change() is successfully performed for non-DRCP
-connections in a PHP script, subsequent connections with the new
-password from this PHP instance no longer fail with "ORA-1017 invalid
-username/password".
-
-Changing a password over DRCP connections will continue to fail with
-the error "ORA-56609: Usage not supported with DRCP".  This is an
-documented restriction of Oracle Database 11g.
-
-6.4.3 Oci8.max_persistent setting is re-enabled.
-
-The php.ini parameter oci8.max_persistent will limit the number of
-persistent connections that each PHP process will keep open between
-HTTP requests.  Any further oci_pconnect() calls once this limit is
-reached will be treated as oci_connect() calls.
+6.4. Recommendations and Known Limitations 
 
-It is still recommended that DRCP users modify the connection pool
-settings of the database to control resource usage.  Non-DRCP users
-should consider setting oci8.persistent_timeout to close idle
-connections.
+6.4.1 Changing Password for DRCP connections
 
+Changing a password over DRCP connections will fail with the error
+"ORA-56609: Usage not supported with DRCP".  This is an documented
+restriction of Oracle Database 11g.
 
-6.4.4 LOGON Triggers can be used to set session properties
+6.4.2 LOGON Triggers can be used to set session properties
 
 The patch for Oracle Database 11.1.0.6 bug 6474441 (see section 6.5)
 allows PHP applications with DRCP connection to use a database LOGON
@@ -364,9 +343,9 @@ application code.
 With DRCP there is an connection management relationship between (i)
 DRCP's automatic pool expansion and reduction, (ii) PHP's persistent
 connection caching, (iii) with the way LOGON triggers fire with DRCP
-authentication.  Because of this interplay, LOGON triggers in PHP when
-DRCP is used are only recommended for setting session attributes and
-not for per-PHP connection events.
+authentication.  Because of this interplay, LOGON triggers in PHP
+(when DRCP is used) are only recommended for setting session
+attributes and not for per-PHP connection events.
 
 
 6.5. Patching Oracle Database 11g
index e9b0d90a3b7f5d41e6444dff3bb249800c51532b..f27607d40413faadfe4f269ea1ed711ff963e7fb 100644 (file)
@@ -33,7 +33,7 @@
  *
  * get OCI_ATTR_CHARSET_ID attr of column to detect UTF string and multiply buffer in 4 times
  *
- * */
+ */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
@@ -59,7 +59,7 @@ int le_pconnection;
 int le_statement;
 int le_descriptor;
 int le_psessionpool;
-#ifdef PHP_OCI8_HAVE_COLLECTIONS 
+#ifdef PHP_OCI8_HAVE_COLLECTIONS
 int le_collection;
 #endif
 
@@ -86,6 +86,7 @@ zend_class_entry *oci_coll_class_entry_ptr;
 /* static protos {{{ */
 static void php_oci_connection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
 static void php_oci_pconnection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
+static void php_oci_pconnection_list_np_dtor (zend_rsrc_list_entry * TSRMLS_DC);
 static void php_oci_statement_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
 static void php_oci_descriptor_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
 static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC);
@@ -107,6 +108,7 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool
 static int php_oci_old_create_session(php_oci_connection *connection, zstr dbname, int dbname_len, zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, int session_mode, zend_uchar type TSRMLS_DC);
 static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, int charsetid, zend_uchar type TSRMLS_DC);
 static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, char *hash_key, int hash_key_len, int charsetid, zend_uchar type TSRMLS_DC);
+static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC);
 /* }}} */
 
 /* {{{ dynamically loadable module stuff */
@@ -211,184 +213,184 @@ PHP_FUNCTION(oci_collection_trim);
 /* {{{ extension definition structures
 */
 static const zend_function_entry php_oci_functions[] = {
-       PHP_FE(oci_define_by_name,          oci_third_arg_force_ref)
-       PHP_FE(oci_bind_by_name,            oci_third_arg_force_ref)
-       PHP_FE(oci_bind_array_by_name,      oci_third_arg_force_ref)
-       PHP_FE(oci_field_is_null,           NULL)
-       PHP_FE(oci_field_name,              NULL)
-       PHP_FE(oci_field_size,              NULL)
-       PHP_FE(oci_field_scale,             NULL)
-       PHP_FE(oci_field_precision,         NULL)
-       PHP_FE(oci_field_type,              NULL)
-       PHP_FE(oci_field_type_raw,          NULL)
-       PHP_FE(oci_execute,                 NULL)
-       PHP_FE(oci_cancel,                  NULL)
-       PHP_FE(oci_fetch,                   NULL)
-       PHP_FE(oci_fetch_object,            NULL)
-       PHP_FE(oci_fetch_row,               NULL)
-       PHP_FE(oci_fetch_assoc,             NULL)
-       PHP_FE(oci_fetch_array,             NULL)
-       PHP_FE(ocifetchinto,                oci_second_arg_force_ref)
-       PHP_FE(oci_fetch_all,               oci_second_arg_force_ref)
-       PHP_FE(oci_free_statement,          NULL)
-       PHP_FE(oci_internal_debug,          NULL)
-       PHP_FE(oci_num_fields,              NULL)
-       PHP_FE(oci_parse,                   NULL)
-       PHP_FE(oci_new_cursor,              NULL)
-       PHP_FE(oci_result,                  NULL)
-       PHP_FE(oci_server_version,          NULL)
-       PHP_FE(oci_statement_type,          NULL)
-       PHP_FE(oci_num_rows,                NULL)
-       PHP_FE(oci_close,                   NULL)
-       PHP_FE(oci_connect,                 NULL)
-       PHP_FE(oci_new_connect,             NULL)
-       PHP_FE(oci_pconnect,                NULL)
-       PHP_FE(oci_error,                   NULL)
-       PHP_FE(oci_free_descriptor,         NULL)
-       PHP_FE(oci_lob_save,                NULL)
-       PHP_FE(oci_lob_import,              NULL)
-       PHP_FE(oci_lob_size,                NULL)       
-       PHP_FE(oci_lob_load,                NULL)
-       PHP_FE(oci_lob_read,                NULL)
-       PHP_FE(oci_lob_eof,                 NULL)       
-       PHP_FE(oci_lob_tell,                NULL)
-       PHP_FE(oci_lob_truncate,            NULL)
-       PHP_FE(oci_lob_erase,               NULL)
-       PHP_FE(oci_lob_flush,               NULL)
-       PHP_FE(ocisetbufferinglob,          NULL)
-       PHP_FE(ocigetbufferinglob,          NULL)
-       PHP_FE(oci_lob_is_equal,                    NULL)
-       PHP_FE(oci_lob_rewind,              NULL)
-       PHP_FE(oci_lob_write,               NULL)
-       PHP_FE(oci_lob_append,              NULL)
-       PHP_FE(oci_lob_copy,                NULL)
-       PHP_FE(oci_lob_export,              NULL)
-       PHP_FE(oci_lob_seek,                NULL)
-       PHP_FE(oci_commit,                  NULL)
-       PHP_FE(oci_rollback,                NULL)
-       PHP_FE(oci_new_descriptor,          NULL)
-       PHP_FE(oci_set_prefetch,            NULL)
-       PHP_FE(oci_password_change,         NULL)
+       PHP_FE(oci_define_by_name,                      oci_third_arg_force_ref)
+       PHP_FE(oci_bind_by_name,                        oci_third_arg_force_ref)
+       PHP_FE(oci_bind_array_by_name,          oci_third_arg_force_ref)
+       PHP_FE(oci_field_is_null,                       NULL)
+       PHP_FE(oci_field_name,                          NULL)
+       PHP_FE(oci_field_size,                          NULL)
+       PHP_FE(oci_field_scale,                         NULL)
+       PHP_FE(oci_field_precision,                     NULL)
+       PHP_FE(oci_field_type,                          NULL)
+       PHP_FE(oci_field_type_raw,                      NULL)
+       PHP_FE(oci_execute,                                     NULL)
+       PHP_FE(oci_cancel,                                      NULL)
+       PHP_FE(oci_fetch,                                       NULL)
+       PHP_FE(oci_fetch_object,                        NULL)
+       PHP_FE(oci_fetch_row,                           NULL)
+       PHP_FE(oci_fetch_assoc,                         NULL)
+       PHP_FE(oci_fetch_array,                         NULL)
+       PHP_FE(ocifetchinto,                            oci_second_arg_force_ref)
+       PHP_FE(oci_fetch_all,                           oci_second_arg_force_ref)
+       PHP_FE(oci_free_statement,                      NULL)
+       PHP_FE(oci_internal_debug,                      NULL)
+       PHP_FE(oci_num_fields,                          NULL)
+       PHP_FE(oci_parse,                                       NULL)
+       PHP_FE(oci_new_cursor,                          NULL)
+       PHP_FE(oci_result,                                      NULL)
+       PHP_FE(oci_server_version,                      NULL)
+       PHP_FE(oci_statement_type,                      NULL)
+       PHP_FE(oci_num_rows,                            NULL)
+       PHP_FE(oci_close,                                       NULL)
+       PHP_FE(oci_connect,                                     NULL)
+       PHP_FE(oci_new_connect,                         NULL)
+       PHP_FE(oci_pconnect,                            NULL)
+       PHP_FE(oci_error,                                       NULL)
+       PHP_FE(oci_free_descriptor,                     NULL)
+       PHP_FE(oci_lob_save,                            NULL)
+       PHP_FE(oci_lob_import,                          NULL)
+       PHP_FE(oci_lob_size,                            NULL)
+       PHP_FE(oci_lob_load,                            NULL)
+       PHP_FE(oci_lob_read,                            NULL)
+       PHP_FE(oci_lob_eof,                                     NULL)
+       PHP_FE(oci_lob_tell,                            NULL)
+       PHP_FE(oci_lob_truncate,                        NULL)
+       PHP_FE(oci_lob_erase,                           NULL)
+       PHP_FE(oci_lob_flush,                           NULL)
+       PHP_FE(ocisetbufferinglob,                      NULL)
+       PHP_FE(ocigetbufferinglob,                      NULL)
+       PHP_FE(oci_lob_is_equal,                        NULL)
+       PHP_FE(oci_lob_rewind,                          NULL)
+       PHP_FE(oci_lob_write,                           NULL)
+       PHP_FE(oci_lob_append,                          NULL)
+       PHP_FE(oci_lob_copy,                            NULL)
+       PHP_FE(oci_lob_export,                          NULL)
+       PHP_FE(oci_lob_seek,                            NULL)
+       PHP_FE(oci_commit,                                      NULL)
+       PHP_FE(oci_rollback,                            NULL)
+       PHP_FE(oci_new_descriptor,                      NULL)
+       PHP_FE(oci_set_prefetch,                        NULL)
+       PHP_FE(oci_password_change,                     NULL)
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
-       PHP_FE(oci_free_collection,         NULL)
-       PHP_FE(oci_collection_append,       NULL)
-       PHP_FE(oci_collection_element_get,      NULL)
-       PHP_FE(oci_collection_element_assign,   NULL)
-       PHP_FE(oci_collection_assign,       NULL)
-       PHP_FE(oci_collection_size,         NULL)
-       PHP_FE(oci_collection_max,          NULL)
-       PHP_FE(oci_collection_trim,         NULL)
-       PHP_FE(oci_new_collection,          NULL)
+       PHP_FE(oci_free_collection,                     NULL)
+       PHP_FE(oci_collection_append,           NULL)
+       PHP_FE(oci_collection_element_get,      NULL)
+       PHP_FE(oci_collection_element_assign,   NULL)
+       PHP_FE(oci_collection_assign,           NULL)
+       PHP_FE(oci_collection_size,                     NULL)
+       PHP_FE(oci_collection_max,                      NULL)
+       PHP_FE(oci_collection_trim,                     NULL)
+       PHP_FE(oci_new_collection,                      NULL)
 #endif
-       
-       PHP_FALIAS(oci_free_cursor,     oci_free_statement,       NULL)
-       PHP_FALIAS(ocifreecursor,       oci_free_statement,       NULL)
-       PHP_FALIAS(ocibindbyname,       oci_bind_by_name,       oci_third_arg_force_ref)
-       PHP_FALIAS(ocidefinebyname,     oci_define_by_name,     oci_third_arg_force_ref)
-       PHP_FALIAS(ocicolumnisnull,     oci_field_is_null,      NULL)
-       PHP_FALIAS(ocicolumnname,       oci_field_name,         NULL)
-       PHP_FALIAS(ocicolumnsize,       oci_field_size,         NULL)
-       PHP_FALIAS(ocicolumnscale,      oci_field_scale,        NULL)
-       PHP_FALIAS(ocicolumnprecision,  oci_field_precision,    NULL)
-       PHP_FALIAS(ocicolumntype,       oci_field_type,         NULL)
-       PHP_FALIAS(ocicolumntyperaw,    oci_field_type_raw,     NULL)
-       PHP_FALIAS(ociexecute,          oci_execute,            NULL)
-       PHP_FALIAS(ocicancel,           oci_cancel,             NULL)
-       PHP_FALIAS(ocifetch,            oci_fetch,              NULL)
-       PHP_FALIAS(ocifetchstatement,   oci_fetch_all,          oci_second_arg_force_ref)
-       PHP_FALIAS(ocifreestatement,    oci_free_statement,     NULL)
-       PHP_FALIAS(ociinternaldebug,    oci_internal_debug,     NULL)
-       PHP_FALIAS(ocinumcols,          oci_num_fields,         NULL)
-       PHP_FALIAS(ociparse,            oci_parse,              NULL)
-       PHP_FALIAS(ocinewcursor,        oci_new_cursor,         NULL)
-       PHP_FALIAS(ociresult,           oci_result,             NULL)
-       PHP_FALIAS(ociserverversion,    oci_server_version,     NULL)
-       PHP_FALIAS(ocistatementtype,    oci_statement_type,     NULL)
-       PHP_FALIAS(ocirowcount,         oci_num_rows,           NULL)
-       PHP_FALIAS(ocilogoff,           oci_close,              NULL)
-       PHP_FALIAS(ocilogon,            oci_connect,            NULL)
-       PHP_FALIAS(ocinlogon,           oci_new_connect,        NULL)
-       PHP_FALIAS(ociplogon,           oci_pconnect,           NULL)
-       PHP_FALIAS(ocierror,            oci_error,              NULL)
-       PHP_FALIAS(ocifreedesc,         oci_free_descriptor,    NULL)
-       PHP_FALIAS(ocisavelob,          oci_lob_save,           NULL)
-       PHP_FALIAS(ocisavelobfile,      oci_lob_import,         NULL)
-       PHP_FALIAS(ociwritelobtofile,   oci_lob_export,         NULL)
-       PHP_FALIAS(ociloadlob,          oci_lob_load,           NULL)
-       PHP_FALIAS(ocicommit,           oci_commit,             NULL)
-       PHP_FALIAS(ocirollback,         oci_rollback,           NULL)
-       PHP_FALIAS(ocinewdescriptor,    oci_new_descriptor,     NULL)
-       PHP_FALIAS(ocisetprefetch,      oci_set_prefetch,       NULL)
-       PHP_FALIAS(ocipasswordchange,   oci_password_change,    NULL)
+
+       PHP_FALIAS(oci_free_cursor,             oci_free_statement,             NULL)
+       PHP_FALIAS(ocifreecursor,               oci_free_statement,             NULL)
+       PHP_FALIAS(ocibindbyname,               oci_bind_by_name,               oci_third_arg_force_ref)
+       PHP_FALIAS(ocidefinebyname,             oci_define_by_name,             oci_third_arg_force_ref)
+       PHP_FALIAS(ocicolumnisnull,             oci_field_is_null,              NULL)
+       PHP_FALIAS(ocicolumnname,               oci_field_name,                 NULL)
+       PHP_FALIAS(ocicolumnsize,               oci_field_size,                 NULL)
+       PHP_FALIAS(ocicolumnscale,              oci_field_scale,                NULL)
+       PHP_FALIAS(ocicolumnprecision,  oci_field_precision,    NULL)
+       PHP_FALIAS(ocicolumntype,               oci_field_type,                 NULL)
+       PHP_FALIAS(ocicolumntyperaw,    oci_field_type_raw,             NULL)
+       PHP_FALIAS(ociexecute,                  oci_execute,                    NULL)
+       PHP_FALIAS(ocicancel,                   oci_cancel,                             NULL)
+       PHP_FALIAS(ocifetch,                    oci_fetch,                              NULL)
+       PHP_FALIAS(ocifetchstatement,   oci_fetch_all,                  oci_second_arg_force_ref)
+       PHP_FALIAS(ocifreestatement,    oci_free_statement,             NULL)
+       PHP_FALIAS(ociinternaldebug,    oci_internal_debug,             NULL)
+       PHP_FALIAS(ocinumcols,                  oci_num_fields,                 NULL)
+       PHP_FALIAS(ociparse,                    oci_parse,                              NULL)
+       PHP_FALIAS(ocinewcursor,                oci_new_cursor,                 NULL)
+       PHP_FALIAS(ociresult,                   oci_result,                             NULL)
+       PHP_FALIAS(ociserverversion,    oci_server_version,             NULL)
+       PHP_FALIAS(ocistatementtype,    oci_statement_type,             NULL)
+       PHP_FALIAS(ocirowcount,                 oci_num_rows,                   NULL)
+       PHP_FALIAS(ocilogoff,                   oci_close,                              NULL)
+       PHP_FALIAS(ocilogon,                    oci_connect,                    NULL)
+       PHP_FALIAS(ocinlogon,                   oci_new_connect,                NULL)
+       PHP_FALIAS(ociplogon,                   oci_pconnect,                   NULL)
+       PHP_FALIAS(ocierror,                    oci_error,                              NULL)
+       PHP_FALIAS(ocifreedesc,                 oci_free_descriptor,    NULL)
+       PHP_FALIAS(ocisavelob,                  oci_lob_save,                   NULL)
+       PHP_FALIAS(ocisavelobfile,              oci_lob_import,                 NULL)
+       PHP_FALIAS(ociwritelobtofile,   oci_lob_export,                 NULL)
+       PHP_FALIAS(ociloadlob,                  oci_lob_load,                   NULL)
+       PHP_FALIAS(ocicommit,                   oci_commit,                             NULL)
+       PHP_FALIAS(ocirollback,                 oci_rollback,                   NULL)
+       PHP_FALIAS(ocinewdescriptor,    oci_new_descriptor,             NULL)
+       PHP_FALIAS(ocisetprefetch,              oci_set_prefetch,               NULL)
+       PHP_FALIAS(ocipasswordchange,   oci_password_change,    NULL)
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
-       PHP_FALIAS(ocifreecollection,   oci_free_collection,    NULL)
-       PHP_FALIAS(ocinewcollection,    oci_new_collection,     NULL)
-       PHP_FALIAS(ocicollappend,       oci_collection_append,  NULL)
-       PHP_FALIAS(ocicollgetelem,      oci_collection_element_get,     NULL)
-       PHP_FALIAS(ocicollassignelem,   oci_collection_element_assign,  NULL)
-       PHP_FALIAS(ocicollsize,         oci_collection_size,    NULL)
-       PHP_FALIAS(ocicollmax,          oci_collection_max,     NULL)
-       PHP_FALIAS(ocicolltrim,         oci_collection_trim,    NULL)
+       PHP_FALIAS(ocifreecollection,   oci_free_collection,    NULL)
+       PHP_FALIAS(ocinewcollection,    oci_new_collection,             NULL)
+       PHP_FALIAS(ocicollappend,               oci_collection_append,  NULL)
+       PHP_FALIAS(ocicollgetelem,              oci_collection_element_get,             NULL)
+       PHP_FALIAS(ocicollassignelem,   oci_collection_element_assign,  NULL)
+       PHP_FALIAS(ocicollsize,                 oci_collection_size,    NULL)
+       PHP_FALIAS(ocicollmax,                  oci_collection_max,             NULL)
+       PHP_FALIAS(ocicolltrim,                 oci_collection_trim,    NULL)
 #endif
        {NULL,NULL,NULL}
 };
 
 static const zend_function_entry php_oci_lob_class_functions[] = {
-       PHP_FALIAS(load,        oci_lob_load,           NULL)
-       PHP_FALIAS(tell,        oci_lob_tell,           NULL)
-       PHP_FALIAS(truncate,    oci_lob_truncate,       NULL)
-       PHP_FALIAS(erase,       oci_lob_erase,          NULL)
-       PHP_FALIAS(flush,       oci_lob_flush,          NULL)
-       PHP_FALIAS(setbuffering,ocisetbufferinglob,     NULL)
-       PHP_FALIAS(getbuffering,ocigetbufferinglob,     NULL)
-       PHP_FALIAS(rewind,      oci_lob_rewind,                 NULL)
-       PHP_FALIAS(read,        oci_lob_read,           NULL)
-       PHP_FALIAS(eof,         oci_lob_eof,            NULL)
-       PHP_FALIAS(seek,        oci_lob_seek,           NULL)   
-       PHP_FALIAS(write,       oci_lob_write,          NULL)
-       PHP_FALIAS(append,      oci_lob_append,         NULL)
-       PHP_FALIAS(size,        oci_lob_size,           NULL)
-       PHP_FALIAS(writetofile, oci_lob_export,         NULL)
-       PHP_FALIAS(export,      oci_lob_export,         NULL)
-       PHP_FALIAS(import,      oci_lob_import,         NULL)
+       PHP_FALIAS(load,                oci_lob_load,                   NULL)
+       PHP_FALIAS(tell,                oci_lob_tell,                   NULL)
+       PHP_FALIAS(truncate,    oci_lob_truncate,               NULL)
+       PHP_FALIAS(erase,               oci_lob_erase,                  NULL)
+       PHP_FALIAS(flush,               oci_lob_flush,                  NULL)
+       PHP_FALIAS(setbuffering,ocisetbufferinglob,             NULL)
+       PHP_FALIAS(getbuffering,ocigetbufferinglob,             NULL)
+       PHP_FALIAS(rewind,              oci_lob_rewind,                 NULL)
+       PHP_FALIAS(read,                oci_lob_read,                   NULL)
+       PHP_FALIAS(eof,                 oci_lob_eof,                    NULL)
+       PHP_FALIAS(seek,                oci_lob_seek,                   NULL)
+       PHP_FALIAS(write,               oci_lob_write,                  NULL)
+       PHP_FALIAS(append,              oci_lob_append,                 NULL)
+       PHP_FALIAS(size,                oci_lob_size,                   NULL)
+       PHP_FALIAS(writetofile, oci_lob_export,                 NULL)
+       PHP_FALIAS(export,              oci_lob_export,                 NULL)
+       PHP_FALIAS(import,              oci_lob_import,                 NULL)
 #ifdef HAVE_OCI8_TEMP_LOB
-       PHP_FALIAS(writetemporary,  oci_lob_write_temporary,    NULL)
-       PHP_FALIAS(close,           oci_lob_close,              NULL)
+       PHP_FALIAS(writetemporary,      oci_lob_write_temporary,        NULL)
+       PHP_FALIAS(close,                       oci_lob_close,                          NULL)
 #endif
-       PHP_FALIAS(save,        oci_lob_save,           NULL)
-       PHP_FALIAS(savefile,    oci_lob_import,         NULL)
-       PHP_FALIAS(free,        oci_free_descriptor,    NULL)
+       PHP_FALIAS(save,                oci_lob_save,                   NULL)
+       PHP_FALIAS(savefile,    oci_lob_import,                 NULL)
+       PHP_FALIAS(free,                oci_free_descriptor,    NULL)
        {NULL,NULL,NULL}
 };
 
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
 static const zend_function_entry php_oci_coll_class_functions[] = {
-       PHP_FALIAS(append,        oci_collection_append,            NULL)
-       PHP_FALIAS(getelem,       oci_collection_element_get,       NULL)
-       PHP_FALIAS(assignelem,    oci_collection_element_assign,    NULL)
-       PHP_FALIAS(assign,        oci_collection_assign,            NULL)
-       PHP_FALIAS(size,          oci_collection_size,              NULL)
-       PHP_FALIAS(max,           oci_collection_max,               NULL)
-       PHP_FALIAS(trim,          oci_collection_trim,              NULL)
-       PHP_FALIAS(free,          oci_free_collection,              NULL)
+       PHP_FALIAS(append,                oci_collection_append,                        NULL)
+       PHP_FALIAS(getelem,               oci_collection_element_get,           NULL)
+       PHP_FALIAS(assignelem,    oci_collection_element_assign,        NULL)
+       PHP_FALIAS(assign,                oci_collection_assign,                        NULL)
+       PHP_FALIAS(size,                  oci_collection_size,                          NULL)
+       PHP_FALIAS(max,                   oci_collection_max,                           NULL)
+       PHP_FALIAS(trim,                  oci_collection_trim,                          NULL)
+       PHP_FALIAS(free,                  oci_free_collection,                          NULL)
        {NULL,NULL,NULL}
 };
 #endif
 
 zend_module_entry oci8_module_entry = {
        STANDARD_MODULE_HEADER,
-       "oci8",               /* extension name */
-       php_oci_functions,    /* extension function list */
-       PHP_MINIT(oci),       /* extension-wide startup function */
-       PHP_MSHUTDOWN(oci),   /* extension-wide shutdown function */
-       PHP_RINIT(oci),       /* per-request startup function */
-       PHP_RSHUTDOWN(oci),   /* per-request shutdown function */
-       PHP_MINFO(oci),       /* information function */
+       "oci8",                           /* extension name */
+       php_oci_functions,        /* extension function list */
+       PHP_MINIT(oci),           /* extension-wide startup function */
+       PHP_MSHUTDOWN(oci),       /* extension-wide shutdown function */
+       PHP_RINIT(oci),           /* per-request startup function */
+       PHP_RSHUTDOWN(oci),       /* per-request shutdown function */
+       PHP_MINFO(oci),           /* information function */
        "1.3.1",
        PHP_MODULE_GLOBALS(oci),  /* globals descriptor */
-       PHP_GINIT(oci),           /* globals ctor */
-       NULL,                     /* globals dtor */
-       NULL,                     /* post deactivate */
+       PHP_GINIT(oci),                   /* globals ctor */
+       NULL,                                     /* globals dtor */
+       NULL,                                     /* post deactivate */
        STANDARD_MODULE_PROPERTIES_EX
 };
 /* }}} */
@@ -411,7 +413,7 @@ PHP_INI_END()
 */
 
 /* {{{ php_oci_init_global_handles()
- Initialize global handles only when they are needed 
+ Initialize global handles only when they are needed
 */
 static void php_oci_init_global_handles(TSRMLS_D)
 {
@@ -420,21 +422,21 @@ static void php_oci_init_global_handles(TSRMLS_D)
        text tmp_buf[PHP_OCI_ERRBUF_LEN];
 
        errcode = OCIEnvInit (&OCI_G(env), OCI_DEFAULT, 0, NULL);
-       
+
        if (errcode == OCI_ERROR) {
                goto oci_error;
        }
-       
+
        errcode = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL);
-       
+
        if (errcode == OCI_ERROR || errcode == OCI_SUCCESS_WITH_INFO) {
                goto oci_error;
        }
 
        return;
-       
+
 oci_error:
-       
+
        OCIErrorGet(OCI_G(env), (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR);
 
        if (error_code) {
@@ -443,12 +445,12 @@ oci_error:
                if (tmp_buf_len > 0 && tmp_buf[tmp_buf_len - 1] == '\n') {
                        tmp_buf[tmp_buf_len - 1] = '\0';
                }
-                       
+
                if (errcode != OCI_SUCCESS_WITH_INFO) {
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_ERROR: %s", tmp_buf);
-                       
+
                        OCIHandleFree((dvoid *) OCI_G(env), OCI_HTYPE_ENV);
-                       
+
                        OCI_G(env) = NULL;
                        OCI_G(err) = NULL;
                } else {
@@ -466,7 +468,7 @@ static void php_oci_cleanup_global_handles(TSRMLS_D)
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ERROR));
                OCI_G(err) = NULL;
        }
-       
+
        if (OCI_G(env)) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV));
                OCI_G(env) = NULL;
@@ -509,7 +511,7 @@ PHP_MINIT_FUNCTION(oci)
 
        le_statement = zend_register_list_destructors_ex(php_oci_statement_list_dtor, NULL, "oci8 statement", module_number);
        le_connection = zend_register_list_destructors_ex(php_oci_connection_list_dtor, NULL, "oci8 connection", module_number);
-       le_pconnection = zend_register_list_destructors_ex(NULL, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number);
+       le_pconnection = zend_register_list_destructors_ex(php_oci_pconnection_list_np_dtor, php_oci_pconnection_list_dtor, "oci8 persistent connection", module_number);
        le_psessionpool = zend_register_list_destructors_ex(NULL, php_oci_spool_list_dtor, "oci8 persistent session pool", module_number);
        le_descriptor = zend_register_list_destructors_ex(php_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number);
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
@@ -541,15 +543,15 @@ PHP_MINIT_FUNCTION(oci)
 
 /*     for $LOB->flush() */
        REGISTER_LONG_CONSTANT("OCI_LOB_BUFFER_FREE",OCI_LOB_BUFFER_FREE, CONST_CS | CONST_PERSISTENT);
-       
-/* for OCIBindByName (real "oci" names + short "php" names*/
+
+/* for OCIBindByName (real "oci" names + short "php" names */
        REGISTER_LONG_CONSTANT("SQLT_BFILEE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_CFILEE",SQLT_CFILEE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);       
-       REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);       
+       REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_RSET",SQLT_RSET, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_AFC",SQLT_AFC, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_CHR",SQLT_CHR, CONST_CS | CONST_PERSISTENT);
@@ -570,7 +572,7 @@ PHP_MINIT_FUNCTION(oci)
 
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
        REGISTER_LONG_CONSTANT("OCI_B_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);       
+       REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);
        REGISTER_STRING_CONSTANT("OCI_SYSDATE","SYSDATE", CONST_CS | CONST_PERSISTENT);
 #endif
 
@@ -595,7 +597,7 @@ PHP_MINIT_FUNCTION(oci)
        REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",PHP_OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",PHP_OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT);
 
-/* for OCINewDescriptor (real "oci" names + short "php" names*/
+/* for OCINewDescriptor (real "oci" names + short "php" names */
        REGISTER_LONG_CONSTANT("OCI_DTYPE_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_DTYPE_LOB",OCI_DTYPE_LOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_DTYPE_ROWID",OCI_DTYPE_ROWID, CONST_CS | CONST_PERSISTENT);
@@ -627,7 +629,7 @@ PHP_RINIT_FUNCTION(oci)
 PHP_MSHUTDOWN_FUNCTION(oci)
 {
        OCI_G(shutdown) = 1;
-       
+
        UNREGISTER_INI_ENTRIES();
 
 #ifndef ZTS
@@ -648,7 +650,7 @@ PHP_RSHUTDOWN_FUNCTION(oci)
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
        zend_hash_apply_with_argument(&EG(regular_list), (apply_func_arg_t) php_oci_list_helper, (void *)le_collection TSRMLS_CC);
 #endif
-       while (OCI_G(num_statements)) { 
+       while (OCI_G(num_statements)) {
                zend_hash_apply_with_argument(&EG(regular_list), (apply_func_arg_t) php_oci_list_helper, (void *)le_statement TSRMLS_CC);
        }
 #endif
@@ -682,8 +684,8 @@ PHP_MINFO_FUNCTION(oci)
        php_info_print_table_row(2, "Oracle Version", PHP_OCI8_VERSION );
        php_info_print_table_row(2, "Compile-time ORACLE_HOME", PHP_OCI8_DIR );
        php_info_print_table_row(2, "Libraries Used", PHP_OCI8_SHARED_LIBADD );
-#else 
-#      if defined(HAVE_OCI_INSTANT_CLIENT) && defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION) 
+#else
+#      if defined(HAVE_OCI_INSTANT_CLIENT) && defined(OCI_MAJOR_VERSION) && defined(OCI_MINOR_VERSION)
        snprintf(buf, sizeof(buf), "%d.%d", OCI_MAJOR_VERSION, OCI_MINOR_VERSION);
        php_info_print_table_row(2, "Oracle Instant Client Version", buf);
 #      endif
@@ -702,7 +704,7 @@ PHP_MINFO_FUNCTION(oci)
 #endif
 
        php_info_print_table_end();
-       
+
        DISPLAY_INI_ENTRIES();
 }
 /* }}} */
@@ -714,8 +716,11 @@ PHP_MINFO_FUNCTION(oci)
 static void php_oci_connection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
 {
        php_oci_connection *connection = (php_oci_connection *)entry->ptr;
-       php_oci_connection_close(connection TSRMLS_CC);
-       OCI_G(num_links)--;
+
+       if (connection) {
+               php_oci_connection_close(connection TSRMLS_CC);
+               OCI_G(num_links)--;
+       }
 } /* }}} */
 
 /* {{{ php_oci_pconnection_list_dtor()
@@ -723,8 +728,25 @@ static void php_oci_connection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
 static void php_oci_pconnection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
 {
        php_oci_connection *connection = (php_oci_connection *)entry->ptr;
-       php_oci_connection_close(connection TSRMLS_CC);
-       OCI_G(num_persistent)--;
+
+       if (connection) {
+               php_oci_connection_close(connection TSRMLS_CC);
+               OCI_G(num_persistent)--;
+       }
+} /* }}} */
+
+/* {{{ php_oci_pconnection_list_np_dtor()
+ Non-Persistent destructor for persistent connection - This gets invoked when
+ the refcount of this goes to zero in the regular list */
+static void php_oci_pconnection_list_np_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
+{
+       php_oci_connection *connection = (php_oci_connection *)entry->ptr;
+
+       /* If it is a bad connection, clean it up. This is the sole purpose of this dtor. We should ideally do a hash_del also, but this scenario is currently not possible. */
+       if (connection && !connection->is_open && !connection->is_stub) {
+               php_oci_connection_close(connection TSRMLS_CC);
+               OCI_G(num_persistent)--;
+       }
 } /* }}} */
 
 /* {{{ php_oci_statement_list_dtor()
@@ -790,12 +812,6 @@ void php_oci_bind_hash_dtor(void *data)
                efree(bind->array.indicators);
        }
 
-/*
-       if (bind->array.retcodes) {
-               efree(bind->array.retcodes);
-       } 
-*/
-
        zval_ptr_dtor(&bind->zval);
 }
 /* }}} */
@@ -831,7 +847,7 @@ void php_oci_descriptor_flush_hash_dtor(void *data)
 {
        php_oci_descriptor *descriptor = *(php_oci_descriptor **)data;
        TSRMLS_FETCH();
-       
+
        if (descriptor && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED && (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE)) {
                php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
                descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
@@ -846,7 +862,7 @@ int php_oci_descriptor_delete_from_hash(void *data, void *id TSRMLS_DC)
 {
        php_oci_descriptor *descriptor = *(php_oci_descriptor **)data;
        int *desc_id = (int *) id;
-       
+
        if (descriptor && desc_id && descriptor->id == *desc_id) {
                return 1;
        }
@@ -881,7 +897,7 @@ sb4 php_oci_error(OCIError *err_p, sword status TSRMLS_DC)
                case OCI_NO_DATA:
                        php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NO_DATA");
                        break;
-               case OCI_ERROR: 
+               case OCI_ERROR:
                        errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC);
                        if (errbuf) {
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "%R", (UG(unicode) ? IS_UNICODE : IS_STRING), errbuf);
@@ -950,7 +966,7 @@ sb4 php_oci_fetch_errmsg(OCIError *error_handle, text **error_buf TSRMLS_DC)
                                        err_buf[err_buf_len - 1] = '\0';
                                }
                        }
-                       
+
                        if (err_buf_len && error_buf) {
                                *error_buf = (text *)estrndup((char *)err_buf, TEXT_BYTES(err_buf_len));
                        }
@@ -962,7 +978,7 @@ sb4 php_oci_fetch_errmsg(OCIError *error_handle, text **error_buf TSRMLS_DC)
 #ifdef HAVE_OCI8_ATTR_STATEMENT
 /* {{{ php_oci_fetch_sqltext_offset()
  Compute offset in the SQL statement */
-int php_oci_fetch_sqltext_offset(php_oci_statement *statement,  zstr *sqltext, ub2 *error_offset TSRMLS_DC)
+int php_oci_fetch_sqltext_offset(php_oci_statement *statement, zstr *sqltext, ub2 *error_offset TSRMLS_DC)
 {
        ub4 sqltext_len = 0;
 
@@ -974,15 +990,15 @@ int php_oci_fetch_sqltext_offset(php_oci_statement *statement,  zstr *sqltext, u
        } else {
                PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *) &(sqltext->s), (ub4 *)&sqltext_len, OCI_ATTR_STATEMENT, statement->err));
        }
-       
-       if (statement->errcode != OCI_SUCCESS) { 
+
+       if (statement->errcode != OCI_SUCCESS) {
                php_oci_error(statement->err, statement->errcode TSRMLS_CC);
                return 1;
        }
 
        PHP_OCI_CALL_RETURN(statement->errcode, OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)error_offset, (ub4 *)0, OCI_ATTR_PARSE_ERROR_OFFSET, statement->err));
-       
-       if (statement->errcode != OCI_SUCCESS) { 
+
+       if (statement->errcode != OCI_SUCCESS) {
                php_oci_error(statement->err, statement->errcode TSRMLS_CC);
                return 1;
        }
@@ -990,7 +1006,7 @@ int php_oci_fetch_sqltext_offset(php_oci_statement *statement,  zstr *sqltext, u
 } /* }}} */
 #endif
 
-/* {{{ php_oci_do_connect() 
+/* {{{ php_oci_do_connect()
  Connect wrapper */
 void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclusive)
 {
@@ -1006,7 +1022,7 @@ void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclus
        /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "TT|TTl", &username, &username_len, &username_type, &password, &password_len, &password_type, &dbname, &dbname_len, &dbname_type, &charset, &charset_len, &charset_type, &session_mode) == FAILURE) {
                return;
-       } 
+       }
 
        connection = php_oci_do_connect_ex(username, username_len, password, password_len, NULL_ZSTR, 0, dbname, dbname_len, charset, session_mode, persistent, exclusive, username_type TSRMLS_CC);
 
@@ -1014,12 +1030,12 @@ void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclus
                RETURN_FALSE;
        }
        RETURN_RESOURCE(connection->rsrc_id);
-       
+
 } /* }}} */
 
 /* {{{ php_oci_do_connect_ex()
  * The real connect function. Allocates all the resources needed, establishes the connection and returns the result handle (or NULL) */
-php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC) 
+php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC)
 {
        zend_rsrc_list_entry *le;
        zend_rsrc_list_entry new_le;
@@ -1027,13 +1043,14 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
        smart_str hashed_details = {0};
        time_t timestamp;
        php_oci_spool *session_pool = NULL;
-       zend_bool use_spool = 1;       /* Default is to use client-side session pool */
+       zend_bool use_spool = 1;           /* Default is to use client-side session pool */
+       zend_bool ping_done = 0;
 
 #if HAVE_OCI_ENV_NLS_CREATE
        ub2 charsetid = 0;
        ub2 charsetid_nls_lang = 0;
 #endif
-       
+
        switch (session_mode) {
                case OCI_DEFAULT:
                        break;
@@ -1058,34 +1075,40 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
        /* We cannot use the new session create logic (OCISessionGet from
         * client-side session pool) when privileged connect or password
         * change is attempted. TODO: Remove this once OCI provides
-        * capability 
+        * capability
         */
-       if ((session_mode==OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) {
+       if ((session_mode == OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) {
                use_spool = 0;
-       }
-       else if (UG(unicode)) {
+       } else if (UG(unicode)) {
                /* Pre 10.1 session pool does not support unicode - bypass pool */
-#ifndef HAVE_OCI_LOB_READ2  /* For finding 10.1+ client */
+#ifndef HAVE_OCI_LOB_READ2     /* For finding 10.1+ client */
                use_spool = 0;
 #endif
        }
 
-       smart_str_appendl_ex(&hashed_details, "oci8___", sizeof("oci8___") - 1, 0);
+       smart_str_appendl_ex(&hashed_details, "oci8***", sizeof("oci8***") - 1, 0);
        smart_str_appendl_ex(&hashed_details, username.s, USTR_BYTES(type, username_len), 0);
-       smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0);
+       smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
+
+       /* DRCP: connection_class is an attribute of a connection */
+       if (OCI_G(connection_class)){
+               smart_str_appendl_ex(&hashed_details, OCI_G(connection_class), (ub4)UG(unicode) ? USTR_BYTES(type, u_strlen((UChar *)OCI_G(connection_class))) : strlen(OCI_G(connection_class)), 0);
+       }
+       smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
+
        if (password_len) {
                ulong password_hash;
                password_hash = zend_u_inline_hash_func(type, password, password_len);
                smart_str_append_unsigned_ex(&hashed_details, password_hash, 0);
        }
-       smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0);
+       smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
 
        if (dbname_len) {
                smart_str_appendl_ex(&hashed_details, dbname.s, USTR_BYTES(type, dbname_len), 0);
        }
-       smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0);
+       smart_str_appendl_ex(&hashed_details, "**", sizeof("**") - 1, 0);
 
-       /* Initialize global handles if the weren't initialized before */
+       /* Initialize global handles if they weren't initialized before */
        if (OCI_G(env) == NULL) {
                php_oci_init_global_handles(TSRMLS_C);
        }
@@ -1112,8 +1135,7 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                        }
                        smart_str_append_unsigned_ex(&hashed_details, charsetid_nls_lang, 0);
                }
-       }
-       else {
+       } else {
                charsetid = OCI_UTF16ID;
                smart_str_append_unsigned_ex(&hashed_details, charsetid, 0);
        }
@@ -1125,13 +1147,13 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
 #endif
 
        timestamp = time(NULL);
-       
+
        smart_str_append_unsigned_ex(&hashed_details, session_mode, 0);
        smart_str_0(&hashed_details);
 
        /* make it lowercase */
        php_strtolower(hashed_details.c, hashed_details.len);
-       
+
        if (!exclusive && !new_password.v) {
                zend_bool found = 0;
 
@@ -1139,7 +1161,7 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                        found = 1;
                        /* found */
                        if (le->type == le_pconnection) {
-                               connection = (php_oci_connection *)le->ptr;     
+                               connection = (php_oci_connection *)le->ptr;
                        }
                } else if (!persistent && zend_hash_find(&EG(regular_list), hashed_details.c, hashed_details.len+1, (void **) &le) == SUCCESS) {
                        found = 1;
@@ -1156,21 +1178,19 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                }
 
                /* Debug statements {{{ */
-               if (OCI_G(debug_mode)) { 
+               if (OCI_G(debug_mode)) {
                        if (connection && connection->is_stub) {
                                php_printf ("OCI8 DEBUG L1: Got a cached stub: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
-                       }
-                       else if (connection) {
+                       } else if (connection) {
                                php_printf ("OCI8 DEBUG L1: Got a cached connection: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
-                       }
-                       else {
+                       } else {
                                php_printf ("OCI8 DEBUG L1: Got NO cached connection at (%s:%d) \n", __FILE__, __LINE__);
                        }
                } /* }}} */
 
-               /* If we got a pconnection stub, then 'load'(OCISessionGet) the 
+               /* If we got a pconnection stub, then 'load'(OCISessionGet) the
                 * real connection from its private spool
-                * A connection is a stub if it is only a cached structure and the 
+                * A connection is a stub if it is only a cached structure and the
                 * real connection is released to its underlying private session pool.
                 * We currently do not have stub support for non-persistent conns.
                 *
@@ -1183,26 +1203,29 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
 
                                return NULL;
                        }
+                       /* We do the ping in php_oci_create_session, no need to ping again below */
+                       ping_done = 1;
                }
-                       
+
                if (connection) {
                        if (connection->is_open) {
                                /* found an open connection. now ping it */
                                if (connection->is_persistent) {
+                                       int rsrc_type;
+
                                        /* check connection liveness in the following order:
                                         * 1) always check OCI_ATTR_SERVER_STATUS
                                         * 2) see if it's time to ping it
-                                        * 3) ping it if needed 
-                                        * */
+                                        * 3) ping it if needed
+                                        */
                                        if (php_oci_connection_status(connection TSRMLS_CC)) {
-                                               /* only ping if: 
+                                               /* only ping if:
                                                 * 1) next_ping > 0, which means that ping_interval is not -1 (aka "Off")
                                                 * 2) current_timestamp > next_ping, which means "it's time to check if it's still alive"
-                                                * */
-                                               if ( (connection->next_ping > 0) && (timestamp >= connection->next_ping) && !php_oci_connection_ping(connection TSRMLS_CC)) {
+                                                */
+                                               if ( !ping_done && (*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp)) && !php_oci_connection_ping(connection TSRMLS_CC) ) {
                                                        /* server died */
                                                } else {
-                                                       int rsrc_type;
                                                        php_oci_connection *tmp;
 
                                                        /* okay, the connection is open and the server is still alive */
@@ -1221,6 +1244,18 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                                        }
                                        /* server died */
                                        connection->is_open = 0;
+                                       connection->used_this_request = 1;
+
+                                       /* Connection is no more part of the persistent list */
+                                       free(connection->hash_key);
+                                       connection->hash_key = NULL;
+                                       connection->hash_key_len = 0;
+
+                                       /* We have to do a hash_del but need to preserve the resource if there is a positive refcount. Set the data pointer in the list entry to NULL */
+                                       if (zend_list_find(connection->rsrc_id, &rsrc_type)) {
+                                               le->ptr = NULL;
+                                       }
+
                                        zend_hash_del(&EG(persistent_list), hashed_details.c, hashed_details.len+1);
                                        connection = NULL;
                                        goto open;
@@ -1247,22 +1282,22 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
 open:
 
        /* Check if we have reached max_persistent. If so, try to remove a few
-        * timeout out connections. As last resort, return a non-persistent conn
+        * timed-out connections. As a last resort, return a non-persistent connection.
         */
        if (persistent) {
                zend_bool alloc_non_persistent = 0;
-                       
+
                if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) {
                        /* try to find an idle connection and kill it */
                        zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC);
-                       
+
                        if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) {
                                /* all persistent connactions are in use, fallback to non-persistent connection creation */
                                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Too many open persistent connections (%ld)", OCI_G(num_persistent));
                                alloc_non_persistent = 1;
                        }
                }
-               
+
                if (alloc_non_persistent) {
                        connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
                        connection->hash_key = estrndup(hashed_details.c, hashed_details.len);
@@ -1282,9 +1317,9 @@ open:
        }
 
        /* {{{ Get the session pool that suits this connection request from the
-        * persistent list. This step is only for non-persistent connections as 
+        * persistent list. This step is only for non-persistent connections as
         * persistent connections have private session pools. Non-persistent conns
-        * use shared session pool to allow for optimizations such as caching the 
+        * use shared session pool to allow for optimizations such as caching the
         * physical connection (for DRCP) even when the non-persistent php connection
         * is destroyed.
         * TODO: Unconditionally do this once OCI provides extended OCISessionGet capability */
@@ -1294,20 +1329,14 @@ open:
                        php_oci_connection_close(connection TSRMLS_CC);
                        smart_str_free_ex(&hashed_details, 0);
                        return NULL;
-               }   
+               }
        } /* }}} */
 
        connection->idle_expiry = (OCI_G(persistent_timeout) > 0) ? (timestamp + OCI_G(persistent_timeout)) : 0;
-       if (OCI_G(ping_interval) >= 0) {
-               connection->next_ping = timestamp + OCI_G(ping_interval);
-       } else {
-               /* -1 means "Off" */
-               connection->next_ping = 0;
-       }
-       
+
        /* mark password as unchanged by PHP during the duration of the database session */
        connection->passwd_changed = 0;
-       
+
        smart_str_free_ex(&hashed_details, 0);
 
 #if HAVE_OCI_ENV_NLS_CREATE
@@ -1318,21 +1347,20 @@ open:
        }
 #endif
 
-       /* Old session creation semantics when session pool cannot be used Eg: privileged connect/password change {{{*/
+       /* Old session creation semantics when session pool cannot be used Eg: privileged connect/password change */
        if ( !use_spool) {
                if (php_oci_old_create_session(connection, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) {
                        php_oci_connection_close(connection TSRMLS_CC);
                        return NULL;
                }
-       } /* }}} */
-       else  {
+       } else  {
                /* create using the client-side session pool */
                if (php_oci_create_session(connection, session_pool, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) {
                        php_oci_connection_close(connection TSRMLS_CC);
                        return NULL;
-               }       
+               }
        }
-       
+
        /* mark it as open */
        connection->is_open = 1;
 
@@ -1351,16 +1379,15 @@ open:
                zend_hash_update(&EG(regular_list), connection->hash_key, connection->hash_key_len+1, (void *)&new_le, sizeof(zend_rsrc_list_entry), NULL);
                OCI_G(num_links)++;
        } else {
-               connection->rsrc_id = zend_list_insert(connection, le_connection);      
+               connection->rsrc_id = zend_list_insert(connection, le_connection);
                OCI_G(num_links)++;
        }
 
        /* Debug statements {{{ */
-       if (OCI_G(debug_mode)) { 
+       if (OCI_G(debug_mode)) {
                if (connection->is_persistent) {
                        php_printf ("OCI8 DEBUG L1: New Persistent Connection address:(%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
-               }
-               else {
+               } else {
                        php_printf ("OCI8 DEBUG L1: New Non-Persistent Connection address: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
                }
                php_printf ("OCI8 DEBUG L1: num_persistent=(%ld), num_links=(%ld) at (%s:%d) \n", OCI_G(num_persistent), OCI_G(num_links), __FILE__, __LINE__);
@@ -1378,20 +1405,19 @@ static int php_oci_connection_ping(php_oci_connection *connection TSRMLS_DC)
         * ORA-1010 (invalid OCI operation) such as from Pre-10.1 servers,
         * the error is still from the server and we would have
         * successfully performed a roundtrip and validated the
-        * connection. Use OCIServerVersion for Pre-10.1 clients
+        * connection. Use OCIServerVersion for Pre-10.2 clients
         */
-#if HAVE_OCI_LOB_READ2  /* 10.1 and greater client - OCIPing was first available in 10.1 */
+#if ( (OCI_MAJOR_VERSION > 10) || ((OCI_MAJOR_VERSION == 10) && (OCI_MINOR_VERSION > 2)) )     /* OCIPing available 10.2 onwards */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT));
 #else
        char version[256];
        /* use good old OCIServerVersion() */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text*)version, sizeof(version), OCI_HTYPE_SVCCTX));
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->svc, OCI_G(err), (text *)version, sizeof(version), OCI_HTYPE_SVCCTX));
 #endif
-       
+
        if (OCI_G(errcode) == OCI_SUCCESS) {
                return 1;
-       }
-       else {
+       } else {
                sb4 error_code = 0;
                text tmp_buf[PHP_OCI_ERRBUF_LEN];
 
@@ -1402,7 +1428,7 @@ static int php_oci_connection_ping(php_oci_connection *connection TSRMLS_DC)
                }
        }
 
-       /* ignore errors here, just return failure 
+       /* ignore errors here, just return failure
         * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
        return 0;
 }
@@ -1416,12 +1442,12 @@ static int php_oci_connection_status(php_oci_connection *connection TSRMLS_DC)
 
        /* get OCI_ATTR_SERVER_STATUS */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->server, OCI_HTYPE_SERVER, (dvoid *)&ss, (ub4 *)0, OCI_ATTR_SERVER_STATUS, OCI_G(err)));
-       
+
        if (OCI_G(errcode) == OCI_SUCCESS && ss == OCI_SERVER_NORMAL) {
                return 1;
        }
 
-       /* ignore errors here, just return failure 
+       /* ignore errors here, just return failure
         * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
        return 0;
 }
@@ -1457,7 +1483,7 @@ int php_oci_connection_commit(php_oci_connection *connection TSRMLS_DC)
        return 0;
 } /* }}} */
 
-/* {{{ php_oci_connection_close() 
+/* {{{ php_oci_connection_close()
  Close the connection and free all its resources */
 static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
 {
@@ -1469,7 +1495,7 @@ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
                efree(connection->descriptors);
        }
 
-       if (connection->svc) {  
+       if (connection->svc) {
                /* rollback outstanding transactions */
                if (connection->needs_commit) {
                        if (php_oci_connection_rollback(connection TSRMLS_CC)) {
@@ -1480,11 +1506,18 @@ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
        }
 
        if (!connection->is_stub && connection->svc && connection->is_open) {
+               /* Update the next_ping in the connection. Needed also for non-peristent because non-persistent DRCP caches connection underneath */
+               if (OCI_G(ping_interval) >= 0) {
+                       *(connection->next_pingp) = time(NULL) + OCI_G(ping_interval);
+               } else {
+                       /* ping_interval is -1 */
+                       *(connection->next_pingp) = 0;
+               }
+
                /* Use OCISessionRelease for session pool connections */
                if (connection->using_spool) {
                        PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) 0));
-               }
-               else {
+               } else {
                        PHP_OCI_CALL(OCISessionEnd, (connection->svc, connection->err, connection->session, (ub4) 0));
                }
        }
@@ -1495,31 +1528,30 @@ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
        if (connection->authinfo) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->authinfo, (ub4) OCI_HTYPE_AUTHINFO));
        }
-       
-       /* No Handlefrees for session pool connections {{{ */
+
+       /* No Handlefrees for session pool connections */
        if (!connection->using_spool) {
                if (connection->session) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->session, OCI_HTYPE_SESSION));
                }
-               
+
                if (connection->is_attached) {
                        PHP_OCI_CALL(OCIServerDetach, (connection->server, OCI_G(err), OCI_DEFAULT));
                }
-               
+
                if (connection->svc) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX));
                }
-               
+
                if (connection->server) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER));
                }
-               
+
                if (connection->env) {
                        PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV));
                }
-       }  /* }}} */
-       else if (connection->private_spool) {
-       /* Keep this as the last member to be freed, as there are dependencies 
+       } else if (connection->private_spool) {
+       /* Keep this as the last member to be freed, as there are dependencies
         * (like env) on the session pool
         */
                php_oci_spool_close(connection->private_spool TSRMLS_CC);
@@ -1541,7 +1573,7 @@ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
        return result;
 } /* }}} */
 
-/* {{{ php_oci_connection_release() 
+/* {{{ php_oci_connection_release()
  Release the connection to its session pool. This looks similar to php_oci_connection_close, but the latter is used for connections that are to be terminated. The latter was not overloaded for "release" because of too many callers */
 int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC)
 {
@@ -1558,7 +1590,7 @@ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC)
                connection->descriptors = NULL;
        }
 
-       if (connection->svc) {  
+       if (connection->svc) {
                /* rollback outstanding transactions */
                if (connection->needs_commit) {
                        if (php_oci_connection_rollback(connection TSRMLS_CC)) {
@@ -1570,8 +1602,15 @@ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC)
 
        /* Release the session */
        if (connection->svc) {
-               PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,
-                        0, OCI_DEFAULT));
+               if (OCI_G(ping_interval) >= 0) {
+                       *(connection->next_pingp) = time(NULL) + OCI_G(ping_interval);
+               } else {
+                       /* ping_interval is -1 */
+                       *(connection->next_pingp) = 0;
+               }
+
+               PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,
+                                               0, result ? OCI_SESSRLS_DROPSESS : OCI_DEFAULT));
        }
 
        /* It no longer has relation with the database session. However authinfo and env are cached */
@@ -1582,9 +1621,11 @@ int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC)
        connection->is_attached = connection->is_open = connection->needs_commit = 0;
        connection->is_stub = 1;
 
-       /* now a stub, so don't count it in the number of connnections */
+       /* Cut the link between the connection structure and the time_t structure allocated within the OCI session */
+       connection->next_pingp = NULL;
+
        if (!connection->is_persistent) {
-               OCI_G(num_links)--;      /* Support for "connection" stubs - future use */
+               OCI_G(num_links)--;              /* Support for "connection" stubs - future use */
        }
 
        OCI_G(in_call) = in_call_save;
@@ -1606,14 +1647,14 @@ int php_oci_password_change(php_oci_connection *connection, zstr user, int user_
        return 0;
 } /* }}} */
 
-/* {{{ php_oci_server_get_version() 
+/* {{{ php_oci_server_get_version()
  Get Oracle server version */
-int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSRMLS_DC) 
+int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSRMLS_DC)
 {
        char version_buff[512];
 
-       PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text*)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX));
-       
+       PHP_OCI_CALL_RETURN(connection->errcode, OCIServerVersion, (connection->svc, connection->err, (text *)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX));
+
        if (connection->errcode != OCI_SUCCESS) {
                php_oci_error(connection->err, connection->errcode TSRMLS_CC);
                PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
@@ -1628,7 +1669,7 @@ int php_oci_server_get_version(php_oci_connection *connection, zstr *version TSR
        return 0;
 } /* }}} */
 
-/* {{{ php_oci_column_to_zval() 
+/* {{{ php_oci_column_to_zval()
  Convert php_oci_out_column struct into zval */
 int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSRMLS_DC)
 {
@@ -1639,20 +1680,20 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
        zstr lob_buffer;
        zstr zstr_data = ZSTR(column->data);
        php_oci_lob_type lob_type;
-       
-       if (column->indicator == -1) { /* column is NULL */ 
-               ZVAL_NULL(value); 
+
+       if (column->indicator == -1) { /* column is NULL */
+               ZVAL_NULL(value);
                return 0;
        }
-       
+
        if (column->is_cursor) { /* REFCURSOR -> simply return the statement id */
                ZVAL_RESOURCE(value, column->stmtid);
                zend_list_addref(column->stmtid);
        } else if (column->is_descr) {
-               
+
                if (column->data_type != SQLT_RDD) {
                        int rsrc_type;
-                       
+
                        /* reset descriptor's length */
                        descriptor = (php_oci_descriptor *) zend_list_find(column->descid, &rsrc_type);
 
@@ -1660,7 +1701,7 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
                                php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find LOB descriptor #%d", column->descid);
                                return 1;
                        }
-                                                                 
+
                        descriptor->lob_size = -1;
                        descriptor->lob_current_position = 0;
                        descriptor->buffering = 0;
@@ -1668,7 +1709,7 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
 
                if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) {
                        /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
-                       
+
                        lob_fetch_status = php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC);
                        lob_fetch_status |= (php_oci_lob_get_type(descriptor, &lob_type TSRMLS_CC) > 0);
 #ifdef HAVE_OCI8_TEMP_LOB
@@ -1696,7 +1737,7 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
                                        break;
                        }
                        return 0;
-               } else { 
+               } else {
                        /* return the locator */
                        object_init_ex(value, oci_lob_class_entry_ptr);
                        add_property_resource(value, "descriptor", column->descid);
@@ -1704,7 +1745,7 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
                }
        } else {
                switch (column->retcode) {
-                       case 0: 
+                       case 0:
                                /* intact value */
                                if (column->piecewise) {
                                        column_size = column->retlen4;
@@ -1712,19 +1753,19 @@ int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSR
                                        column_size = column->retlen;
                                }
                                break;
-                       
-                       default:                                
-                               ZVAL_FALSE(value); 
+
+                       default:
+                               ZVAL_FALSE(value);
                                return 0;
                }
-               
+
                ZVAL_TEXTL(value, zstr_data, TEXT_CHARS(column_size), 1);
        }
        return 0;
 }
 /* }}} */
 
-/* {{{ php_oci_fetch_row() 
+/* {{{ php_oci_fetch_row()
  Fetch the next row from the given statement */
 void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_args)
 {
@@ -1741,7 +1782,7 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|l", &z_statement, &array, &fetch_mode) == FAILURE) {
                        return;
                }
-               
+
                if (ZEND_NUM_ARGS() == 2) {
                        fetch_mode = mode;
                }
@@ -1751,17 +1792,17 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_statement, &fetch_mode) == FAILURE) {
                        return;
                }
-               
+
                if (ZEND_NUM_ARGS() == 1) {
                        fetch_mode = mode;
                }
        } else {
                /* for all oci_fetch_*() */
-               
+
                if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
                        return;
                }
-       
+
                fetch_mode = mode;
        }
 
@@ -1769,7 +1810,7 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
                /* none of the modes present, use the default one */
                if (mode & PHP_OCI_ASSOC) {
                        fetch_mode |= PHP_OCI_ASSOC;
-               } 
+               }
                if (mode & PHP_OCI_NUM) {
                        fetch_mode |= PHP_OCI_NUM;
                }
@@ -1784,9 +1825,9 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
        array_init(return_value);
 
        for (i = 0; i < statement->ncolumns; i++) {
-               
+
                column = php_oci_statement_get_column(statement, i + 1, NULL_ZSTR, 0 TSRMLS_CC);
-               
+
                if (column == NULL) {
                        continue;
                }
@@ -1796,7 +1837,7 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
 
                if (!(column->indicator == -1)) {
                        zval *element;
-                       
+
                        MAKE_STD_ZVAL(element);
                        php_oci_column_to_zval(column, element, fetch_mode TSRMLS_CC);
 
@@ -1809,7 +1850,7 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
                                }
                                add_u_assoc_zval(return_value, (UG(unicode) ? IS_UNICODE : IS_STRING), column->name, element);
                        }
-               
+
                } else {
                        if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) {
                                add_index_null(return_value, i);
@@ -1831,7 +1872,7 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
 }
 /* }}} */
 
-/* {{{ php_oci_persistent_helper() 
+/* {{{ php_oci_persistent_helper()
  Helper function to close/rollback persistent connections at the end of request. A return value of 1 indicates that the connection is to be destroyed */
 static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
 {
@@ -1839,7 +1880,7 @@ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
        php_oci_connection *connection;
 
        timestamp = time(NULL);
-       
+
        /* pconnection stubs are also counted as they have private session pools */
        if (le->type == le_pconnection) {
                connection = (php_oci_connection *)le->ptr;
@@ -1849,19 +1890,24 @@ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
                                return ZEND_HASH_APPLY_REMOVE;
                        }
 
+                       /* Helps remove bad connections from the persistent list */
+                       if (!connection->is_open && !connection->is_stub) {
+                               return ZEND_HASH_APPLY_REMOVE;
+                       }
+
                        if (connection->descriptors) {
                                zend_hash_destroy(connection->descriptors);
                                efree(connection->descriptors);
                                connection->descriptors = NULL;
                        }
-                       
+
                        if (connection->needs_commit) {
                                php_oci_connection_rollback(connection TSRMLS_CC);
                        }
-                       
+
                        /* If oci_password_change() changed the password of a
                         * persistent connection, close the connection and remove
-                        * it from the persistent connection cache.  This means
+                        * it from the persistent connection cache.      This means
                         * subsequent scripts will be prevented from being able to
                         * present the old (now invalid) password to a usable
                         * connection to the database; they must use the new
@@ -1874,17 +1920,19 @@ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
                        if (OCI_G(persistent_timeout) > 0) {
                                connection->idle_expiry = timestamp + OCI_G(persistent_timeout);
                        }
-               
-                       if (OCI_G(ping_interval) >= 0) {
-                               connection->next_ping = timestamp + OCI_G(ping_interval);
-                       } else {
-                               /* ping_interval is -1 */
-                               connection->next_ping = 0;
-                       }
 
-                       /* Release all persistent connections at the end of the request */
-                       if (connection->using_spool && !connection->is_stub && php_oci_connection_release(connection TSRMLS_CC)) {
-                               return ZEND_HASH_APPLY_REMOVE;
+                       if (!connection->is_stub) {
+                               if (OCI_G(ping_interval) >= 0) {
+                                       *(connection->next_pingp) = timestamp + OCI_G(ping_interval);
+                               } else {
+                                       /* ping_interval is -1 */
+                                       *(connection->next_pingp) = 0;
+                               }
+
+                               /* Release all session pool-using persistent connections at the end of the request */
+                               if (connection->using_spool && php_oci_connection_release(connection TSRMLS_CC)) {
+                                       return ZEND_HASH_APPLY_REMOVE;
+                               }
                        }
 
                        connection->used_this_request = 0;
@@ -1904,16 +1952,17 @@ static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr
 {
        php_oci_spool *session_pool = NULL;
        zend_bool iserror = 0;
+       ub4 poolmode = OCI_DEFAULT; /* Mode to be passed to OCISessionPoolCreate */
 
        /*Allocate sessionpool out of persistent memory */
        session_pool = (php_oci_spool *) calloc(1, sizeof(php_oci_spool));
 
-    /* Populate key if passed */
+       /* Populate key if passed */
        if (hash_key_len) {
                session_pool->spool_hash_key = zend_strndup(hash_key, hash_key_len);
                session_pool->spool_hash_key_len = hash_key_len;
        }
-       
+
        /* Create the session pool's env */
        if (!(session_pool->env = php_oci_create_env(charsetid TSRMLS_CC))) {
                iserror = 1;
@@ -1932,7 +1981,7 @@ static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr
        /* allocate the session pool error handle - This only for use in the
         * destructor, as there is a generic bug which can free up the OCI_G(err)
         * variable before destroying connections. We cannot use this for other
-        * roundtrip calls as there is no way the user can access this error 
+        * roundtrip calls as there is no way the user can access this error
         */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, ((dvoid *) session_pool->env, (dvoid **)&(session_pool->err), (ub4) OCI_HTYPE_ERROR,(size_t) 0, (dvoid **) 0));
 
@@ -1940,13 +1989,20 @@ static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
                goto exit_create_spool;
-       } 
+       }
+
+/* Disable RLB as we'd mostly have single-connection pools */
+#if (OCI_MAJOR_VERSION > 10 )
+       poolmode = OCI_SPC_NO_RLB | OCI_SPC_HOMOGENEOUS;
+#else
+       poolmode = OCI_SPC_HOMOGENEOUS;
+#endif
 
        /* Create the homogeneous session pool - We have different session pools
         * for every different username, password, charset and dbname.
         */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname.s, (ub4)USTR_BYTES(type, dbname_len), 1, UB4MAXVAL, 1,(OraText *)username.s, (ub4)USTR_BYTES(type, username_len), (OraText *)password.s,(ub4)USTR_BYTES(type, password_len), OCI_SPC_HOMOGENEOUS));
-                               
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionPoolCreate,(session_pool->env, OCI_G(err), session_pool->poolh, (OraText **)&session_pool->poolname, &session_pool->poolname_len, (OraText *)dbname.s, (ub4)USTR_BYTES(type, dbname_len), 0, UB4MAXVAL, 1,(OraText *)username.s, (ub4)USTR_BYTES(type, username_len), (OraText *)password.s,(ub4)USTR_BYTES(type, password_len), poolmode));
+
        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                iserror = 1;
@@ -1958,20 +2014,21 @@ static php_oci_spool *php_oci_create_spool(zstr username, int username_len, zstr
                ub4 timeout = OCI_G(persistent_timeout);
 
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) session_pool->poolh, (ub4) OCI_HTYPE_SPOOL, (void *) &timeout, (ub4) sizeof(timeout), (ub4) OCI_ATTR_SPOOL_TIMEOUT, OCI_G(err)));
-               
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        iserror = 1;
                        goto exit_create_spool;
                }
        }
+
 exit_create_spool:
        if (iserror && session_pool) {
                php_oci_spool_close(session_pool TSRMLS_CC);
                session_pool = NULL;
        }
 
-       if (OCI_G(debug_mode)) { 
+       if (OCI_G(debug_mode)) {
                php_printf ("OCI8 DEBUG L1: create_spool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__);
        }
 
@@ -1979,7 +2036,7 @@ exit_create_spool:
 } /* }}} */
 
 /* {{{ php_oci_get_spool()
-       Get Session pool for the given dbname and charsetid from the persistent 
+       Get Session pool for the given dbname and charsetid from the persistent
        list. Function called for non-persistent connections.
 */
 static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr password, int password_len, zstr dbname, int dbname_len, int charsetid, zend_uchar type TSRMLS_DC)
@@ -1989,26 +2046,26 @@ static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr pa
        zend_rsrc_list_entry spool_le = {0};
        zend_rsrc_list_entry *spool_out_le = NULL;
        zend_bool iserror = 0;
-       
+
        /* Create the spool hash key {{{ */
-       smart_str_appendl_ex(&spool_hashed_details, "oci8__spool__", sizeof("oci8__spool__") - 1, 0);
+       smart_str_appendl_ex(&spool_hashed_details, "oci8spool***", sizeof("oci8spool***") - 1, 0);
        smart_str_appendl_ex(&spool_hashed_details, username.s, USTR_BYTES(type, username_len), 0);
-       smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0);
+       smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
        if (password_len) {
                ulong password_hash;
                password_hash = zend_u_inline_hash_func(type, password, password_len);
                smart_str_append_unsigned_ex(&spool_hashed_details, password_hash, 0);
        }
-       smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0);
+       smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
 
        if (dbname_len) {
                smart_str_appendl_ex(&spool_hashed_details, dbname.s, USTR_BYTES(type, dbname_len), 0);
        }
-       smart_str_appendl_ex(&spool_hashed_details, "__", sizeof("__") - 1, 0);
-               
+       smart_str_appendl_ex(&spool_hashed_details, "**", sizeof("**") - 1, 0);
+
        smart_str_append_unsigned_ex(&spool_hashed_details, charsetid, 0);
 
-       /* Session Pool Hash Key : oci8__spool__dbname__charset */
+       /* Session Pool Hash Key : oci8spool***username**hashedpassword**dbname**charset */
 
        smart_str_0(&spool_hashed_details);
        php_strtolower(spool_hashed_details.c, spool_hashed_details.len);
@@ -2018,16 +2075,15 @@ static php_oci_spool *php_oci_get_spool(zstr username, int username_len, zstr pa
 
                session_pool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, spool_hashed_details.c, spool_hashed_details.len, charsetid, type TSRMLS_CC);
 
-        if (session_pool == NULL) {
+               if (session_pool == NULL) {
                        iserror = 1;
-            goto exit_get_spool;
-        }
+                       goto exit_get_spool;
+               }
                spool_le.ptr  = session_pool;
                spool_le.type = le_psessionpool;
                zend_list_insert(session_pool, le_psessionpool);
                zend_hash_update(&EG(persistent_list), session_pool->spool_hash_key, session_pool->spool_hash_key_len + 1, (void *)&spool_le, sizeof(zend_rsrc_list_entry),NULL);
-       }
-       else if (spool_out_le->type == le_psessionpool && 
+       } else if (spool_out_le->type == le_psessionpool &&
                (((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key_len) == spool_hashed_details.len &&
                memcmp(((php_oci_spool *)(spool_out_le->ptr))->spool_hash_key, spool_hashed_details.c, spool_hashed_details.len) == 0 ) {
                /* retrieve the cached session pool */
@@ -2047,25 +2103,25 @@ exit_get_spool:
 
 /* {{{ php_oci_create_env()
 Create the OCI environment choosing the correct function for the OCI version */
-static OCIEnvphp_oci_create_env(ub2 charsetid TSRMLS_DC)
+static OCIEnv *php_oci_create_env(ub2 charsetid TSRMLS_DC)
 {
        OCIEnv *retenv = NULL;
 
        /* allocate environment handle */
 #if HAVE_OCI_ENV_NLS_CREATE
 #define PHP_OCI_INIT_FUNC_NAME "OCIEnvNlsCreate"
-       
+
        /* create an environment using the character set id, Oracle 9i+ ONLY */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvNlsCreate, (&retenv, OCI_G(events) ? PHP_OCI_INIT_MODE | OCI_EVENTS : PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, charsetid, charsetid));
 
 #elif HAVE_OCI_ENV_CREATE
 #define PHP_OCI_INIT_FUNC_NAME "OCIEnvCreate"
-       
+
        /* allocate env handle without NLS support */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvCreate, (&retenv, PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL));
 #else
 #define PHP_OCI_INIT_FUNC_NAME "OCIEnvInit"
-       
+
        /* the simpliest way */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvInit, (&retenv, OCI_DEFAULT, 0, NULL));
 #endif
@@ -2089,26 +2145,26 @@ static OCIEnv* php_oci_create_env(ub2 charsetid TSRMLS_DC)
    This function is to be deprecated in future in favour of OCISessionGet which is used in php_oci_do_connect_ex */
 static int php_oci_old_create_session(php_oci_connection *connection, zstr dbname, int dbname_len, zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, int session_mode, zend_uchar type TSRMLS_DC)
 {
-       if (OCI_G(debug_mode)) { 
+       if (OCI_G(debug_mode)) {
                php_printf ("OCI8 DEBUG: Bypassing client-side session pool for session create at (%s:%d) \n", __FILE__, __LINE__);
        }
 
        /* Create the OCI environment separate for each connection */
-       if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) { 
-       return 1;
+       if (!(connection->env = php_oci_create_env(connection->charset TSRMLS_CC))) {
+               return 1;
        }
 
-       /* Allocate our server handle {{{ */    
+       /* Allocate our server handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->server), OCI_HTYPE_SERVER, 0, NULL));
-       
+
        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
        } /* }}} */
 
        /* Attach to the server {{{ */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text*)dbname.s, USTR_BYTES(type, dbname_len), (ub4) OCI_DEFAULT));
-       
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerAttach, (connection->server, OCI_G(err), (text *)dbname.s, USTR_BYTES(type, dbname_len), (ub4) OCI_DEFAULT));
+
        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
@@ -2117,7 +2173,7 @@ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbnam
 
        /* Allocate our session handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->session), OCI_HTYPE_SESSION, 0, NULL));
-       
+
        if (OCI_G(errcode) != OCI_SUCCESS) {
                php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                return 1;
@@ -2142,24 +2198,24 @@ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbnam
        /* Set the username {{{ */
        if (username_len) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) username.s, (ub4) USTR_BYTES(type, username_len), (ub4) OCI_ATTR_USERNAME, OCI_G(err)));
-               
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
-               } 
+               }
        }/* }}} */
 
        /* Set the password {{{ */
        if (password_len) {
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) password.s, (ub4) USTR_BYTES(type, password_len), (ub4) OCI_ATTR_PASSWORD, OCI_G(err)));
-               
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
-               } 
+               }
        }/* }}} */
 
-       /* Set the server handle in the service handle {{{ */ 
+       /* Set the server handle in the service handle {{{ */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->server, 0, OCI_ATTR_SERVER, OCI_G(err)));
 
        if (OCI_G(errcode) != OCI_SUCCESS) {
@@ -2217,23 +2273,29 @@ static int php_oci_old_create_session(php_oci_connection *connection, zstr dbnam
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        /* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when
                         * user's password has expired, but is still usable.
-                        * */
+                        */
                        if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
                                return 1;
                        }
                } /* }}} */
        }
 
+       /* Brand new connection: Init and update the next_ping in the connection */
+       if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               return 1;
+       }
+
 #if HAVE_OCI_STMT_PREPARE2
        {
                ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0;
 
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err)));
-               
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
-               }       
+               }
        }
 #endif
 
@@ -2249,6 +2311,7 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool
 #if (OCI_MAJOR_VERSION > 10 )
        ub4 purity = -2;                                /* Illegal value to initialize */
 #endif
+       time_t timestamp = time(NULL);
 
        /* Persistent connections have private session pools */
        if (connection->is_persistent && !connection->private_spool &&
@@ -2266,22 +2329,21 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool
                connection->using_spool = 1;
        }
 
-       if (OCI_G(debug_mode)) { 
+       if (OCI_G(debug_mode)) {
                if (session_pool) {
                        php_printf ("OCI8 DEBUG L1: using shared pool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__);
-               }
-               else {
+               } else {
                        php_printf ("OCI8 DEBUG L1: using private pool: (%p) at (%s:%d) \n", connection->private_spool, __FILE__, __LINE__);
                }
        }
 
-       /* The passed in "connection" can be a cached stub from plist or a
+       /* The passed in "connection" can be a cached stub from plist or
         * freshly created. In the former case, we do not have to allocate
         * any handles */
 
        if (!connection->err) {
-               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL)); 
-                                        
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL));
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
@@ -2290,14 +2352,14 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool
 
        /* {{{ Allocate and initialize the connection-private authinfo handle if not allocated yet */
        if (!connection->authinfo) {
-               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL)); 
-                                        
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->authinfo), OCI_HTYPE_AUTHINFO, 0, NULL));
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
 
-               /* Set the Connection class and purity if OCI client version >=11g */
+               /* Set the Connection class and purity if OCI client version >= 11g */
 #if (OCI_MAJOR_VERSION > 10 )
                PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_SESSION, (dvoid *) OCI_G(connection_class), (ub4)UG(unicode) ? USTR_BYTES(type, u_strlen((UChar *)OCI_G(connection_class))) : strlen(OCI_G(connection_class)), (ub4)OCI_ATTR_CONNECTION_CLASS, OCI_G(err)));
 
@@ -2310,7 +2372,6 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool
                        purity = OCI_ATTR_PURITY_SELF;
                else
                        purity = OCI_ATTR_PURITY_NEW;
-                       
 
                PHP_OCI_CALL_RETURN(OCI_G(errcode),OCIAttrSet, ((dvoid *) connection->authinfo,(ub4) OCI_HTYPE_AUTHINFO, (dvoid *) &purity, (ub4)0, (ub4)OCI_ATTR_PURITY, OCI_G(err)));
 
@@ -2321,39 +2382,84 @@ static int php_oci_create_session(php_oci_connection *connection, php_oci_spool
 #endif
        } /* }}} */
 
-       /* Continue to use the global error handle as the connection is closed when an error occurs */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL));
-       
-       if (OCI_G(errcode) != OCI_SUCCESS) {
-               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+       /* Debug statements {{{ */
+       if (OCI_G(debug_mode)) {
+               ub4 numfree = 0, numbusy = 0, numopen = 0;
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numopen, (ub4 *)0, OCI_ATTR_SPOOL_OPEN_COUNT, OCI_G(err)));
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)actual_spool->poolh, OCI_HTYPE_SPOOL, (dvoid *)&numbusy, (ub4 *)0, OCI_ATTR_SPOOL_BUSY_COUNT, OCI_G(err)));
+               numfree = numopen - numbusy;    /* number of free connections in the pool */
+               php_printf ("OCI8 DEBUG L1: (numopen=%d)(numbusy=%d) at (%s:%d) \n", numopen, numbusy, __FILE__, __LINE__);
+       } /* }}} */
+
+               /* Ping loop: Ping and loop till we get a good
+                * connection. When a database instance goes down, it can
+                * leave several bad connections that need to be flushed out
+                * before getting a good one. In non-RAC, we always get a
+                * brand new connection at the end of the loop and in RAC, we
+                * can get a good connection from a different instance before
+                * flushing out all bad ones. We do not need to ping brand new
+                * connections.
+                */
+       do {
+               /* Continue to use the global error handle as the connection is closed when an error occurs */
+               PHP_OCI_CALL_RETURN(OCI_G(errcode),OCISessionGet, (connection->env, OCI_G(err), &(connection->svc), (OCIAuthInfo *)connection->authinfo, (OraText *)actual_spool->poolname, (ub4)actual_spool->poolname_len, NULL, 0, NULL, NULL, NULL, OCI_SESSGET_SPOOL));
+
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+
+                       /* Session creation returns OCI_SUCCESS_WITH_INFO when
+                        * user's password has expired, but is still usable.
+                        */
+
+                       if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
+                               return 1;
+                       }
+               }
+
+               /* {{{ Populate the session and server fields of the connection */
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err)));
 
-               /* Session creation returns OCI_SUCCESS_WITH_INFO when
-                * user's password has expired, but is still usable.
-                * */
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */
 
-               if (OCI_G(errcode) != OCI_SUCCESS_WITH_INFO) {
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, OCI_G(err), (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&(connection->next_pingp)));
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
                }
-       }
-               
+
+               if (!(connection->next_pingp)){
+                       /* This is a brand new connection, we need not ping, but have to initialize ping */
+                       if (php_oci_ping_init(connection, OCI_G(err) TSRMLS_CC) != OCI_SUCCESS) {
+                               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+                               return 1;
+                       }
+               } else if ((*(connection->next_pingp) > 0) && (timestamp >= *(connection->next_pingp))) {
+                       if (php_oci_connection_ping(connection TSRMLS_CC)) {
+                               /* Got a good connection - update next_ping and get out of ping loop */
+                               *(connection->next_pingp) = timestamp + OCI_G(ping_interval);
+                       } else {
+                               /* Bad connection - remove from pool */
+                               PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) OCI_SESSRLS_DROPSESS));
+                               connection->svc = NULL;
+                               connection->server = NULL;
+                               connection->session = NULL;
+                       }
+               }       /* If ping applicable */
+       } while (!(connection->svc));
+
 #if HAVE_OCI_STMT_PREPARE2
        {
                ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0;
 
                PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX, (ub4 *) &statement_cache_size, 0, (ub4) OCI_ATTR_STMTCACHESIZE, OCI_G(err)));
-               
+
                if (OCI_G(errcode) != OCI_SUCCESS) {
                        php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
                        return 1;
-               }       
+               }
        }
 #endif
 
-       /* {{{ Populate the session and server fields of the connection */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->server), (ub4 *)0, OCI_ATTR_SERVER, OCI_G(err)));
-
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrGet, ((dvoid *)connection->svc, OCI_HTYPE_SVCCTX, (dvoid *)&(connection->session), (ub4 *)0, OCI_ATTR_SESSION, OCI_G(err))); /* }}} */
-
        /* Session is now taken from the session pool and attached and open */
        connection->is_stub = 0;
        connection->is_attached = connection->is_open = 1;
@@ -2374,12 +2480,12 @@ static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
        return;
 } /* }}} */
 
-/* {{{  php_oci_spool_close()
+/* {{{ php_oci_spool_close()
    Destroys the OCI Session Pool */
 static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC)
 {
-       if (session_pool->poolname_len) { 
-               PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh, 
+       if (session_pool->poolname_len) {
+               PHP_OCI_CALL(OCISessionPoolDestroy, ((dvoid *) session_pool->poolh,
                        (dvoid *) session_pool->err, OCI_SPD_FORCE));
        }
 
@@ -2387,23 +2493,65 @@ static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC)
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->poolh, OCI_HTYPE_SPOOL));
        }
 
-       if (session_pool->err) { 
+       if (session_pool->err) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->err, OCI_HTYPE_ERROR));
        }
 
-       if (session_pool->env) { 
+       if (session_pool->env) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->env, OCI_HTYPE_ENV));
        }
 
        if (session_pool->spool_hash_key) {
-               free(session_pool->spool_hash_key); 
+               free(session_pool->spool_hash_key);
        }
 
        free(session_pool);
 } /* }}} */
 
+/* {{{ php_oci_ping_init()
+   Initializes the next_ping time as a context value in the
+   connection. We now use OCIContext{Get,Set}Value to store the
+   next_ping because we need to support ping for non-persistent DRCP
+   connections */
+static sword php_oci_ping_init(php_oci_connection *connection, OCIError *errh TSRMLS_DC)
+{
+       time_t *next_pingp = NULL;
+
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextGetValue, (connection->session, errh, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), (void **)&next_pingp));
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               return OCI_G(errcode);
+       }
+
+       /* This must be a brand-new connection. Allocate memory for the ping */
+       if (!next_pingp) {
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIMemoryAlloc, (connection->session, errh, (void **)&next_pingp, OCI_DURATION_SESSION, sizeof(time_t), OCI_MEMORY_CLEARED));
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       return OCI_G(errcode);
+               }
+       }
+
+       if (OCI_G(ping_interval) >= 0) {
+               time_t timestamp = time(NULL);
+               *next_pingp = timestamp + OCI_G(ping_interval);
+       } else {
+               *next_pingp = 0;
+       }
+
+       /* Set the new ping value into the connection */
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIContextSetValue, (connection->session, errh, OCI_DURATION_SESSION, (ub1 *)"NEXT_PING", (ub1)sizeof("NEXT_PING"), next_pingp));
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               OCIMemoryFree(connection->session, errh, next_pingp);
+               return OCI_G(errcode);
+       }
+
+       /* Cache the pointer so we do not have to do OCIContextGetValue repeatedly */
+       connection->next_pingp = next_pingp;
+
+       return OCI_SUCCESS;
+} /* }}} */
+
 #ifdef ZTS
-/* {{{ php_oci_list_helper() 
+/* {{{ php_oci_list_helper()
  Helper function to destroy data on thread shutdown in ZTS mode */
 static int php_oci_list_helper(zend_rsrc_list_entry *le, void *le_type TSRMLS_DC)
 {
index 0f1ff56968ef53c70993c6d4d1d6e1008be1dfda..ff9d8962de331bc23c02e532b2ab9cb05cb97c83 100644 (file)
@@ -1,6 +1,6 @@
 /*
    +----------------------------------------------------------------------+
-   | PHP Version 5                                                        |
+   | PHP Version 6                                                        |
    +----------------------------------------------------------------------+
    | Copyright (c) 1997-2008 The PHP Group                                |
    +----------------------------------------------------------------------+
 /* misc defines {{{ */
 # if (defined(__osf__) && defined(__alpha))
 #  ifndef A_OSF
-#   define A_OSF
+#      define A_OSF
 #  endif
 #  ifndef OSF1
-#   define OSF1
+#      define OSF1
 #  endif
 #  ifndef _INTRINSICS
-#   define _INTRINSICS
+#      define _INTRINSICS
 #  endif
 # endif /* osf alpha */
 
@@ -59,7 +59,7 @@ extern int le_connection;
 extern int le_pconnection;
 extern int le_statement;
 extern int le_descriptor;
-#ifdef PHP_OCI8_HAVE_COLLECTIONS 
+#ifdef PHP_OCI8_HAVE_COLLECTIONS
 extern int le_collection;
 #endif
 extern int le_server;
@@ -77,19 +77,19 @@ extern zend_class_entry *oci_coll_class_entry_ptr;
 
 #define PHP_OCI_MAX_NAME_LEN  64
 #define PHP_OCI_MAX_DATA_SIZE INT_MAX
-#define PHP_OCI_PIECE_SIZE    (64*1024)-1
+#define PHP_OCI_PIECE_SIZE       (64*1024)-1
 #define PHP_OCI_LOB_BUFFER_SIZE 1048576l  /* 1Mb seems to be the most reasonable buffer size for LOB reading */
 
-#define PHP_OCI_ASSOC               1<<0
-#define PHP_OCI_NUM                 1<<1
-#define PHP_OCI_BOTH                (PHP_OCI_ASSOC|PHP_OCI_NUM)
+#define PHP_OCI_ASSOC                          1<<0
+#define PHP_OCI_NUM                                    1<<1
+#define PHP_OCI_BOTH                           (PHP_OCI_ASSOC|PHP_OCI_NUM)
 
-#define PHP_OCI_RETURN_NULLS        1<<2
-#define PHP_OCI_RETURN_LOBS         1<<3
+#define PHP_OCI_RETURN_NULLS           1<<2
+#define PHP_OCI_RETURN_LOBS                    1<<3
 
-#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN    1<<4
-#define PHP_OCI_FETCHSTATEMENT_BY_ROW       1<<5
-#define PHP_OCI_FETCHSTATEMENT_BY           (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW)
+#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN       1<<4
+#define PHP_OCI_FETCHSTATEMENT_BY_ROW          1<<5
+#define PHP_OCI_FETCHSTATEMENT_BY                      (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW)
 
 #define PHP_OCI_LOB_BUFFER_DISABLED 0
 #define PHP_OCI_LOB_BUFFER_ENABLED 1
@@ -103,147 +103,146 @@ typedef enum {
 } php_oci_lob_type;
 
 typedef struct { /* php_oci_spool {{{ */
-       OCIEnv *env;                    /*env of this session pool */
-       OCIError *err;                  /* pool's error handle  */
-       OCISPool *poolh;                /* pool handle */
-       void *poolname;                 /* session pool name */ 
-       unsigned int poolname_len;      /* length of session pool name */
-       char *spool_hash_key;           /* Hash key for session pool in plist */
-       int   spool_hash_key_len;       /* Hash key length */
+       OCIEnv           *env;                                  /*env of this session pool */
+       OCIError         *err;                                  /* pool's error handle  */
+       OCISPool         *poolh;                                /* pool handle */
+       void             *poolname;                             /* session pool name */
+       unsigned int  poolname_len;                     /* length of session pool name */
+       char             *spool_hash_key;               /* Hash key for session pool in plist */
+       int                       spool_hash_key_len;   /* Hash key length */
 } php_oci_spool; /* }}} */
 
 typedef struct { /* php_oci_connection {{{ */
-       OCIEnv *env;            /* private env handle */
-       ub2 charset;            /* charset ID */
-       OCIServer *server;      /* private server handle */
-       OCISvcCtx *svc;         /* private service context handle */
-       OCISession *session; /* private session handle */
-       OCIAuthInfo *authinfo;  /* Cached authinfo handle for OCISessionGet */
-       OCIError *err;          /* private error handle */
-        php_oci_spool *private_spool;  /* private session pool (for persistent) */
-       sword errcode;          /* last errcode */
-
-       HashTable *descriptors;         /* descriptors hash, used to flush all the LOBs using this connection on commit */
-       unsigned is_open:1;                     /* hels to determine if the connection is dead or not */
-       unsigned is_attached:1;         /* hels to determine if we should detach from the server when closing/freeing the connection */
-       unsigned is_persistent:1;       /* self-descriptive */
-       unsigned used_this_request:1; /* helps to determine if we should reset connection's next ping time and check its timeout */
-       unsigned needs_commit:1;        /* helps to determine if we should rollback this connection on close/shutdown */
-       unsigned passwd_changed:1;      /* helps determine if a persistent connection hash should be invalidated after a password change */
-       unsigned is_stub:1;                     /* flag to keep track whether the connection structure has a real OCI connection associated */
-       unsigned using_spool:1;         /* Is this connection from session pool? */
-       int rsrc_id;                            /* resource ID */
-       time_t idle_expiry;                     /* time when the connection will be considered as expired */
-       time_t next_ping;                       /* time of the next ping */
-       char *hash_key;                         /* hashed details of the connection */
-       int   hash_key_len;     
+       OCIEnv                  *env;                                           /* private env handle */
+       ub2                              charset;                                       /* charset ID */
+       OCIServer               *server;                                        /* private server handle */
+       OCISvcCtx               *svc;                                           /* private service context handle */
+       OCISession              *session;                                       /* private session handle */
+       OCIAuthInfo             *authinfo;                                      /* Cached authinfo handle for OCISessionGet */
+       OCIError                *err;                                           /* private error handle */
+       php_oci_spool   *private_spool;                         /* private session pool (for persistent) */
+       sword                    errcode;                                       /* last errcode */
+
+       HashTable               *descriptors;                           /* descriptors hash, used to flush all the LOBs using this connection on commit */
+       unsigned                 is_open:1;                                     /* hels to determine if the connection is dead or not */
+       unsigned                 is_attached:1;                         /* hels to determine if we should detach from the server when closing/freeing the connection */
+       unsigned                 is_persistent:1;                       /* self-descriptive */
+       unsigned                 used_this_request:1;           /* helps to determine if we should reset connection's next ping time and check its timeout */
+       unsigned                 needs_commit:1;                        /* helps to determine if we should rollback this connection on close/shutdown */
+       unsigned                 passwd_changed:1;                      /* helps determine if a persistent connection hash should be invalidated after a password change */
+       unsigned                 is_stub:1;                                     /* flag to keep track whether the connection structure has a real OCI connection associated */
+       unsigned                 using_spool:1;                         /* Is this connection from session pool? */
+       int                              rsrc_id;                                       /* resource ID */
+       time_t                   idle_expiry;                           /* time when the connection will be considered as expired */
+       time_t                  *next_pingp;                            /* (pointer to) time of the next ping */
+       char                    *hash_key;                                      /* hashed details of the connection */
+       int                              hash_key_len;
 } php_oci_connection; /* }}} */
 
 typedef struct { /* php_oci_descriptor {{{ */
-       int id;
-       php_oci_connection *connection; /* parent connection handle */
-       dvoid *descriptor;                              /* OCI descriptor handle */
-       ub4 type;                                               /* descriptor type (FILE/LOB) */
-       int lob_current_position;               /* LOB internal pointer */ 
-       int lob_size;                                   /* cached LOB size. -1 = Lob wasn't initialized yet */
-       int buffering;                                  /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */
-       ub4 chunk_size;                                 /* chunk size of the LOB. 0 - unknown */
-       ub1 charset_form;                               /* charset form, required for NCLOBs */
-       ub2 charset_id;                                 /* charset ID */
-       unsigned is_open:1;                             /* helps to determine if lob is open or not */
-       php_oci_lob_type lob_type;              /* CLOB/BLOB */
+       int                                      id;
+       php_oci_connection      *connection;                    /* parent connection handle */
+       dvoid                           *descriptor;                    /* OCI descriptor handle */
+       ub4                                      type;                                  /* descriptor type (FILE/LOB) */
+       int                                      lob_current_position;  /* LOB internal pointer */
+       int                                      lob_size;                              /* cached LOB size. -1 = Lob wasn't initialized yet */
+       int                                      buffering;                             /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */
+       ub4                                      chunk_size;                    /* chunk size of the LOB. 0 - unknown */
+       ub1                                      charset_form;                  /* charset form, required for NCLOBs */
+       ub2                                      charset_id;                    /* charset ID */
+       unsigned                         is_open:1;                             /* helps to determine if lob is open or not */
+       php_oci_lob_type         lob_type;                              /* CLOB/BLOB */
 } php_oci_descriptor; /* }}} */
 
 typedef struct { /* php_oci_lob_ctx {{{ */
-       char **lob_data;            /* address of pointer to LOB data */
-       ub4 *lob_len;               /* address of LOB length variable (bytes) */
-       ub4 alloc_len;
+       char                       **lob_data;                          /* address of pointer to LOB data */
+       ub4                                     *lob_len;                               /* address of LOB length variable (bytes) */
+       ub4                                      alloc_len;
 } php_oci_lob_ctx; /* }}} */
 
 typedef struct { /* php_oci_collection {{{ */
-       int id;
-       php_oci_connection *connection; /* parent connection handle */
-       OCIType     *tdo;                               /* collection's type handle */
-       OCITypeCode coll_typecode;              /* collection's typecode handle */
-       OCIRef      *elem_ref;                  /* element's reference handle */
-       OCIType     *element_type;              /* element's type handle */
-       OCITypeCode element_typecode;   /* element's typecode handle */
-       OCIColl     *collection;                /* collection handle */
+       int                                      id;
+       php_oci_connection      *connection;                    /* parent connection handle */
+       OCIType                         *tdo;                                   /* collection's type handle */
+       OCITypeCode                      coll_typecode;                 /* collection's typecode handle */
+       OCIRef                          *elem_ref;                              /* element's reference handle */
+       OCIType                         *element_type;                  /* element's type handle */
+       OCITypeCode                      element_typecode;              /* element's typecode handle */
+       OCIColl                         *collection;                    /* collection handle */
 } php_oci_collection; /* }}} */
 
 typedef struct { /* php_oci_define {{{ */
-       zval *zval;             /* zval used in define */
-       zstr name;              /* placeholder's name */
-       zend_uchar name_type;           /* unicode or not */
-       ub4 name_len;   /* placeholder's name length */
-       ub4 type;               /* define type */
+       zval       *zval;                       /* zval used in define */
+       zstr            name;                   /* placeholder's name */
+       zend_uchar      name_type;              /* unicode or not */
+       ub4                     name_len;               /* placeholder's name length */
+       ub4                     type;                   /* define type */
 } php_oci_define; /* }}} */
 
 typedef struct { /* php_oci_statement {{{ */
-       int id;
-       int parent_stmtid;                              /* parent statement id */
-       php_oci_connection *connection; /* parent connection handle */
-       sword errcode;                                  /* last errcode*/
-       OCIError *err;                                  /* private error handle */
-       OCIStmt *stmt;                                  /* statement handle */
-       char *last_query;                               /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */
-       long last_query_len;                    /* last query length */
-       HashTable *columns;                             /* hash containing all the result columns */
-       HashTable *binds;                               /* binds hash */
-       HashTable *defines;                             /* defines hash */
-       int ncolumns;                                   /* number of columns in the result */
-       unsigned executed:1;                    /* statement executed flag */
-       unsigned has_data:1;                    /* statement has more data flag */
-       ub2 stmttype;                                   /* statement type */
+       int                                      id;
+       int                                      parent_stmtid;                 /* parent statement id */
+       php_oci_connection      *connection;                    /* parent connection handle */
+       sword                            errcode;                               /* last errcode*/
+       OCIError                        *err;                                   /* private error handle */
+       OCIStmt                         *stmt;                                  /* statement handle */
+       char                            *last_query;                    /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */
+       long                             last_query_len;                /* last query length */
+       HashTable                       *columns;                               /* hash containing all the result columns */
+       HashTable                       *binds;                                 /* binds hash */
+       HashTable                       *defines;                               /* defines hash */
+       int                                      ncolumns;                              /* number of columns in the result */
+       unsigned                         executed:1;                    /* statement executed flag */
+       unsigned                         has_data:1;                    /* statement has more data flag */
+       ub2                                      stmttype;                              /* statement type */
 } php_oci_statement; /* }}} */
 
 typedef struct { /* php_oci_bind {{{ */
-       OCIBind *bind;                  /* bind handle */
-       zval *zval;                             /* value */
-       dvoid *descriptor;              /* used for binding of LOBS etc */
-       OCIStmt *statement;     /* used for binding REFCURSORs */
-       php_oci_statement *parent_statement;     /* pointer to the parent statement */
+       OCIBind                          *bind;                                 /* bind handle */
+       zval                             *zval;                                 /* value */
+       dvoid                            *descriptor;                   /* used for binding of LOBS etc */
+       OCIStmt                          *statement;                    /* used for binding REFCURSORs */
+       php_oci_statement        *parent_statement;             /* pointer to the parent statement */
        struct {
-               void *elements;
-               sb2 *indicators;
-               ub2 *element_lengths;
-/*             ub2 *retcodes;          */
-               ub4 current_length;
-               ub4 old_length;
-               ub4 max_length;
-               long type;
+               void    *elements;
+               sb2             *indicators;
+               ub2             *element_lengths;
+               ub4              current_length;
+               ub4              old_length;
+               ub4              max_length;
+               long     type;
        } array;
-       sb2 indicator;                  /* -1 means NULL */
-       ub2 retcode;                    /*  */
-       zend_bool out;                  /* OUT bind or not */
-       ub4 dummy_len;                  /* a dummy var to store alenpp value in bind OUT callback */
+       sb2                                       indicator;                    /* -1 means NULL */
+       ub2                                       retcode;
+       zend_bool                         out;                                  /* OUT bind or not */
+       ub4                                       dummy_len;                    /* a dummy var to store alenpp value in bind OUT callback */
 } php_oci_bind; /* }}} */
 
 typedef struct { /* php_oci_out_column {{{ */
-       php_oci_statement *statement;                   /* statement handle. used when fetching REFCURSORS */
-       php_oci_statement *nested_statement;    /* statement handle. used when fetching REFCURSORS */
-       OCIDefine *oci_define;                  /* define handle */
-       zstr name;                                              /* column name */
-       ub4 name_len;                                   /* column name length */
-       ub2 data_type;                                  /* column data type */
-       ub2 data_size;                                  /* data size */
-       ub4 storage_size4;                              /* size used when allocating buffers */
-       sb2 indicator;                                  /* */
-       ub2 retcode;                                    /* code returned when fetching this particular column */
-       ub2 retlen;                                             /* */
-       ub4 retlen4;                                    /* */
-       ub2 is_descr;                                   /* column contains a descriptor */
-       ub2 is_cursor;                                  /* column contains a cursor */
-       int stmtid;                                             /* statement id for cursors */
-       int descid;                                             /* descriptor id for descriptors */
-       void *data;                                             /* */
-       php_oci_define *define;                 /* define handle */
-       int piecewise;                                  /* column is fetched piece-by-piece */
-       ub4 cb_retlen;                                  /* */
-       sb1 scale;                                              /* column scale */
-       sb2 precision;                                  /* column precision */
-       ub1 charset_form;                               /* charset form, required for NCLOBs */
-       ub2 charset_id;                                 /* charset ID */
+       php_oci_statement       *statement;                             /* statement handle. used when fetching REFCURSORS */
+       php_oci_statement       *nested_statement;              /* statement handle. used when fetching REFCURSORS */
+       OCIDefine                       *oci_define;                    /* define handle */
+       zstr                             name;                                  /* column name */
+       ub4                                      name_len;                              /* column name length */
+       ub2                                      data_type;                             /* column data type */
+       ub2                                      data_size;                             /* data size */
+       ub4                                      storage_size4;                 /* size used when allocating buffers */
+       sb2                                      indicator;
+       ub2                                      retcode;                               /* code returned when fetching this particular column */
+       ub2                                      retlen;
+       ub4                                      retlen4;
+       ub2                                      is_descr;                              /* column contains a descriptor */
+       ub2                                      is_cursor;                             /* column contains a cursor */
+       int                                      stmtid;                                /* statement id for cursors */
+       int                                      descid;                                /* descriptor id for descriptors */
+       void                            *data;
+       php_oci_define          *define;                                /* define handle */
+       int                                      piecewise;                             /* column is fetched piece-by-piece */
+       ub4                                      cb_retlen;
+       sb1                                      scale;                                 /* column scale */
+       sb2                                      precision;                             /* column precision */
+       ub1                                      charset_form;                  /* charset form, required for NCLOBs */
+       ub2                                      charset_id;                    /* charset ID */
 } php_oci_out_column; /* }}} */
 
 /* {{{ macros */
@@ -271,17 +270,31 @@ typedef struct { /* php_oci_out_column {{{ */
 #define PHP_OCI_HANDLE_ERROR(connection, errcode) \
        do { \
                switch (errcode) { \
-                       case 1013: \
-                                          zend_bailout(); \
-                       break; \
-                       case 22: \
-                       case 1012: \
-                       case 3113: \
-                       case 604: \
-                       case 1041: \
-                       case 3114: \
-                                          connection->is_open = 0; \
-                       break; \
+                       case  1013: \
+                               zend_bailout(); \
+                               break;  \
+                       case    22: \
+                       case   378: \
+                       case   602: \
+                       case   603: \
+                       case   604: \
+                       case   609: \
+                       case  1012: \
+                       case  1033: \
+                       case  1041: \
+                       case  1043: \
+                       case  1089: \
+                       case  1090: \
+                       case  1092: \
+                       case  3113: \
+                       case  3114: \
+                       case  3122: \
+                       case  3135: \
+                       case 12153: \
+                       case 27146: \
+                       case 28511: \
+                               connection->is_open = 0; \
+                               break;  \
                } \
        } while (0)
 
@@ -302,14 +315,14 @@ typedef struct { /* php_oci_out_column {{{ */
 #define PHP_OCI_ZVAL_TO_COLLECTION(zval, collection) \
        ZEND_FETCH_RESOURCE(collection, php_oci_collection *, &zval, -1, "oci8 collection", le_collection)
 
-#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type)                      \
+#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type)                                                 \
        do { \
                var = (type) zend_fetch_resource(&zval TSRMLS_CC, -1, name, NULL, 1, resource_type); \
-               if (!var) {                                                                          \
-                       return 1;                                                                        \
+               if (!var) {                                                                                                                                                      \
+                       return 1;                                                                                                                                                \
                } \
        } while (0)
-       
+
 #define PHP_OCI_ZVAL_TO_CONNECTION_EX(zval, connection) \
        PHP_OCI_FETCH_RESOURCE_EX(zval, connection, php_oci_connection *, "oci8 connection", le_connection)
 
@@ -339,7 +352,7 @@ sb4 php_oci_fetch_errmsg(OCIError *, text ** TSRMLS_DC);
 #ifdef HAVE_OCI8_ATTR_STATEMENT
 int php_oci_fetch_sqltext_offset(php_oci_statement *, zstr *, ub2 * TSRMLS_DC);
 #endif
-       
+
 void php_oci_do_connect (INTERNAL_FUNCTION_PARAMETERS, int , int);
 php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr password, int password_len, zstr new_password, int new_password_len, zstr dbname, int dbname_len, zstr charset, long session_mode, int persistent, int exclusive, zend_uchar type TSRMLS_DC);
 
@@ -348,7 +361,7 @@ int php_oci_connection_commit(php_oci_connection * TSRMLS_DC);
 int php_oci_connection_release(php_oci_connection *connection TSRMLS_DC);
 
 int php_oci_password_change(php_oci_connection *, zstr, int, zstr, int, zstr, int, zend_uchar TSRMLS_DC);
-int php_oci_server_get_version(php_oci_connection *, zstr* TSRMLS_DC); 
+int php_oci_server_get_version(php_oci_connection *, zstr* TSRMLS_DC);
 
 void php_oci_fetch_row(INTERNAL_FUNCTION_PARAMETERS, int, int);
 int php_oci_column_to_zval(php_oci_out_column *, zval *, int TSRMLS_DC);
@@ -434,36 +447,30 @@ php_oci_bind *php_oci_bind_array_helper_date(zval* var, long max_table_length, p
 /* }}} */
 
 ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ */
-       sword errcode;                  /* global last error code (used when connect fails, for example) */
-       OCIError *err;                  /* global error handle */
-       
-       /*
-       char *default_username;
-       char *default_password;
-       char *default_dbname;
-       */
-
-       zend_bool debug_mode;   /* debug mode flag */
-       
-       long max_persistent;    /* maximum number of persistent connections per process */
-       long num_persistent;    /* number of existing persistent connections */
-       long num_links;                 /* non-persistent + persistent connections */
-       long num_statements;    /* number of statements open */
-       long ping_interval;             /* time interval between pings */
-       long persistent_timeout;        /* time period after which idle persistent connection is considered expired */
-       long statement_cache_size;      /* statement cache size. used with 9i+ clients only*/
-       long default_prefetch;          /* default prefetch setting */
-       zend_bool privileged_connect;   /* privileged connect flag (On/Off) */
-       zend_bool old_oci_close_semantics;      /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */
-       
-       int shutdown;                           /* in shutdown flag */
-
-       OCIEnv *env;                            /* global environment handle */
-
-       zend_bool in_call;
-       char *connection_class;
-       zend_bool events;
-ZEND_END_MODULE_GLOBALS(oci) /* }}} */ 
+       sword            errcode;                                               /* global last error code (used when connect fails, for example) */
+       OCIError        *err;                                                   /* global error handle */
+
+       zend_bool        debug_mode;                                    /* debug mode flag */
+
+       long             max_persistent;                                /* maximum number of persistent connections per process */
+       long             num_persistent;                                /* number of existing persistent connections */
+       long             num_links;                                             /* non-persistent + persistent connections */
+       long             num_statements;                                /* number of statements open */
+       long             ping_interval;                                 /* time interval between pings */
+       long             persistent_timeout;                    /* time period after which idle persistent connection is considered expired */
+       long             statement_cache_size;                  /* statement cache size. used with 9i+ clients only*/
+       long             default_prefetch;                              /* default prefetch setting */
+       zend_bool        privileged_connect;                    /* privileged connect flag (On/Off) */
+       zend_bool        old_oci_close_semantics;               /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */
+
+       int                      shutdown;                                              /* in shutdown flag */
+
+       OCIEnv          *env;                                                   /* global environment handle */
+
+       zend_bool        in_call;
+       char            *connection_class;
+       zend_bool        events;
+ZEND_END_MODULE_GLOBALS(oci) /* }}} */
 
 #ifdef ZTS
 #define OCI_G(v) TSRMG(oci_globals_id, zend_oci_globals *, v)
@@ -486,5 +493,3 @@ ZEND_EXTERN_MODULE_GLOBALS(oci)
  * c-basic-offset: 4
  * End:
  */
-
-
diff --git a/ext/oci8/tests/drcp_cclass1.phpt b/ext/oci8/tests/drcp_cclass1.phpt
new file mode 100644 (file)
index 0000000..c7166ef
--- /dev/null
@@ -0,0 +1,108 @@
+--TEST--
+DRCP: Test setting connection class inline
+--SKIPIF--
+<?php 
+if (!extension_loaded('oci8')) die ("skip no oci8 extension"); 
+require(__DIR__."/details.inc");
+if (!$test_drcp) die("skip testing DRCP connection class only works in DRCP mode");
+if (strcasecmp($user, "system") && strcasecmp($user, "sys")) die("skip needs to be run as a DBA user"); 
+?>
+--FILE--
+<?php
+
+require(__DIR__."/details.inc");
+
+// Initialization
+
+$t = time();
+$cc1 = 'cc1_'.$t;
+$cc2 = 'cc2_'.$t;
+
+// Run Test
+
+echo "Test 1\n";
+
+ini_set('oci8.connection_class', $cc1);
+$c = oci_pconnect($user, $password, $dbase);
+$s = oci_parse($c, "select * from dual");
+oci_execute($s);
+oci_fetch_all($s, $r);
+var_dump($r);
+
+echo "Test 2\n";
+
+ini_set('oci8.connection_class', $cc2);
+$c = oci_pconnect($user, $password, $dbase);
+$s = oci_parse($c, "select * from dual");
+oci_execute($s);
+oci_fetch_all($s, $r);
+var_dump($r);
+
+echo "Test 3\n";
+
+$s = oci_parse($c, "select cclass_name from v\$cpool_cc_stats where cclass_name like '%.cc__$t'");
+oci_execute($s);
+oci_fetch_all($s, $r);
+var_dump($r);
+
+// Cleanup
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Test 1
+array(1) {
+  ["DUMMY"]=>
+  array(1) {
+    [0]=>
+    string(1) "X"
+  }
+}
+Test 2
+array(1) {
+  ["DUMMY"]=>
+  array(1) {
+    [0]=>
+    string(1) "X"
+  }
+}
+Test 3
+array(1) {
+  ["CCLASS_NAME"]=>
+  array(2) {
+    [0]=>
+    string(21) "%s.cc1_%d"
+    [1]=>
+    string(21) "%s.cc2_%d"
+  }
+}
+Done
+--UEXPECTF--
+Test 1
+array(1) {
+  [u"DUMMY"]=>
+  array(1) {
+    [0]=>
+    unicode(1) "X"
+  }
+}
+Test 2
+array(1) {
+  [u"DUMMY"]=>
+  array(1) {
+    [0]=>
+    unicode(1) "X"
+  }
+}
+Test 3
+array(1) {
+  [u"CCLASS_NAME"]=>
+  array(2) {
+    [0]=>
+    unicode(21) "%s.cc1_%d"
+    [1]=>
+    unicode(21) "%s.cc2_%d"
+  }
+}
+Done