]> granicus.if.org Git - php/commitdiff
MFB: sync DRCP connection pooling and FAN support from PHP 5.3
authorChristopher Jones <sixd@php.net>
Tue, 19 Feb 2008 01:44:29 +0000 (01:44 +0000)
committerChristopher Jones <sixd@php.net>
Tue, 19 Feb 2008 01:44:29 +0000 (01:44 +0000)
25 files changed:
ext/oci8/README
ext/oci8/oci8.c
ext/oci8/oci8_interface.c
ext/oci8/oci8_statement.c
ext/oci8/php_oci8_int.h
ext/oci8/tests/bug42841.phpt [new file with mode: 0644]
ext/oci8/tests/debug.phpt
ext/oci8/tests/details.inc
ext/oci8/tests/drcp_characterset.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_conn_close1.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_conn_close2.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_connect1.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_connection_class.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_functions.inc [new file with mode: 0644]
ext/oci8/tests/drcp_newconnect.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_pconn_close1.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_pconn_close2.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_privileged.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_scope1.phpt [new file with mode: 0644]
ext/oci8/tests/drcp_scope2.phpt [new file with mode: 0644]
ext/oci8/tests/fetch_all3.phpt [new file with mode: 0644]
ext/oci8/tests/password.phpt
ext/oci8/tests/password_2.phpt
ext/oci8/tests/password_new.phpt
ext/oci8/tests/password_old.phpt

index c47b1d75055301b3a7a11e463638cb27cf3fbfec..2caf22509fba6421f9efc9e0c6d0b37c406d81d7 100644 (file)
@@ -6,58 +6,79 @@ Installing OCI8
 3. Installing as statically compiled extension.
 4. Installing from PECL.
 5. Testing OCI8
+6. DRCP and FAN Support
 
 1. Common requirements
 ----------------------
-In case if you use Oracle Instant Client, you don't have to set ORACLE_HOME and
-most of the other environment variables to build PHP with OCI8 support.
-The only variables you may have to set are:
-LD_LIBRARY_PATH - it must include Instant Client libraries dir
-NLS_LANG - in case if you want to change the default encoding used during
-interaction with Oracle servers
-
-If you use common Oracle Client installation that comes along with the Oracle
-server installation, you MUST set at least ORACLE_HOME environment variable
-and make it visible for your web-server BEFORE it starts. Most appropriate
-places to add ORACLE_HOME definition are:
-- /etc/profile
-- /etc/profile.local
-- /etc/profile.d
-and others.
+
+If you use a common Oracle Client installation that comes with the
+Oracle server installation, you MUST set at least the ORACLE_HOME
+environment variable and make it visible for your web-server BEFORE it
+starts.
+
+If you use Oracle Instant Client, you don't have to set ORACLE_HOME
+and many of the other environment variables to build PHP with OCI8
+support.  The only variables you may have to set are:
+
+  LD_LIBRARY_PATH - it must include the Instant Client library directory
+
+  NLS_LANG - if you want to change the default encoding used during
+  interaction with Oracle servers
+
+The most appropriate places to add the environment variables are:
+
+  /etc/profile
+  /etc/profile.local
+  /etc/profile.d
 
 2. Installing as shared extension
 ---------------------------------
-To install OCI8 as shared extension (i.e. the one you should put into
-your php.ini) use the following configure lines to configure PHP:
-a) if you use common Oracle Client installation:
-./configure --with-oci8=shared,$ORACLE_HOME
+
+To install OCI8 as a shared extension (i.e. the one you should put
+into your php.ini) use the following configure lines to configure PHP:
+
+a) if you use a common Oracle or Oracle Client installation:
+
+  ./configure --with-oci8=shared,$ORACLE_HOME
 
 b) with Oracle Instant Client:
-./configure --with-oci8=shared,instantclient,/path/to/instant/client/lib
-If you use rpm-based installation of Oracle Instant Client, your configure
+
+  ./configure --with-oci8=shared,instantclient,/path/to/instant/client/lib
+
+If you use an RPM-based installation of Oracle Instant Client, your configure
 line will look like this:
-./configure --with-oci8=shared,instantclient,/usr/lib/oracle/<OIC version>/client/lib
 
-Follow the usual building procedure after that and you'll get OCI8 shared
-extension (i.e. oci8.so). Add it into the php.ini file like this:
-extension=oci8.so
+  ./configure --with-oci8=shared,instantclient,/usr/lib/oracle/<OIC version>/client/lib
+
+Follow the usual building procedure after that and you'll get an OCI8
+shared extension (i.e. oci8.so). Add it into the php.ini file like
+this:
+
+  extension=oci8.so
+
 and don't forget to specify the right extension_dir for PHP to be able
 to find shared extensions correctly.
 
 3. Installing as statically compiled extension
 ----------------------------------------------
-To install OCI8 as statically compiled module use the following configure lines:
-a) with common Oracle Client installation
-./configure --with-oci8=$ORACLE_HOME
+
+To install OCI8 as statically compiled module use the following
+configure lines:
+
+a) with a common Oracle or Oracle Client installation
+
+  ./configure --with-oci8=$ORACLE_HOME
 
 b) with Oracle Instant Client
-./configure --with-oci8=instantclient,/path/to/instant/client/lib
 
-After successful compile, you don't have to add oci8.so to the php.ini, the module will
-be usable without any additional actions.
+  ./configure --with-oci8=instantclient,/path/to/instant/client/lib
+
+After successful compile, you don't have to add oci8.so to the
+php.ini.  The module will be usable without any additional actions.
 
 4. Installing from PECL
 -----------------------
+
 TBD
 
 5. Testing OCI8
@@ -78,6 +99,10 @@ directory will contain logs of any failures.
   If the database is on the same machine as PHP, set
   $oracle_on_localhost to TRUE.
 
+  If Oracle 11g Database Resident Connection Pooling is being tested,
+  set $test_drcp to TRUE and ensure the connection string uses an
+  appropriate pooled server (see section 6.2.2).
+
   An alternative to editing details.inc is the set the environment
   variables
 
@@ -85,6 +110,7 @@ directory will contain logs of any failures.
     PHP_OCI8_TEST_PASS
     PHP_OCI8_TEST_DB
     PHP_OCI8_TEST_DB_ON_LOCALHOST
+    PHP_OCI8_TEST_DRCP
 
   for example:
 
@@ -92,6 +118,7 @@ directory will contain logs of any failures.
     $ export PHP_OCI8_TEST_PASS=oracle
     $ export PHP_OCI8_TEST_DB=localhost/XE
     $ export PHP_OCI8_TEST_DB_ON_LOCALHOST=TRUE
+    $ export PHP_OCI8_TEST_DRCP=FALSE
 
 5.1.2. Set any necessary environment variables for the Oracle
     database.  With Oracle 10g XE do:
@@ -134,3 +161,221 @@ directory will contain logs of any failures.
     SQL> startup force
 
 5.2.5. Rerun the tests
+
+
+6. DRCP and FAN Support
+-----------------------
+
+The PHP OCI8 Beta extension has support for the Oracle Database
+Resident Connection Pool (DRCP) and Fast Application Notification
+(FAN).
+
+This release is for Beta testing only.  Questions and issues can be
+raised on the Oracle OTN forum (free registration required)
+http://www.oracle.com/technology/forums/php.html
+
+
+6.1. Oracle Version Compatibility
+
+The OCI8 extension will compile with Oracle libraries from version
+9iR2 onwards.  However, full functionality (e.g. DRCP support) is only
+available when Oracle 11g is used.
+
+For other, general database functionality, the version of the Oracle
+libraries used by PHP does not necessarily have to match the version
+of the database.
+
+
+6.2. Database Resident Connection Pooling (DRCP)
+
+DRCP allows more efficient use of database machine memory and provides
+high scalability.
+
+For DRCP to be available in OCI8, Oracle client libraries used by PHP
+and the version of the Oracle Database must both be 11g.
+
+Documentation on DRCP is found in several Oracle manuals. For example,
+see "Configuring Database Resident Connection Pooling" in the Oracle
+Database Administrator's Guide 11g Release 1 (11.1)
+http://download.oracle.com/docs/cd/B28359_01/server.111/b28310/manproc004.htm#CHDGIDBA
+for usage information.  A whitepaper
+http://www.oracle.com/technology/tech/oci/pdf/oracledrcp11g.pdf
+contains background information on DRCP.
+
+After building PHP with the OCI8 extension and 11g libraries, follow
+these steps:
+
+6.2.1. As a privileged database administrator, use a program like
+       SQL*Plus to start the connection pool in the database:
+
+        SQL> execute dbms_connection_pool.start_pool;
+
+     Optional settings control the size and characteristics of the
+     pool.
+
+6.2.2. For PHP applications that currently connect using a Network Alias
+       like:
+
+          $c = oci_pconnect("myuser", "mypassword", "MYDB");
+
+       Modify your tnsnames.ora file and add the "(SERVER=POOLED)"
+       clause, for example:
+
+          MYDB = (DESCRIPTION=(ADDRESS=(PROTOCOL=tcp) (HOST=myhost.dom.com)
+                 (PORT=1521))(CONNECT_DATA=(SERVICE_NAME=sales)
+                 (SERVER=POOLED)))
+
+     Alternatively, modify the Easy Connect syntax in PHP and add
+     ":POOLED" after the service name:
+
+          $c = oci_pconnect("myuser", "mypassword",
+                            "myhost.dom.com:1521/sales:POOLED");
+
+6.2.3. Edit php.ini and choose a connection class name.  This name
+       indicates a logical division of the connection pool and can be
+       used to isolate pooling for separate applications.  Any PHP
+       instance with the same connection class value will share
+       connections in the pool.
+
+          oci8.connection_class = "MY_APPLICATION_NAME"
+
+6.2.4. Run your application, connecting to the 11g database.
+
+
+6.3. Fast Application Notification (FAN) Support
+
+FAN support gives fast connection failover, a high availability
+feature.  This allows PHP OCI8 scripts to be notified when a database
+machine or database instance becomes unavailable.  Without FAN, OCI8
+can hang until a TCP timeout occurs and an error is returned, which
+might be several minutes.  Enabling FAN in OCI8 can allow your
+applications to detect errors and re-connect to an available database
+instance without the web user being aware of an outage.
+
+FAN support is available when the Oracle client libraries that PHP
+links with and the Oracle Database are either version 10gR2 or 11g.
+
+FAN benefits users of Oracle's clustering technology (RAC) because
+connections to surviving database instances can be immediately made.
+Users of Oracle's Data Guard with a broker will see the FAN events
+generated when the standby database goes online.  Standalone databases
+will send FAN events when the database restarts.
+
+For active connections, when a machine or database instance becomes
+unavailable, a connection failure error will be returned by the OCI8
+extension function currently being called.  On a subsequent PHP script
+re-connect, a connection to a surviving database instance will be
+established.  The OCI8 extension also transparently cleans up any idle
+connections affected by a database machine or instance failure so PHP
+connect calls will establish a fresh connection without the script
+being aware of any service disruption.
+
+When oci8.events is On, it is suggested to set oci8.ping_interval to
+-1 to disable pinging, since enabling FAN events provide pro-active
+connection management of idle connections made invalid by a service
+disruption.
+
+To enable FAN support in PHP, after building PHP with Oracle 10gR2 or
+11g libraries follow these steps:
+
+6.3.1. As a privileged database administrator, use a program like
+       SQL*Plus to enable the database service to post FAN events, for
+       example:
+
+          SQL> execute dbms_service.modify_service(
+                 SERVICE_NAME        => 'sales',
+                 AQ_HA_NOTIFICATIONS => TRUE);
+
+6.3.2. Edit php.ini and add
+
+          oci8.events = On
+
+6.3.3. If your application does not already handle OCI8 error
+       conditions, modify it to detect failures and take appropriate
+       action.  This may include re-connecting and re-executing
+       statements.
+
+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.
+
+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.4 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
+trigger to set session properties at the time of session creation.
+Examples of such settings are the NLS language and the date format.
+
+If the Oracle 11.1.0.6 database patch cannot be applied, one of the
+following workarounds can be used:
+
+(i) After logon, explicitly set the session properties using PHP
+application code.
+
+(ii) Connect using Oracle dedicated or shared servers instead of DRCP.
+
+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.
+
+
+6.5. Patching Oracle Database 11g
+
+The patch for bug 6474441 is available from Oracle Support's Metalink
+system.
+
+The bug is specific to Oracle 11.1.0.6 with DRCP connections.  The
+issues it fixes do not affect connections using Oracle's dedicated
+(the default connection mode) or shared servers.  They do not affect
+earlier versions of Oracle.  The bug is intended to be fixed in Oracle
+Database 11.1.0.7 (as yet unreleased).
index d9be50e75e42fcf275798cf6b3523ebf1429f950..7b52cfae85866c589e27d6c25ddeba55d4685270 100644 (file)
@@ -1,6 +1,6 @@
 /*
    +----------------------------------------------------------------------+
-   | PHP Version 5                                                        |
+   | PHP Version 6                                                        |
    +----------------------------------------------------------------------+
    | Copyright (c) 1997-2008 The PHP Group                                |
    +----------------------------------------------------------------------+
 #include "zend_hash.h"
 
 ZEND_DECLARE_MODULE_GLOBALS(oci)
-#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
 static PHP_GINIT_FUNCTION(oci);
-#endif
 
 /* True globals, no need for thread safety */
 int le_connection;
 int le_pconnection;
 int le_statement;
 int le_descriptor;
+int le_psessionpool;
 #ifdef PHP_OCI8_HAVE_COLLECTIONS 
 int le_collection;
 #endif
@@ -89,6 +88,7 @@ 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_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);
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
 static void php_oci_collection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
 #endif
@@ -100,6 +100,13 @@ static int php_oci_list_helper(zend_rsrc_list_entry *le, void *le_type TSRMLS_DC
 static int php_oci_connection_ping(php_oci_connection * TSRMLS_DC);
 static int php_oci_connection_status(php_oci_connection * TSRMLS_DC);
 static int php_oci_connection_close(php_oci_connection * TSRMLS_DC);
+static void php_oci_spool_close(php_oci_spool *session_pool TSRMLS_DC);
+
+static OCIEnv *php_oci_create_env(ub2 charsetid TSRMLS_DC);
+static int php_oci_create_session(php_oci_connection *connection, php_oci_spool *session_pool, 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 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);
 /* }}} */
 
 /* {{{ dynamically loadable module stuff */
@@ -377,35 +384,33 @@ zend_module_entry oci8_module_entry = {
        PHP_RINIT(oci),       /* per-request startup function */
        PHP_RSHUTDOWN(oci),   /* per-request shutdown function */
        PHP_MINFO(oci),       /* information function */
-       "1.2.2",
-#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
+       "1.3.1",
        PHP_MODULE_GLOBALS(oci),  /* globals descriptor */
        PHP_GINIT(oci),           /* globals ctor */
        NULL,                     /* globals dtor */
        NULL,                     /* post deactivate */
        STANDARD_MODULE_PROPERTIES_EX
-#else
-       STANDARD_MODULE_PROPERTIES
-#endif
 };
 /* }}} */
 
 /* {{{ PHP_INI */
 PHP_INI_BEGIN()
-    STD_PHP_INI_ENTRY("oci8.max_persistent",           "-1",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               max_persistent,         zend_oci_globals,       oci_globals)
-    STD_PHP_INI_ENTRY("oci8.persistent_timeout",       "-1",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               persistent_timeout,     zend_oci_globals,       oci_globals)
-    STD_PHP_INI_ENTRY("oci8.ping_interval",            "60",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               ping_interval,          zend_oci_globals,       oci_globals)
-    STD_PHP_INI_BOOLEAN("oci8.privileged_connect",     "0",    PHP_INI_SYSTEM,         OnUpdateBool,           privileged_connect,     zend_oci_globals,       oci_globals)
-    STD_PHP_INI_ENTRY("oci8.statement_cache_size",             "20",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               statement_cache_size,           zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.max_persistent",           "-1",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               max_persistent,                 zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.persistent_timeout",       "-1",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               persistent_timeout,             zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.ping_interval",                    "60",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               ping_interval,                  zend_oci_globals,       oci_globals)
+    STD_PHP_INI_BOOLEAN("oci8.privileged_connect",     "0",    PHP_INI_SYSTEM,         OnUpdateBool,                   privileged_connect,             zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.statement_cache_size",     "20",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               statement_cache_size,   zend_oci_globals,       oci_globals)
     STD_PHP_INI_ENTRY("oci8.default_prefetch",         "10",   PHP_INI_SYSTEM,         ONUPDATELONGFUNC,               default_prefetch,               zend_oci_globals,       oci_globals)
-    STD_PHP_INI_ENTRY("oci8.old_oci_close_semantics",          "0",    PHP_INI_SYSTEM,         OnUpdateBool,           old_oci_close_semantics,                zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.old_oci_close_semantics", "0",     PHP_INI_SYSTEM,         OnUpdateBool,                   old_oci_close_semantics,zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.connection_class",         "" ,    PHP_INI_ALL,            OnUpdateUTF8String,     connection_class,               zend_oci_globals,       oci_globals)
+    STD_PHP_INI_ENTRY("oci8.events",                           "0" ,   PHP_INI_SYSTEM,         OnUpdateBool,                   events,                                 zend_oci_globals,       oci_globals)
 PHP_INI_END()
 /* }}} */
 
 /* {{{ startup, shutdown and info functions
 */
 
-/* {{{  php_oci_init_global_handles()
+/* {{{ php_oci_init_global_handles()
  Initialize global handles only when they are needed 
 */
 static void php_oci_init_global_handles(TSRMLS_D)
@@ -471,11 +476,7 @@ static void php_oci_cleanup_global_handles(TSRMLS_D)
 /* {{{ PHP_GINIT_FUNCTION
  Zerofill globals during module init
 */
-#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
 static PHP_GINIT_FUNCTION(oci)
-#else
-static void php_oci_init_globals(zend_oci_globals *oci_globals TSRMLS_DC)
-#endif
 {
        memset(oci_globals, 0, sizeof(zend_oci_globals));
 }
@@ -504,16 +505,12 @@ PHP_MINIT_FUNCTION(oci)
        OCIInitialize(PHP_OCI_INIT_MODE, NULL, NULL, NULL, NULL);
 #endif
 
-#if (PHP_MAJOR_VERSION == 5 && PHP_MINOR_VERSION > 1) || (PHP_MAJOR_VERSION > 5)
-       /* this is handled by new globals management code */
-#else
-       ZEND_INIT_MODULE_GLOBALS(oci, php_oci_init_globals, NULL);
-#endif
        REGISTER_INI_ENTRIES();
 
        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_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
        le_collection = zend_register_list_destructors_ex(php_oci_collection_list_dtor, NULL, "oci8 collection", module_number);
@@ -673,7 +670,7 @@ PHP_MINFO_FUNCTION(oci)
 
        php_info_print_table_start();
        php_info_print_table_row(2, "OCI8 Support", "enabled");
-       php_info_print_table_row(2, "Version", "1.2.2");
+       php_info_print_table_row(2, "Version", "1.3.1 Beta");
        php_info_print_table_row(2, "Revision", "$Revision$");
 
        snprintf(buf, sizeof(buf), "%ld", OCI_G(num_persistent));
@@ -999,11 +996,11 @@ void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclus
 {
        php_oci_connection *connection;
        zstr username, password;
-       zstr dbname, charset = NULL_ZSTR;
+       zstr dbname = NULL_ZSTR, charset = NULL_ZSTR;
        int username_len = 0, password_len = 0;
        int dbname_len = 0, charset_len = 0;
        zend_uchar username_type, password_type;
-       zend_uchar dbname_type, charset_type;
+       zend_uchar dbname_type = '\0', charset_type = '\0';
        long session_mode = OCI_DEFAULT;
 
        /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */
@@ -1029,6 +1026,9 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
        php_oci_connection *connection = NULL;
        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 */
+
 #if HAVE_OCI_ENV_NLS_CREATE
        ub2 charsetid = 0;
        ub2 charsetid_nls_lang = 0;
@@ -1055,6 +1055,21 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                        break;
        }
 
+       /* 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 
+        */
+       if ((session_mode==OCI_SYSOPER) || (session_mode == OCI_SYSDBA) || (new_password_len)) {
+               use_spool = 0;
+       }
+       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 */
+               use_spool = 0;
+#endif
+       }
+
        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);
@@ -1085,10 +1100,8 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                                smart_str_append_unsigned_ex(&hashed_details, charsetid, 0);
                        }
                }
-               
 
                /* use NLS_LANG if no or invalid charset specified */
-               
                if (!charsetid) {
                        size_t rsize = 0;
                        sword result;
@@ -1100,7 +1113,11 @@ 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 {
+               charsetid = OCI_UTF16ID;
+               smart_str_append_unsigned_ex(&hashed_details, charsetid, 0);
+       }
+
 #else
        if (charset && *charset) {
                php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Your version of Oracle Client doesn't support setting the charset; bad or no charset conversions may result");
@@ -1138,6 +1155,36 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
                        }
                }
 
+               /* Debug statements {{{ */
+               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) {
+                               php_printf ("OCI8 DEBUG L1: Got a cached connection: (%p) at (%s:%d) \n", connection, __FILE__, __LINE__);
+                       }
+                       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 
+                * real connection from its private spool
+                * 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.
+                *
+                * TODO: put in negative code for non-persistent stubs
+                */
+               if (connection && connection->is_persistent && connection->is_stub) {
+                       if (php_oci_create_session(connection, NULL, dbname, dbname_len, username, username_len, password, password_len, new_password, new_password_len, session_mode, type TSRMLS_CC)) {
+                               smart_str_free_ex(&hashed_details, 0);
+                               zend_hash_del(&EG(persistent_list), connection->hash_key, connection->hash_key_len+1);
+
+                               return NULL;
+                       }
+               }
+                       
                if (connection) {
                        if (connection->is_open) {
                                /* found an open connection. now ping it */
@@ -1198,6 +1245,10 @@ 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
+        */
        if (persistent) {
                zend_bool alloc_non_persistent = 0;
                        
@@ -1230,6 +1281,22 @@ open:
                connection->is_persistent = 0;
        }
 
+       /* {{{ Get the session pool that suits this connection request from the
+        * 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 
+        * physical connection (for DRCP) even when the non-persistent php connection
+        * is destroyed.
+        * TODO: Unconditionally do this once OCI provides extended OCISessionGet capability */
+       if (use_spool && !connection->is_persistent) {
+               if ((session_pool = php_oci_get_spool(username, username_len, password, password_len, dbname, dbname_len, charsetid ? charsetid:charsetid_nls_lang, type TSRMLS_CC))==NULL)
+               {
+                       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);
@@ -1243,200 +1310,28 @@ open:
        
        smart_str_free_ex(&hashed_details, 0);
 
-       /* allocate environment handle */
 #if HAVE_OCI_ENV_NLS_CREATE
-#define PHP_OCI_INIT_FUNC_NAME "OCIEnvNlsCreate"
-
-       if (UG(unicode)) {
-               connection->charset = OCI_UTF16ID;
+       if (charsetid) {
+               connection->charset = charsetid;
        } else {
-               if (charsetid) {
-                       connection->charset = charsetid;
-               } else {
-                       connection->charset = charsetid_nls_lang;
-               }
+               connection->charset = charsetid_nls_lang;
        }
-
-       /* create an environment using the character set id, Oracle 9i+ ONLY */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIEnvNlsCreate, (&(connection->env), PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, connection->charset, connection->charset));
-
-#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, (&(connection->env), 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, (&(connection->env), OCI_DEFAULT, 0, NULL));
-#endif
-
-       if (OCI_G(errcode) != OCI_SUCCESS) {
-#ifdef HAVE_OCI_INSTANT_CLIENT
-# ifdef PHP_WIN32
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, PHP_OCI_INIT_FUNC_NAME "() failed. There is something wrong with your system - please check that PATH includes the directory with Oracle Instant Client libraries");
-# else
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, PHP_OCI_INIT_FUNC_NAME "() failed. There is something wrong with your system - please check that LD_LIBRARY_PATH includes the directory with Oracle Instant Client libraries");
-# endif
-#else
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, PHP_OCI_INIT_FUNC_NAME "() failed. There is something wrong with your system - please check that ORACLE_HOME is set and points to the right directory");
 #endif
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       }
-
-       /* 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);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-
-       /* 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));
-       
-       if (OCI_G(errcode) != OCI_SUCCESS) {
-               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-       connection->is_attached = 1;
-
-       /* 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);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-
-       /* allocate our private error-handle {{{ */
-       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);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-
-       /* allocate our service-context {{{ */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->svc), OCI_HTYPE_SVCCTX, 0, NULL));
-
-       if (OCI_G(errcode) != OCI_SUCCESS) {
-               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-
-       /* set the username {{{ */
-       if (username.v) {
-               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);
-                       php_oci_connection_close(connection TSRMLS_CC);
-                       return NULL;
-               } 
-       }/* }}} */
-
-       /* set the password {{{ */
-       if (password.v) {
-               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);
-                       php_oci_connection_close(connection TSRMLS_CC);
-                       return NULL;
-               } 
-       }/* }}} */
-
-       /* 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) {
-               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-
-       /* set the authentication handle in the service handle {{{ */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->session, 0, OCI_ATTR_SESSION, OCI_G(err)));
-
-       if (OCI_G(errcode) != OCI_SUCCESS) {
-               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
-               php_oci_connection_close(connection TSRMLS_CC);
-               return NULL;
-       } /* }}} */
-
-       if (new_password_len) {
-               /* try to change password if new one was provided {{{ */
-               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPasswordChange, (connection->svc, OCI_G(err), (text *)username.s, USTR_BYTES(type, username_len), (text *)password.s, USTR_BYTES(type, password_len), (text *)new_password.s, USTR_BYTES(type, new_password_len), OCI_AUTH));
-
-               if (OCI_G(errcode) != OCI_SUCCESS) {
-                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
-                       php_oci_connection_close(connection TSRMLS_CC);
-                       return NULL;
-               }
-
-               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) {
-                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+       /* 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 {
-               /* start the session {{{ */
-               switch (session_mode) {
-                       case OCI_DEFAULT:
-#if HAVE_OCI_STMT_PREPARE2
-                               /* statement caching is suported only in Oracle 9+ */
-                               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) OCI_STMT_CACHE));
-#else
-                               /* others cannot use stmt caching, so we call OCISessionBegin() with OCI_DEFAULT */
-                               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT));
-#endif
-                               break;
-                       case OCI_SYSDBA:
-                       case OCI_SYSOPER:
-                       default:
-                               if (username_len == 1 && username.s[0] == '/' && password_len == 0) {
-                                       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_EXT, (ub4) session_mode));
-                               } else {
-                                       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) session_mode));
-                               }
-                               break;
                }
-
-               if (OCI_G(errcode) != OCI_SUCCESS) {
-                       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) {
-                               php_oci_connection_close(connection TSRMLS_CC);
-                               return NULL;
-                       }
-               } /* }}} */
-       }
-
-#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);
+       } /* }}} */
+       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;
                }       
        }
-#endif
        
        /* mark it as open */
        connection->is_open = 1;
@@ -1459,6 +1354,18 @@ open:
                connection->rsrc_id = zend_list_insert(connection, le_connection);      
                OCI_G(num_links)++;
        }
+
+       /* Debug statements {{{ */
+       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 {
+                       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__);
+       } /* }}} */
+
        return connection;
 }
 /* }}} */
@@ -1467,18 +1374,33 @@ open:
  * Ping connection. Uses OCIPing() or OCIServerVersion() depending on the Oracle Client version */
 static int php_oci_connection_ping(php_oci_connection *connection TSRMLS_DC)
 {
-       /* OCIPing() crashes Oracle servers older than 10.2 */
-#if 0
+       /* Use OCIPing instead of OCIServerVersion. If OCIPing returns
+        * 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
+        */
+#if HAVE_OCI_LOB_READ2  /* 10.1 and greater client - OCIPing was first available in 10.1 */
        PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT));
 #else
        char version[256];
-       /* use good old OCIServerVersion() by default */
-       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIServerVersion, (connection->server, OCI_G(err), (text*)version, sizeof(version), OCI_HTYPE_SERVER));
+       /* use good old OCIServerVersion() */
+       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 {
+               sb4 error_code = 0;
+               text tmp_buf[PHP_OCI_ERRBUF_LEN];
+
+               /* Treat ORA-1010 as a successful Ping */
+               OCIErrorGet(OCI_G(err), (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR);
+               if (error_code == 1010) {
+                       return 1;
+               }
+       }
 
        /* ignore errors here, just return failure 
         * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
@@ -1557,32 +1479,50 @@ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
                }
        }
 
-       if (connection->svc && connection->session && connection->is_open) {
-               PHP_OCI_CALL(OCISessionEnd, (connection->svc, OCI_G(err), connection->session, (ub4) 0));
-       }
-       
-       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->is_stub && connection->svc && connection->is_open) {
+               /* Use OCISessionRelease for session pool connections */
+               if (connection->using_spool) {
+                       PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,0, (ub4) 0));
+               }
+               else {
+                       PHP_OCI_CALL(OCISessionEnd, (connection->svc, connection->err, connection->session, (ub4) 0));
+               }
        }
-       
+
        if (connection->err) {
                PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->err, (ub4) OCI_HTYPE_ERROR));
        }
-       
-       if (connection->server) {
-               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER));
+       if (connection->authinfo) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->authinfo, (ub4) OCI_HTYPE_AUTHINFO));
        }
        
-       if (connection->env) {
-               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV));
+       /* 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 
+        * (like env) on the session pool
+        */
+               php_oci_spool_close(connection->private_spool TSRMLS_CC);
        }
 
        if (connection->is_persistent) {
@@ -1601,6 +1541,56 @@ static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
        return result;
 } /* }}} */
 
+/* {{{ 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)
+{
+       int result = 0;
+       zend_bool in_call_save = OCI_G(in_call);
+
+       if (connection->is_stub || !connection->using_spool) {
+               return 0;  /* Not our concern */
+       }
+
+       if (connection->descriptors) {
+               zend_hash_destroy(connection->descriptors);
+               efree(connection->descriptors);
+               connection->descriptors = NULL;
+       }
+
+       if (connection->svc) {  
+               /* rollback outstanding transactions */
+               if (connection->needs_commit) {
+                       if (php_oci_connection_rollback(connection TSRMLS_CC)) {
+                               /* rollback failed */
+                               result = 1;
+                       }
+               }
+       }
+
+       /* Release the session */
+       if (connection->svc) {
+               PHP_OCI_CALL(OCISessionRelease, (connection->svc, connection->err, NULL,
+                        0, OCI_DEFAULT));
+       }
+
+       /* It no longer has relation with the database session. However authinfo and env are cached */
+       connection->svc = NULL;
+       connection->server = NULL;
+       connection->session = NULL;
+
+       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 */
+       if (!connection->is_persistent) {
+               OCI_G(num_links)--;      /* Support for "connection" stubs - future use */
+       }
+
+       OCI_G(in_call) = in_call_save;
+       return result;
+} /* }}} */
+
 /* {{{ php_oci_password_change()
  Change password for the user with the username given */
 int php_oci_password_change(php_oci_connection *connection, zstr user, int user_len, zstr pass_old, int pass_old_len, zstr pass_new, int pass_new_len, zend_uchar type TSRMLS_DC)
@@ -1842,7 +1832,7 @@ void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_arg
 /* }}} */
 
 /* {{{ php_oci_persistent_helper() 
- Helper function to close/rollback persistent connections at the end of request */
+ 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)
 {
        time_t timestamp;
@@ -1850,6 +1840,7 @@ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
 
        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;
 
@@ -1891,6 +1882,11 @@ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
                                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;
+                       }
+
                        connection->used_this_request = 0;
                } else if (OCI_G(persistent_timeout) != -1) {
                        if (connection->idle_expiry < timestamp) {
@@ -1902,6 +1898,510 @@ static int php_oci_persistent_helper(zend_rsrc_list_entry *le TSRMLS_DC)
        return ZEND_HASH_APPLY_KEEP;
 } /* }}} */
 
+/* {{{ php_oci_create_spool()
+   Create(alloc + Init) Session pool for the given dbname and charsetid */
+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)
+{
+       php_oci_spool *session_pool = NULL;
+       zend_bool iserror = 0;
+
+       /*Allocate sessionpool out of persistent memory */
+       session_pool = (php_oci_spool *) calloc(1, sizeof(php_oci_spool));
+
+    /* 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;
+               goto exit_create_spool;
+       }
+
+       /* Allocate the pool handle */
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (session_pool->env, (dvoid **) &session_pool->poolh, OCI_HTYPE_SPOOL, (size_t) 0, (dvoid **) 0));
+
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               iserror = 1;
+               goto exit_create_spool;
+       }
+
+       /* 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 
+        */
+       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));
+
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               iserror = 1;
+               goto exit_create_spool;
+       } 
+
+       /* 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));
+                               
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               iserror = 1;
+               goto exit_create_spool;
+       }
+
+       /* Set the session pool's timeout to the oci8.persistent_timeout param */
+       if (OCI_G(persistent_timeout)) {
+               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)) { 
+               php_printf ("OCI8 DEBUG L1: create_spool: (%p) at (%s:%d) \n", session_pool, __FILE__, __LINE__);
+       }
+
+       return session_pool;
+} /* }}} */
+
+/* {{{ php_oci_get_spool()
+       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)
+{
+       smart_str spool_hashed_details = {0};
+       php_oci_spool *session_pool = NULL;
+       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, username.s, USTR_BYTES(type, username_len), 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);
+
+       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_append_unsigned_ex(&spool_hashed_details, charsetid, 0);
+
+       /* Session Pool Hash Key : oci8__spool__dbname__charset */
+
+       smart_str_0(&spool_hashed_details);
+       php_strtolower(spool_hashed_details.c, spool_hashed_details.len);
+       /* }}} */
+
+       if (zend_hash_find(&EG(persistent_list),spool_hashed_details.c, spool_hashed_details.len+1, (void **)&spool_out_le) == FAILURE ) {
+
+               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) {
+                       iserror = 1;
+            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 && 
+               (((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 */
+               session_pool = (php_oci_spool *)(spool_out_le->ptr);
+       }
+
+exit_get_spool:
+       smart_str_free_ex(&spool_hashed_details, 0);
+       if (iserror && session_pool) {
+               php_oci_spool_close(session_pool TSRMLS_CC);
+               session_pool = NULL;
+       }
+
+       return session_pool;
+
+} /* }}} */
+
+/* {{{ php_oci_create_env()
+Create the OCI environment choosing the correct function for the OCI version */
+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
+
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+#ifdef HAVE_OCI_INSTANT_CLIENT
+# ifdef PHP_WIN32
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, PHP_OCI_INIT_FUNC_NAME "() failed. There is something wrong with your system - please check that PATH includes the directory with Oracle Instant Client libraries");
+# else
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, PHP_OCI_INIT_FUNC_NAME "() failed. There is something wrong with your system - please check that LD_LIBRARY_PATH includes the directory with Oracle Instant Client libraries");
+# endif
+#else
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, PHP_OCI_INIT_FUNC_NAME "() failed. There is something wrong with your system - please check that ORACLE_HOME is set and points to the right directory");
+#endif
+               return NULL;
+       }
+       return retenv;
+}/* }}} */
+
+/* {{{ php_oci_old_create_session()
+   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)) { 
+               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;
+       }
+
+       /* 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));
+       
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               return 1;
+       } /* }}} */
+       connection->is_attached = 1;
+
+       /* 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;
+       } /* }}} */
+
+       /* Allocate our private error-handle {{{ */
+       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;
+       } /* }}} */
+
+       /* Allocate our service-context {{{ */
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIHandleAlloc, (connection->env, (dvoid **)&(connection->svc), OCI_HTYPE_SVCCTX, 0, NULL));
+
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               return 1;
+       } /* }}} */
+
+       /* 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 {{{ */ 
+       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) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               return 1;
+       } /* }}} */
+
+       /* Set the authentication handle in the service handle {{{ */
+       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->session, 0, OCI_ATTR_SESSION, OCI_G(err)));
+
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               return 1;
+       } /* }}} */
+
+       if (new_password_len) {
+               /* Try to change password if new one was provided {{{ */
+               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCIPasswordChange, (connection->svc, OCI_G(err), (text *)username.s, USTR_BYTES(type, username_len), (text *)password.s, USTR_BYTES(type, password_len), (text *)new_password.s, USTR_BYTES(type, new_password_len), OCI_AUTH));
+
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+                       return 1;
+               }
+
+               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) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+                       return 1;
+               } /* }}} */
+       } else {
+               /* start the session {{{ */
+               switch (session_mode) {
+                       case OCI_DEFAULT:
+#if HAVE_OCI_STMT_PREPARE2
+                               /* statement caching is suported only in Oracle 9+ */
+                               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) OCI_STMT_CACHE));
+#else
+                               /* Others cannot use stmt caching, so we call OCISessionBegin() with OCI_DEFAULT */
+                               PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT));
+#endif
+                               break;
+                       case OCI_SYSDBA:
+                       case OCI_SYSOPER:
+                       default:
+                               if (username_len == 1 && username.s[0] == '/' && password_len == 0) {
+                                       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_EXT, (ub4) session_mode));
+                               } else {
+                                       PHP_OCI_CALL_RETURN(OCI_G(errcode), OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) session_mode));
+                               }
+                               break;
+               }
+
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       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;
+                       }
+               } /* }}} */
+       }
+
+#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
+
+  /* Successfully created session */
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_create_session()
+   Create session using client-side session pool - new norm */
+static int php_oci_create_session(php_oci_connection *connection, php_oci_spool *session_pool, 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)
+{
+       php_oci_spool *actual_spool = NULL;
+#if (OCI_MAJOR_VERSION > 10 )
+       ub4 purity = -2;                                /* Illegal value to initialize */
+#endif
+
+       /* Persistent connections have private session pools */
+       if (connection->is_persistent && !connection->private_spool &&
+               !(connection->private_spool = php_oci_create_spool(username, username_len, password, password_len, dbname, dbname_len, NULL, 0, connection->charset, type TSRMLS_CC))) {
+                       return 1;
+       }
+       actual_spool = (connection->is_persistent) ? (connection->private_spool) : (session_pool);
+
+       connection->env = actual_spool->env;
+
+       /* Do this upfront so that connection close on an error would know
+        * that this is a session pool connection. Failure to do this
+        * would result in crashes in error scenarios */
+       if (!connection->using_spool) {
+               connection->using_spool = 1;
+       }
+
+       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 {
+                       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
+        * 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)); 
+                                        
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+                       return 1;
+               }
+       }
+
+       /* {{{ 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)); 
+                                        
+               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 */
+#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)));
+
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+                       return 1;
+               }
+
+               if (connection->is_persistent)
+                       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)));
+
+               if (OCI_G(errcode) != OCI_SUCCESS) {
+                       php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+                       return 1;
+               }
+#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);
+
+               /* 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;
+               }
+       }
+               
+#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;
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_spool_list_dtor()
+   Session pool destructor function */
+static void php_oci_spool_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
+{
+       php_oci_spool *session_pool = (php_oci_spool *)entry->ptr;
+
+       if (session_pool) {
+               php_oci_spool_close(session_pool TSRMLS_CC);
+       }
+
+       return;
+} /* }}} */
+
+/* {{{  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, 
+                       (dvoid *) session_pool->err, OCI_SPD_FORCE));
+       }
+
+       if (session_pool->poolh) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->poolh, OCI_HTYPE_SPOOL));
+       }
+
+       if (session_pool->err) { 
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) session_pool->err, OCI_HTYPE_ERROR));
+       }
+
+       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);
+} /* }}} */
+
 #ifdef ZTS
 /* {{{ php_oci_list_helper() 
  Helper function to destroy data on thread shutdown in ZTS mode */
index 2390981e570ea075e9315d3fdef61a1a1b4dcb95..7eeb1804d6afa67d2c75e48f851f56dc2bba978a 100644 (file)
@@ -1561,8 +1561,17 @@ PHP_FUNCTION(oci_free_statement)
    Disconnect from database */
 PHP_FUNCTION(oci_close)
 {
+       /* oci_close for pconnect (if old_oci_close_semantics not set) would 
+        * release the connection back to the client-side session pool (and to the 
+        * server-side pool if Database Resident Connection Pool is being used).
+        * Subsequent pconnects in the same script are not guaranteed to get the
+        * same database session. When a persistent connection goes out-of-scope, 
+        * the connection is not released to the session pool and is kept in the Plist
+        */
+
        zval *z_connection;
        php_oci_connection *connection;
+       int dummy_type = -1;
 
        if (OCI_G(old_oci_close_semantics)) {
                /* do nothing to keep BC */
@@ -1575,6 +1584,17 @@ PHP_FUNCTION(oci_close)
 
        PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
        zend_list_delete(connection->rsrc_id);
+
+       /* If refcount has fallen to zero(resource id removed from the list), 
+        * Release the OCI session associated with this connection structure back 
+        * to the underlying pool. The connection would be cached in the plist as a 
+        * stub 
+        */
+       if(connection->is_persistent && connection->using_spool && !zend_list_find(connection->rsrc_id, &dummy_type)) {
+
+               php_oci_connection_release(connection TSRMLS_CC);
+       }
+
        ZVAL_NULL(z_connection);
        
        RETURN_TRUE;
@@ -1609,7 +1629,7 @@ PHP_FUNCTION(oci_pconnect)
    Return the last error of stmt|connection|global. If no error happened returns false. */
 PHP_FUNCTION(oci_error)
 {
-       zval *arg;
+       zval *arg = NULL;
        php_oci_statement *statement;
        php_oci_connection *connection;
        text *errbuf;
@@ -2212,7 +2232,7 @@ PHP_FUNCTION(oci_new_collection)
        php_oci_collection *collection;
        zstr tdo, schema = NULL_ZSTR;
        int tdo_len, schema_len = 0;
-       zend_uchar tdo_type, schema_type;
+       zend_uchar tdo_type, schema_type = '\0';
        
        if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rT|T", &z_connection, &tdo, &tdo_len, &tdo_type, &schema, &schema_len, &schema_type) == FAILURE) {
                return;
index de311a90f7afa43aabf7bbd986ceaa782ab2644b..6fed08492e6f79c6e30413911c468bf1489f474a 100644 (file)
@@ -1226,6 +1226,14 @@ sb4 php_oci_bind_out_callback(
        phpbind->out = 1; /* mark as OUT bind */
 
        if (Z_TYPE_P(val) == IS_RESOURCE) {
+               /* Processing for ref-cursor out binds */
+               if (phpbind->statement != NULL) {
+                       *bufpp = phpbind->statement;
+                       *alenpp = &phpbind->dummy_len;
+                       *piecep = OCI_ONE_PIECE;
+                       *rcodepp = &phpbind->retcode;
+                       *indpp = &phpbind->indicator;
+               }
                retval = OCI_CONTINUE;
        } else if (Z_TYPE_P(val) == IS_OBJECT) {
                if (!phpbind->descriptor) {
index b58e9fab59065f76f311cfb718ad5228e00533f1..81668b7f69cd612967ade080b8936912d6de23a1 100644 (file)
@@ -102,13 +102,25 @@ typedef enum {
        OCI_IS_BLOB
 } 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 */
+} 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 */
@@ -118,6 +130,8 @@ typedef struct { /* php_oci_connection {{{ */
        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 */
@@ -330,6 +344,7 @@ php_oci_connection *php_oci_do_connect_ex(zstr username, int username_len, zstr
 
 int php_oci_connection_rollback(php_oci_connection * TSRMLS_DC);
 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); 
@@ -445,7 +460,8 @@ ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ */
        OCIEnv *env;                            /* global environment handle */
 
        zend_bool in_call;
-
+       char *connection_class;
+       zend_bool events;
 ZEND_END_MODULE_GLOBALS(oci) /* }}} */ 
 
 #ifdef ZTS
diff --git a/ext/oci8/tests/bug42841.phpt b/ext/oci8/tests/bug42841.phpt
new file mode 100644 (file)
index 0000000..ce567a7
--- /dev/null
@@ -0,0 +1,241 @@
+--TEST--
+Bug #42841 (REF CURSOR and oci_new_cursor PHP crash)
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.statement_cache_size=20
+--FILE--
+<?php
+
+require dirname(__FILE__).'/details.inc';
+
+// note a oci_new_connect() occurs lower in the script
+$c = oci_connect($user, $password, $dbase);
+
+// Initialization
+
+$stmtarray = array(
+       "create or replace procedure bug42841_proc(out_1 out sys_refcursor) is
+   begin
+         open out_1 for select 11 from dual union all select 12 from dual union all select 13 from dual;
+   end bug42841_proc;",
+
+       "create or replace package bug43449_pkg is
+               type cursortype is ref Cursor;  
+               function testcursor return cursortype;
+       end bug43449_pkg;",
+       
+       "create or replace package body bug43449_pkg is
+       function testcursor return cursortype is
+       retCursor cursorType;
+       begin
+               Open retCursor For 'select * from dual';
+               return retCursor;
+       end;
+       end bug43449_pkg;"
+);
+
+foreach ($stmtarray as $stmt) {
+       $s = oci_parse($c, $stmt);
+       @oci_execute($s);
+}
+
+// Main code
+
+function do_bug42841($c)
+{
+       echo "First attempt\n";
+
+       $sql = "BEGIN bug42841_proc(:cursor); END;";
+       $stmt = oci_parse($c, $sql);
+       $cursor = oci_new_cursor($c);
+       oci_bind_by_name($stmt, ":cursor", $cursor, -1, OCI_B_CURSOR);
+       
+       oci_execute($stmt, OCI_DEFAULT);
+       oci_execute($cursor);
+       
+       while($row = oci_fetch_array($cursor, OCI_ASSOC + OCI_RETURN_LOBS)) {
+               $data1[] = $row;
+       }
+       
+       oci_free_statement($stmt);
+       oci_free_statement($cursor);
+       var_dump($data1);
+       
+       echo "Second attempt\n";
+       
+       $sql = "BEGIN bug42841_proc(:cursor); END;";
+       $stmt = oci_parse($c, $sql);
+       $cursor = oci_new_cursor($c);
+       oci_bind_by_name($stmt, ":cursor", $cursor, -1, OCI_B_CURSOR);
+       
+       oci_execute($stmt, OCI_DEFAULT);
+       oci_execute($cursor);
+       
+       while($row = oci_fetch_array($cursor, OCI_ASSOC + OCI_RETURN_LOBS)) {
+               $data2[] = $row;
+       }
+       
+       oci_free_statement($stmt);
+       oci_free_statement($cursor);
+       var_dump($data2);
+}
+
+function do_bug43449($c)
+{
+
+       for ($i = 0; $i < 2; $i++) {
+               var_dump(bug43449_getCur($c));
+       }
+}
+
+function bug43449_getCur($c)
+{              
+       $cur = oci_new_cursor($c);
+       $stmt = oci_parse($c, 'begin :cur := bug43449_pkg.testcursor; end;');
+       oci_bind_by_name($stmt, ':cur', $cur, -1, OCI_B_CURSOR);
+       oci_execute($stmt, OCI_DEFAULT);
+       oci_execute($cur, OCI_DEFAULT);
+       
+       $ret = array();
+       
+       while (ocifetchinto($cur, $row, OCI_ASSOC)) {
+               $ret[] = $row;
+       }
+       
+       oci_free_statement($cur);
+       oci_free_statement($stmt);
+       return $ret;
+}
+
+echo "Test bug 42841: Procedure with OUT cursor parameter\n";
+do_bug42841($c);
+
+$c = oci_new_connect($user, $password, $dbase);
+
+echo "Test bug 43449: Cursor as function result\n";
+do_bug43449($c);
+
+// Cleanup
+
+$stmtarray = array(
+       "drop procedure bug42841_proc",
+       "drop package bug43449_pkg"
+);
+
+foreach ($stmtarray as $stmt) {
+       $s = oci_parse($c, $stmt);
+       oci_execute($s);
+}
+
+echo "Done\n";
+
+?>
+--EXPECT--
+Test bug 42841: Procedure with OUT cursor parameter
+First attempt
+array(3) {
+  [0]=>
+  array(1) {
+    [11]=>
+    string(2) "11"
+  }
+  [1]=>
+  array(1) {
+    [11]=>
+    string(2) "12"
+  }
+  [2]=>
+  array(1) {
+    [11]=>
+    string(2) "13"
+  }
+}
+Second attempt
+array(3) {
+  [0]=>
+  array(1) {
+    [11]=>
+    string(2) "11"
+  }
+  [1]=>
+  array(1) {
+    [11]=>
+    string(2) "12"
+  }
+  [2]=>
+  array(1) {
+    [11]=>
+    string(2) "13"
+  }
+}
+Test bug 43449: Cursor as function result
+array(1) {
+  [0]=>
+  array(1) {
+    ["DUMMY"]=>
+    string(1) "X"
+  }
+}
+array(1) {
+  [0]=>
+  array(1) {
+    ["DUMMY"]=>
+    string(1) "X"
+  }
+}
+Done
+--UEXPECT--
+Test bug 42841: Procedure with OUT cursor parameter
+First attempt
+array(3) {
+  [0]=>
+  array(1) {
+    [11]=>
+    unicode(2) "11"
+  }
+  [1]=>
+  array(1) {
+    [11]=>
+    unicode(2) "12"
+  }
+  [2]=>
+  array(1) {
+    [11]=>
+    unicode(2) "13"
+  }
+}
+Second attempt
+array(3) {
+  [0]=>
+  array(1) {
+    [11]=>
+    unicode(2) "11"
+  }
+  [1]=>
+  array(1) {
+    [11]=>
+    unicode(2) "12"
+  }
+  [2]=>
+  array(1) {
+    [11]=>
+    unicode(2) "13"
+  }
+}
+Test bug 43449: Cursor as function result
+array(1) {
+  [0]=>
+  array(1) {
+    [u"DUMMY"]=>
+    unicode(1) "X"
+  }
+}
+array(1) {
+  [0]=>
+  array(1) {
+    [u"DUMMY"]=>
+    unicode(1) "X"
+  }
+}
+Done
index 7bb5d530a57ea31e3910f855d143938ac36f297f..e8c10dc75d5cc0203f2d4974b1132a03e4f82abe 100644 (file)
@@ -21,10 +21,25 @@ echo "Done\n";
 ?>
 --EXPECTF--
 OCI8 DEBUG: OCINlsEnvironmentVariableGet at (%s:%d) 
+OCI8 DEBUG L1: Got a cached connection: (%s) at (%s:%d) 
 Done
-OCI8 DEBUG: OCISessionEnd at (%s:%d) 
+OCI8 DEBUG: OCISessionRelease at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCISessionPoolDestroy at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d)
+--UEXPECTF--
+OCI8 DEBUG L1: Got a cached connection: (%s) at (%s:%d) 
+Done
+OCI8 DEBUG: OCISessionRelease at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCIHandleFree at (%s:%d) 
+OCI8 DEBUG: OCISessionPoolDestroy at (%s:%d) 
 OCI8 DEBUG: OCIHandleFree at (%s:%d) 
-OCI8 DEBUG: OCIServerDetach at (%s:%d) 
 OCI8 DEBUG: OCIHandleFree at (%s:%d) 
 OCI8 DEBUG: OCIHandleFree at (%s:%d) 
 OCI8 DEBUG: OCIHandleFree at (%s:%d) 
index bfd9f309b707f95c02c158a208d555c5d3e11208..226ab359de8bd6321cc1bb74763da13222856813 100644 (file)
@@ -2,13 +2,28 @@
 
 /*
  * Please change $user, $password and $dbase to match your configuration.
- * Set $oracle_on_localhost to TRUE if the Oracle Database is installed on your localhost.
+ *
+ * Set $oracle_on_localhost to TRUE if the Oracle Database is
+ * installed on your localhost.
+ *
+ * Set $test_drcp to TRUE if you want to run the Oracle Database
+ * Resident Connection Pooling (DRCP) tests. For these tests to run
+ * successfully, you need a server and client which is Oracle 11g or
+ * greater, and $dbase should be set to the tnsnames.ora entry
+ * corresponding to the POOLED server instance or an Easy Connect
+ * string like hostname:port/service_name:POOLED
  */
 
 if (false !== getenv('PHP_OCI8_TEST_DB')) {
        $user           = getenv('PHP_OCI8_TEST_USER');   // Database username for tests
        $password       = getenv('PHP_OCI8_TEST_PASS');   // Password for $user
        $dbase          = getenv('PHP_OCI8_TEST_DB');     // Database connection string
+       $test_drcp      = getenv('PHP_OCI8_TEST_DRCP');
+       if (false !== $test_drcp && 0 == strcasecmp($test_drcp,'TRUE')) {
+               $test_drcp = TRUE;
+       } else {
+               $test_drcp = FALSE;
+       }
        $oracle_on_localhost = getenv('PHP_OCI8_TEST_DB_ON_LOCALHOST');
        if (false !== $oracle_on_localhost && 0 == strcasecmp($oracle_on_localhost,'TRUE')) {
                $oracle_on_localhost = TRUE;
@@ -20,6 +35,7 @@ if (false !== getenv('PHP_OCI8_TEST_DB')) {
        $password                                       = "system";
        $dbase                                          = "oracle";
        $oracle_on_localhost            = FALSE;
+       $test_drcp                                      = FALSE;
 }
 
 ?>
diff --git a/ext/oci8/tests/drcp_characterset.phpt b/ext/oci8/tests/drcp_characterset.phpt
new file mode 100644 (file)
index 0000000..c2ac1e1
--- /dev/null
@@ -0,0 +1,73 @@
+--TEST--
+DRCP: oci_pconnect() and oci_connect() with different character sets
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+
+// Note PHP 6 Unicode mode ignores the character set, so connections
+// specifying different character sets are equivalent, and hence can
+// share connections aka resources.
+
+// Create connections with oci_connect and oci_pconnect with UTF8 as Charset
+
+$c1 = oci_connect($user,$password,$dbase,"UTF8");
+var_dump($c1);
+
+// Now with oci_pconnect()
+
+$p1 = oci_pconnect($user,$password,$dbase,"UTF8");
+var_dump($p1);
+
+// Create two more connections with character set US7ASCII
+
+$c2 = oci_connect($user,$password,$dbase,"US7ASCII");
+var_dump($c2);
+
+// Now with oci_pconnect()
+
+$p2 = oci_pconnect($user,$password,$dbase,"US7ASCII");
+var_dump($p2);
+
+// The two connections c1 and c2 should not share resources as they use different
+//character sets
+
+if((int)$c1 === (int)$c2)
+       echo "First and third connections share a resource: NOT OK\n";
+else
+       echo "First and third connections are different: OK\n";
+
+// The two connections p1 and p2 should not share resources as they use different
+//character sets
+
+if((int)$p1 === (int)$p2)
+       echo "Second and fourth connections share a resource: NOT OK\n";
+else
+       echo "Second and fourth connections are different: OK\n";
+
+// Close all the connections
+oci_close($c1);
+oci_close($c2);
+oci_close($p1);
+oci_close($p2);
+
+echo "Done\n";
+?>
+--EXPECTF--
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 persistent connection)
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 persistent connection)
+First and third connections are different: OK
+Second and fourth connections are different: OK
+Done
+--UEXPECTF--
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 persistent connection)
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 persistent connection)
+First and third connections share a resource: NOT OK
+Second and fourth connections share a resource: NOT OK
+Done
diff --git a/ext/oci8/tests/drcp_conn_close1.phpt b/ext/oci8/tests/drcp_conn_close1.phpt
new file mode 100644 (file)
index 0000000..697b7e3
--- /dev/null
@@ -0,0 +1,45 @@
+--TEST--
+DRCP: oci_connect() with oci_close() and oci8.old_oci_close_semantics ON
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.old_oci_close_semantics=1
+oci8.connection_class=test
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+
+// Test will open a connection
+// Close the connection
+// Open another connection
+// With oci_close() being a no-op, the same conneciton will be returned
+
+
+echo "This is with a OCI_CONNECT\n";
+var_dump($conn1 = oci_connect($user,$password,$dbase));
+$rn1 = (int)$conn1;
+oci_close($conn1);
+
+// Open another connection
+
+var_dump($conn2 = oci_connect($user,$password,$dbase));
+$rn2 = (int)$conn2;
+oci_close($conn2);
+
+// Compare the resource numbers
+
+if ($rn1 === $rn2)
+       echo "Both connections share a resource : OK \n";
+else
+       echo "Both connections are different : NOT OK \n";
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+This is with a OCI_CONNECT
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 connection)
+Both connections share a resource : OK 
+Done
diff --git a/ext/oci8/tests/drcp_conn_close2.phpt b/ext/oci8/tests/drcp_conn_close2.phpt
new file mode 100644 (file)
index 0000000..0d3f824
--- /dev/null
@@ -0,0 +1,46 @@
+--TEST--
+DRCP: oci_connect() with oci_close() and oci8.old_oci_close_semantics OFF
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.old_oci_close_semantics=0
+oci8.connection_class=test
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+
+// Test will open a connection
+// Close the connection
+// Open another connection
+// With oci_close() the connection is released to the pool and hence the
+// the second conneciton will be different
+
+
+// OCI_CONNECT
+echo "This is with a OCI_CONNECT\n";
+var_dump($conn1 = oci_connect($user,$password,$dbase));
+$rn1 = (int)$conn1;
+oci_close($conn1);
+
+// Open another connection
+var_dump($conn2 = oci_connect($user,$password,$dbase));
+$rn2 = (int)$conn2;
+oci_close($conn2);
+
+// Compare the resource numbers
+
+if ($rn1 === $rn2)
+       echo "Both connections share a resource : NOT OK \n";
+else
+       echo "Both connections are different : OK \n";
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+This is with a OCI_CONNECT
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 connection)
+Both connections are different : OK 
+Done
diff --git a/ext/oci8/tests/drcp_connect1.phpt b/ext/oci8/tests/drcp_connect1.phpt
new file mode 100644 (file)
index 0000000..a49885f
--- /dev/null
@@ -0,0 +1,86 @@
+--TEST--
+DRCP: oci_connect()
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.connection_class=test
+oci8.old_oci_close_semantics=0
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+require dirname(__FILE__)."/drcp_functions.inc";
+
+// Open a number of connections with oci_connect and oci_pconnect and verify
+// whether we get a used session with DRCP.
+// To verify this, we change the value of a PL/SQL package variable in one
+// session and query for this through another connection
+
+var_dump($conn1 = oci_connect($user,$password,$dbase));
+// Create the package
+drcp_create_package($conn1);
+     
+// OCI_CONNECT
+echo " This is with OCI_CONNECT.....\n";
+drcp_select_packagevar($conn1); // Returns 0
+drcp_set_packagevar($conn1,1000);
+oci_close($conn1);
+echo " Connection conn1  closed....\n";
+
+// Second connection should return 0 for the package variable.
+var_dump($conn2 = oci_connect($user,$password,$dbase));
+echo " Select with connection 2 \n";
+drcp_select_packagevar($conn2); // Returns 0
+drcp_set_packagevar($conn2,100);
+
+// Third connection. There is no oci_close() for conn2 hence this should
+// return the value set by conn2.
+var_dump($conn3 = oci_connect($user,$password,$dbase));
+echo " Select with connection 3 \n";
+drcp_select_packagevar($conn3); // Returns 100
+
+// Close all the connections
+oci_close($conn2);
+oci_close($conn3);
+
+// OCI_PCONNECT
+echo "\n This is with oci_pconnect().....\n";
+var_dump($pconn1 = oci_pconnect($user,$password,$dbase));
+drcp_set_packagevar($pconn1,1000);
+oci_close($pconn1);
+echo " Connection pconn1  closed....\n";
+
+// Second conenction with oci_pconnect should return the same session hence the
+// value returned is what is set by pconn1
+
+var_dump($pconn2 = oci_pconnect($user,$password,$dbase));
+echo " Select with persistent connection 2 \n";
+drcp_select_packagevar($pconn2); // Returns 1000
+oci_close($pconn2);
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+resource(%d) of type (oci8 connection)
+ This is with OCI_CONNECT.....
+ The value of the package variable is 0
+ Package variable value set to 1000
+ Connection conn1  closed....
+resource(%d) of type (oci8 connection)
+ Select with connection 2 
+ The value of the package variable is 0
+ Package variable value set to 100
+resource(%d) of type (oci8 connection)
+ Select with connection 3 
+ The value of the package variable is 100
+
+ This is with oci_pconnect().....
+resource(%d) of type (oci8 persistent connection)
+ Package variable value set to 1000
+ Connection pconn1  closed....
+resource(%d) of type (oci8 persistent connection)
+ Select with persistent connection 2 
+ The value of the package variable is 1000
+Done
+
diff --git a/ext/oci8/tests/drcp_connection_class.phpt b/ext/oci8/tests/drcp_connection_class.phpt
new file mode 100644 (file)
index 0000000..2aed131
--- /dev/null
@@ -0,0 +1,24 @@
+--TEST--
+DRCP: oci8.connection_class with ini_get() and ini_set()
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.connection_class=test
+--FILE--
+<?php
+
+echo "Setting a new connection class now\n";
+ini_set('oci8.connection_class',"New cc");
+
+// Get the New connection class name .Should return New CC
+
+$new_cc = ini_get('oci8.connection_class');
+echo "The New oci8.connection_class is $new_cc \n";
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Setting a new connection class now
+The New oci8.connection_class is New cc 
+Done
diff --git a/ext/oci8/tests/drcp_functions.inc b/ext/oci8/tests/drcp_functions.inc
new file mode 100644 (file)
index 0000000..26adb21
--- /dev/null
@@ -0,0 +1,93 @@
+<?php
+
+/* This file contains functions required by the DRCP tests */
+
+function drcp_create_table($conn)
+{
+       $create_sql = "CREATE TABLE DRCPTEST (id NUMBER, name VARCHAR2(10), dept VARCHAR2(10))";
+       $statement = oci_parse($conn, $create_sql);
+       oci_execute($statement);
+       
+       $id_values = array(100,101,102,103,104,105,106,107,108);
+       $name_values = array("WIILIAMS","JOHN","SMITH","JONES","ADAMS","ROBERT",
+                                                "BILL","LAWSON","MARY");
+       $dept_values = array("ACCOUNTS","HR","HR","ADMIN","ACCOUNTS","HR",
+                                                "ACCOUNTS","HR","ACCOUNTS");
+       for($i=0; $i<8; $i++) {
+               $insert = "INSERT INTO DRCPTEST VALUES('".$id_values[$i]."','". $name_values[$i]."','".$dept_values[$i]."')";
+               $s = oci_parse($conn, $insert);
+               oci_execute($s);
+       }       
+}
+
+function drcp_drop_table($conn)
+{
+       $ora_sql = "DROP TABLE DRCPTEST";
+       $statement = oci_parse($conn, $ora_sql);
+       oci_execute($statement);
+}
+
+function drcp_update_table($conn)
+{
+       $update_stmt ="Update drcptest set dept ='NEWDEPT' where id = 105";
+       $s1 = oci_parse($conn,$update_stmt);
+       oci_execute($s1,OCI_DEFAULT);
+       echo "Update done-- DEPT value has been set to NEWDEPT\n";
+}
+
+function drcp_select_value($conn)
+{
+       $sel_stmt="select dept from drcptest where id=105";
+       $s2 = oci_parse($conn,$sel_stmt);
+       oci_execute($s2,OCI_DEFAULT);
+       while(oci_fetch($s2)) {
+               echo "The value of DEPT for id 105 is ".oci_result($s2,1)."\n";
+       }
+}
+
+function drcp_select_packagevar($conn)
+{
+       $sel_stmt="select drcp_test_package.f1 as f1 from dual";
+       $s2 = oci_parse($conn, $sel_stmt);
+       oci_define_by_name($s2,'f1',$ret_num);
+       oci_execute($s2);
+       while(oci_fetch($s2)) {
+               echo " The value of the package variable is ".oci_result($s2,1)."\n";
+       }
+}
+
+
+function drcp_set_packagevar($conn,$num)
+{
+       $set_stmt = "begin drcp_test_package.p1($num); end;";
+       $s1 = oci_parse($conn,$set_stmt);
+       oci_execute($s1);
+       echo " Package variable value set to " .$num."\n";
+}
+
+function drcp_create_package($c)
+{
+       $create_package_stmt = "create or replace package drcp_test_package as
+                       var int :=0;
+                       procedure p1(var1 int);
+                       function f1 return number;
+                       end;";
+       $s1 = oci_parse($c, $create_package_stmt);
+       oci_execute($s1);
+       
+       $package_body = "create or replace package body drcp_test_package as
+               procedure p1(var1 int) is
+               begin
+               var :=var1;
+               end;    
+               function f1 return number is
+               begin
+               return drcp_test_package.var;
+               end;
+               end;";
+
+       $s2 = oci_parse($c, $package_body);
+       oci_execute($s2);
+}
+
+?>
diff --git a/ext/oci8/tests/drcp_newconnect.phpt b/ext/oci8/tests/drcp_newconnect.phpt
new file mode 100644 (file)
index 0000000..79718f4
--- /dev/null
@@ -0,0 +1,43 @@
+--TEST--
+DRCP: oci_new_connect()
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.connection_class=test
+oci8.old_oci_close_semantics=0
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+
+// Open two connections with oci_new_connect
+// Verify they are different by comparing the resource ids
+
+var_dump($c1 = oci_new_connect($user,$password,$dbase));
+$rn1 = (int)$c1;
+
+// Another connection now
+
+var_dump($c2 = oci_new_connect($user,$password,$dbase));
+$rn2 = (int)$c2;
+
+// rn1 and rn2 should be different.
+
+if ($rn1 === $rn2)
+       echo "First and second connections share a resource: Not OK\n";
+else
+       echo "First and second connections are different  OK\n";
+
+// Close the connections
+oci_close($c1);
+oci_close($c2);
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+resource(%d) of type (oci8 connection)
+resource(%d) of type (oci8 connection)
+First and second connections are different  OK
+Done
+
diff --git a/ext/oci8/tests/drcp_pconn_close1.phpt b/ext/oci8/tests/drcp_pconn_close1.phpt
new file mode 100644 (file)
index 0000000..a9b912b
--- /dev/null
@@ -0,0 +1,44 @@
+--TEST--
+DRCP: oci_pconnect() with oci_close() and oci8.old_oci_close_semantics ON
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.old_oci_close_semantics=1
+oci8.connection_class=test
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+
+// Test will open a persistent connection
+// Close the connection
+// Open another connection
+// With oci_close() being a no-op, the same conneciton will be returned
+
+echo "This is with a OCI_PCONNECT\n";
+var_dump($conn1 = oci_pconnect($user,$password,$dbase));
+$rn1 = (int)$conn1;
+oci_close($conn1);
+
+//  Open another connection
+
+var_dump($conn2 = oci_pconnect($user,$password,$dbase));
+$rn2 = (int)$conn2;
+oci_close($conn2);
+
+// Compare the resource numbers
+
+if ($rn1 === $rn2)
+       echo "Both connections share a resource : OK \n";
+else
+       echo "Both connections are different : NOT OK \n";
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+This is with a OCI_PCONNECT
+resource(%d) of type (oci8 persistent connection)
+resource(%d) of type (oci8 persistent connection)
+Both connections share a resource : OK 
+Done
diff --git a/ext/oci8/tests/drcp_pconn_close2.phpt b/ext/oci8/tests/drcp_pconn_close2.phpt
new file mode 100644 (file)
index 0000000..5fd2c23
--- /dev/null
@@ -0,0 +1,46 @@
+--TEST--
+DRCP: oci_pconnect() with oci_close() and oci8.old_oci_close_semantics OFF
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.old_oci_close_semantics=0
+oci8.connection_class=test
+--FILE--
+<?php
+
+require dirname(__FILE__)."/details.inc";
+
+// Test will open a persistent connection
+// Close the connection
+// Open another connection
+// With oci_close() the connection is released to the pool and hence the
+// the second connection will be different
+
+
+echo "This is with a OCI_PCONNECT\n";
+var_dump($conn1 = oci_pconnect($user,$password,$dbase));
+$rn1 = (int)$conn1;
+oci_close($conn1);
+
+// Query for the row updated. The new value should be returned
+
+var_dump($conn2 = oci_pconnect($user,$password,$dbase));
+$rn2 = (int)$conn2;
+oci_close($conn2);
+
+// Compare the resource numbers
+
+if ($rn1 === $rn2)
+       echo "Both connections share a resource : NOT OK \n";
+else
+       echo "Both connections are different : OK \n";
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+This is with a OCI_PCONNECT
+resource(%d) of type (oci8 persistent connection)
+resource(%d) of type (oci8 persistent connection)
+Both connections are different : OK 
+Done
diff --git a/ext/oci8/tests/drcp_privileged.phpt b/ext/oci8/tests/drcp_privileged.phpt
new file mode 100644 (file)
index 0000000..9af2062
--- /dev/null
@@ -0,0 +1,47 @@
+--TEST--
+DRCP: privileged connect
+--SKIPIF--
+<?php
+if (!extension_loaded('oci8')) die("skip no oci8 extension");
+if (strcasecmp($user, "system") && strcasecmp($user, "sys")) die("skip needs to be run as a DBA user");
+require(dirname(__FILE__)."/details.inc");
+if (empty($oracle_on_localhost)) die("skip this test is unlikely to work with remote Oracle - unless an Oracle password file has been created");
+?>
+--INI--
+oci8.privileged_connect=1
+--FILE--
+<?php
+
+// Connecting as SYSDBA or SYSOPER through DRCP will give ORA-1031
+
+require dirname(__FILE__)."/details.inc";
+var_dump(oci_connect($user,$password,$dbase,false,OCI_SYSDBA));
+var_dump(oci_connect($user,$password,$dbase,false,OCI_SYSOPER));
+var_dump(oci_new_connect($user,$password,$dbase,false,OCI_SYSDBA));
+var_dump(oci_new_connect($user,$password,$dbase,false,OCI_SYSOPER));
+var_dump(oci_pconnect($user,$password,$dbase,false,OCI_SYSDBA));
+var_dump(oci_pconnect($user,$password,$dbase,false,OCI_SYSOPER));
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+Warning: oci_connect(): ORA-01031: insufficient privileges in %s on line %d
+bool(false)
+
+Warning: oci_connect(): ORA-01031: insufficient privileges in %s on line %d
+bool(false)
+
+Warning: oci_new_connect(): ORA-01031: insufficient privileges in %s on line %d
+bool(false)
+
+Warning: oci_new_connect(): ORA-01031: insufficient privileges in %s on line %d
+bool(false)
+
+Warning: oci_pconnect(): ORA-01031: insufficient privileges in %s on line %d
+bool(false)
+
+Warning: oci_pconnect(): ORA-01031: insufficient privileges in %s on line %d
+bool(false)
+Done
+
diff --git a/ext/oci8/tests/drcp_scope1.phpt b/ext/oci8/tests/drcp_scope1.phpt
new file mode 100644 (file)
index 0000000..01b0a42
--- /dev/null
@@ -0,0 +1,91 @@
+--TEST--
+DRCP: oci_new_connect() and oci_connect() with scope end when oci8.old_oci_close_semantics ON
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.old_oci_close_semantics=1
+--FILE--
+<?php
+
+require dirname(__FILE__)."/drcp_functions.inc";
+require dirname(__FILE__)."/details.inc";
+
+// Scope considered here is the  functional scope
+// Test will open a connection within a function (function 1).
+// Update a table
+// Open another connection from function 2.
+// When the scope ends the txn is rolled back and hence the updated value
+// will not be  reflected for oci_connect and oci_new_connect.
+
+// Create the table
+$c = oci_new_connect($user,$password,$dbase);
+drcp_create_table($c);
+
+// OCI_NEW_CONNECT
+$conn_type = 1;
+echo "This is with a OCI_NEW_CONNECT\n";
+function1($user,$password,$dbase,$conn_type);
+
+// Should return the OLD value
+function2($user,$password,$dbase,$conn_type);
+
+// OCI_CONNECT
+$conn_type = 2;
+echo "\n\nThis is with a OCI_CONNECT\n";
+function1($user,$password,$dbase,$conn_type);
+
+// Should return the OLD value
+function2($user,$password,$dbase,$conn_type);
+
+//This is the first scope for the script
+
+function function1($user,$password,$dbase,$conn_type)
+{
+       switch($conn_type)
+       {
+       case 1:
+               var_dump($conn1 = oci_new_connect($user,$password,$dbase));
+               break;
+       case 2:
+               var_dump($conn1 = oci_connect($user,$password,$dbase));
+               break;
+       }
+       drcp_update_table($conn1);
+}
+
+// This is the second scope
+
+function function2($user,$password,$dbase,$conn_type)
+{
+       switch($conn_type)
+       {
+       case 1:
+               var_dump($conn1 = oci_new_connect($user,$password,$dbase));
+               break;
+       case 2:
+               var_dump($conn1 = oci_connect($user,$password,$dbase));
+               break;
+       }
+       drcp_select_value($conn1);
+}
+
+drcp_drop_table($c);
+oci_close($c);
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+This is with a OCI_NEW_CONNECT
+resource(%d) of type (oci8 connection)
+Update done-- DEPT value has been set to NEWDEPT
+resource(%d) of type (oci8 connection)
+The value of DEPT for id 105 is HR
+
+
+This is with a OCI_CONNECT
+resource(%d) of type (oci8 connection)
+Update done-- DEPT value has been set to NEWDEPT
+resource(%d) of type (oci8 connection)
+The value of DEPT for id 105 is HR
+Done
diff --git a/ext/oci8/tests/drcp_scope2.phpt b/ext/oci8/tests/drcp_scope2.phpt
new file mode 100644 (file)
index 0000000..cb5dcd1
--- /dev/null
@@ -0,0 +1,90 @@
+--TEST--
+DRCP: oci_new_connect() and oci_connect with scope end when oci8.old_oci_close_semantics OFF
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--INI--
+oci8.old_oci_close_semantics=0
+--FILE--
+<?php
+
+require dirname(__FILE__)."/drcp_functions.inc";
+require dirname(__FILE__)."/details.inc";
+
+// Scope considered here is the  functional scope
+// Test will open a connection within a function (function 1).
+// Update a table
+// Open another connection from function 2.
+// When the scope ends the txn is rolled back and hence the updated value
+// will not be  reflected for oci_connect and oci_new_connect.
+
+// Create the table
+$c = oci_new_connect($user,$password,$dbase);
+drcp_create_table($c);
+
+// OCI_NEW_CONNECT
+$conn_type = 1;
+echo "This is with a OCI_NEW_CONNECT\n";
+function1($user,$password,$dbase,$conn_type);
+
+// Should return the OLD value
+function2($user,$password,$dbase,$conn_type);
+
+// OCI_CONNECT
+$conn_type = 2;
+echo "\n\nThis is with a OCI_CONNECT\n";
+function1($user,$password,$dbase,$conn_type);
+
+// Should return the OLD value
+function2($user,$password,$dbase,$conn_type);
+
+//This is the first scope for the script
+
+function function1($user,$password,$dbase,$conn_type)
+{
+       switch($conn_type)
+       {
+       case 1:
+               var_dump($conn1 = oci_new_connect($user,$password,$dbase));
+               break;
+       case 2:
+               var_dump($conn1 = oci_connect($user,$password,$dbase));
+               break;
+       }
+       drcp_update_table($conn1);
+}
+
+// This is the second scope
+
+function function2($user,$password,$dbase,$conn_type)
+{
+       switch($conn_type)
+       {
+       case 1:
+               var_dump($conn1 = oci_new_connect($user,$password,$dbase));
+               break;
+       case 2:
+               var_dump($conn1 = oci_connect($user,$password,$dbase));
+               break;
+       }
+       drcp_select_value($conn1);
+}
+drcp_drop_table($c);
+oci_close($c);
+
+echo "Done\n";
+
+?>
+--EXPECTF--
+This is with a OCI_NEW_CONNECT
+resource(%d) of type (oci8 connection)
+Update done-- DEPT value has been set to NEWDEPT
+resource(%d) of type (oci8 connection)
+The value of DEPT for id 105 is HR
+
+
+This is with a OCI_CONNECT
+resource(%d) of type (oci8 connection)
+Update done-- DEPT value has been set to NEWDEPT
+resource(%d) of type (oci8 connection)
+The value of DEPT for id 105 is HR
+Done
diff --git a/ext/oci8/tests/fetch_all3.phpt b/ext/oci8/tests/fetch_all3.phpt
new file mode 100644 (file)
index 0000000..f266d62
--- /dev/null
@@ -0,0 +1,1043 @@
+--TEST--
+oci_fetch_all() - all combinations of flags
+--SKIPIF--
+<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+--FILE--
+<?php
+
+require dirname(__FILE__)."/connect.inc";
+require dirname(__FILE__).'/create_table.inc';
+
+$insert_sql = "INSERT INTO ".$schema."".$table_name." (id, value) VALUES (:idbv,:vbv)";
+
+$s = oci_parse($c, $insert_sql);
+oci_bind_by_name($s, ":idbv", $idbv, SQLT_INT);
+oci_bind_by_name($s, ":vbv", $vbv, SQLT_INT);
+
+for ($i = 1; $i <= 4; $i++) {
+    $idbv = $i;
+    $vbv = -$i;
+    oci_execute($s, OCI_DEFAULT);
+}
+
+oci_commit($c);
+
+$select_sql = "SELECT ID, VALUE FROM ".$schema."".$table_name." order by id";
+
+$s = oci_parse($c, $select_sql);
+
+echo "None\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1));
+var_dump($all);
+
+echo "OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_COLUMN\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_COLUMN));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM));
+var_dump($all);
+
+echo "OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM|OCI_ASSOC));
+var_dump($all);
+
+echo "OCI_NUM\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_NUM));
+var_dump($all);
+
+echo "OCI_NUM|OCI_ASSOC\n";
+oci_execute($s);
+var_dump(oci_fetch_all($s, $all, 0, -1, OCI_NUM|OCI_ASSOC));
+var_dump($all);
+require dirname(__FILE__).'/drop_table.inc';
+    
+echo "Done\n";
+?>
+--EXPECT--
+None
+int(4)
+array(2) {
+  ["ID"]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  ["VALUE"]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_ASSOC
+int(4)
+array(2) {
+  ["ID"]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  ["VALUE"]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN
+int(4)
+array(2) {
+  ["ID"]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  ["VALUE"]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC
+int(4)
+array(2) {
+  ["ID"]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  ["VALUE"]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "1"
+    ["VALUE"]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "2"
+    ["VALUE"]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "3"
+    ["VALUE"]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "4"
+    ["VALUE"]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "1"
+    ["VALUE"]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "2"
+    ["VALUE"]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "3"
+    ["VALUE"]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "4"
+    ["VALUE"]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "1"
+    ["VALUE"]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "2"
+    ["VALUE"]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "3"
+    ["VALUE"]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "4"
+    ["VALUE"]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "1"
+    ["VALUE"]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "2"
+    ["VALUE"]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "3"
+    ["VALUE"]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    ["ID"]=>
+    string(1) "4"
+    ["VALUE"]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    string(1) "2"
+    [1]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    string(1) "3"
+    [1]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    string(1) "4"
+    [1]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    string(1) "2"
+    [1]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    string(1) "3"
+    [1]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    string(1) "4"
+    [1]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    string(1) "2"
+    [1]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    string(1) "3"
+    [1]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    string(1) "4"
+    [1]=>
+    string(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    string(1) "2"
+    [1]=>
+    string(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    string(1) "3"
+    [1]=>
+    string(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    string(1) "4"
+    [1]=>
+    string(2) "-4"
+  }
+}
+OCI_NUM
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+OCI_NUM|OCI_ASSOC
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    string(1) "1"
+    [1]=>
+    string(1) "2"
+    [2]=>
+    string(1) "3"
+    [3]=>
+    string(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    string(2) "-1"
+    [1]=>
+    string(2) "-2"
+    [2]=>
+    string(2) "-3"
+    [3]=>
+    string(2) "-4"
+  }
+}
+Done
+--UEXPECT--
+None
+int(4)
+array(2) {
+  [u"ID"]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [u"VALUE"]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_ASSOC
+int(4)
+array(2) {
+  [u"ID"]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [u"VALUE"]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN
+int(4)
+array(2) {
+  [u"ID"]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [u"VALUE"]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC
+int(4)
+array(2) {
+  [u"ID"]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [u"VALUE"]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "1"
+    [u"VALUE"]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "2"
+    [u"VALUE"]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "3"
+    [u"VALUE"]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "4"
+    [u"VALUE"]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "1"
+    [u"VALUE"]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "2"
+    [u"VALUE"]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "3"
+    [u"VALUE"]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "4"
+    [u"VALUE"]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "1"
+    [u"VALUE"]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "2"
+    [u"VALUE"]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "3"
+    [u"VALUE"]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "4"
+    [u"VALUE"]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "1"
+    [u"VALUE"]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "2"
+    [u"VALUE"]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "3"
+    [u"VALUE"]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [u"ID"]=>
+    unicode(1) "4"
+    [u"VALUE"]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    unicode(1) "2"
+    [1]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    unicode(1) "3"
+    [1]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    unicode(1) "4"
+    [1]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_FETCHSTATEMENT_BY_COLUMN|OCI_NUM|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    unicode(1) "2"
+    [1]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    unicode(1) "3"
+    [1]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    unicode(1) "4"
+    [1]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    unicode(1) "2"
+    [1]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    unicode(1) "3"
+    [1]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    unicode(1) "4"
+    [1]=>
+    unicode(2) "-4"
+  }
+}
+OCI_FETCHSTATEMENT_BY_ROW|OCI_NUM|OCI_ASSOC
+int(4)
+array(4) {
+  [0]=>
+  array(2) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(2) "-1"
+  }
+  [1]=>
+  array(2) {
+    [0]=>
+    unicode(1) "2"
+    [1]=>
+    unicode(2) "-2"
+  }
+  [2]=>
+  array(2) {
+    [0]=>
+    unicode(1) "3"
+    [1]=>
+    unicode(2) "-3"
+  }
+  [3]=>
+  array(2) {
+    [0]=>
+    unicode(1) "4"
+    [1]=>
+    unicode(2) "-4"
+  }
+}
+OCI_NUM
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+OCI_NUM|OCI_ASSOC
+int(4)
+array(2) {
+  [0]=>
+  array(4) {
+    [0]=>
+    unicode(1) "1"
+    [1]=>
+    unicode(1) "2"
+    [2]=>
+    unicode(1) "3"
+    [3]=>
+    unicode(1) "4"
+  }
+  [1]=>
+  array(4) {
+    [0]=>
+    unicode(2) "-1"
+    [1]=>
+    unicode(2) "-2"
+    [2]=>
+    unicode(2) "-3"
+    [3]=>
+    unicode(2) "-4"
+  }
+}
+Done
index a31843cfd0ea4aaa63aed7c8544395fc3501e00d..a7de393a258c547086c4d74e5da83f99db42b29f 100644 (file)
@@ -1,7 +1,10 @@
 --TEST--
 oci_password_change()
 --SKIPIF--
-<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+<?php 
+if (!extension_loaded('oci8')) die("skip no oci8 extension");
+if ($test_drcp) die("skip password change not supported in DRCP Mode");
+?>
 --FILE--
 <?php
 
index be5cb85400f02d8ca5e3be09a109ad29204278c6..3ee2db5b40db45030454b545b90a5e5107cc40fc 100644 (file)
@@ -5,6 +5,7 @@ oci_password_change() for persistent connections
 if (!extension_loaded('oci8')) die("skip no oci8 extension"); 
 require(dirname(__FILE__)."/details.inc");
 if (strcasecmp($user, "system") && strcasecmp($user, "sys")) die("skip needs to be run as a DBA user"); 
+if ($test_drcp) die("skip password change not supported in DRCP Mode");
 ?>
 --FILE--
 <?php
@@ -31,8 +32,8 @@ var_dump($c1);
 ob_start();
 var_dump($c1);
 $r1 = ob_get_clean();
-preg_match("/resource\(([0-9])\) of.*/", $r1, $matches);
-$rn1 = $matches[1]; /* resource number */
+preg_match("/resource\(([0-9]*)\) of.*/", $r1, $matches);
+$rn1 = $matches[0]; /* resource number */
 
 oci_password_change($c1, "testuser", "testuserpwd", "testuserpwd2");
 
@@ -43,8 +44,8 @@ var_dump($c2);
 ob_start();
 var_dump($c2);
 $r2 = ob_get_clean();
-preg_match("/resource\(([0-9])\) of.*/", $r2, $matches);
-$rn2 = $matches[1]; /* resource number */
+preg_match("/resource\(([0-9]*)\) of.*/", $r2, $matches);
+$rn2 = $matches[0]; /* resource number */
 
 // Despite using the old password this connect should succeed and return the original resource
 $c3 = oci_pconnect("testuser", "testuserpwd", $dbase);  
@@ -53,8 +54,8 @@ var_dump($c3);
 ob_start();
 var_dump($c3);
 $r3 = ob_get_clean();
-preg_match("/resource\(([0-9])\) of.*/", $r3, $matches);
-$rn3 = $matches[1]; /* resource number */
+preg_match("/resource\(([0-9]*)\) of.*/", $r3, $matches);
+$rn3 = $matches[0]; /* resource number */
 
 // Connections should differ
 if ($rn1 == $rn2) {
index a31843cfd0ea4aaa63aed7c8544395fc3501e00d..1de3cb4c96d09c733aabc25d6f67d62e662721ac 100644 (file)
@@ -1,7 +1,11 @@
 --TEST--
 oci_password_change()
 --SKIPIF--
-<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+<?php
+if (!extension_loaded('oci8')) die("skip no oci8 extension"); 
+require dirname(__FILE__)."/details.inc";
+if ($test_drcp) die("skip password change not supported in DRCP Mode");
+?>
 --FILE--
 <?php
 
index d293fce8703270596d3d0622ebe4964f6ce4ecb6..7a2df841e7cf446987006649ca804f2ce3429b04 100644 (file)
@@ -1,7 +1,11 @@
 --TEST--
 ocipasswordchange()
 --SKIPIF--
-<?php if (!extension_loaded('oci8')) die("skip no oci8 extension"); ?>
+<?php
+if (!extension_loaded('oci8')) die("skip no oci8 extension"); 
+require dirname(__FILE__)."/details.inc";
+if ($test_drcp) die("skip password change not supported in DRCP Mode");
+?>
 --FILE--
 <?php