Updated OCI8 driver
authorAntony Dovgal <tony2001@php.net>
Tue, 6 Sep 2005 19:31:59 +0000 (19:31 +0000)
committerAntony Dovgal <tony2001@php.net>
Tue, 6 Sep 2005 19:31:59 +0000 (19:31 +0000)
This updated fixes (this list is not complete):
-------------------
#33915 - crash in _oci_close_session
#26393 - Segfault during request shutdown in _oci_close_session() (oci8.c:2443)

#32741 - hang on ociexecute() with collections (only with 10g, works with 9i)
#32325 - can't retrieve collection using OCI8
#33583 - Apache1.3.33 Segmentation fault with php5 & OCI_New_Collection

#32361 - connection oci_connect stay persist after process the php
#29013 - multiple logins cause handles become invalid
#28944 - OCITypeByName: OCI-21522 with two connections

Fixed by connection handling rewrite.

#32140 - NVARCHAR columns are truncated
#31042 - oci_fetch_* sets field value to false
#27156 - OCIFetchInto returns false as column value when column contains >1 umlaut

Fixed by multiplying buffer size by 3.

#33866 - OCIlogon do not returns conn resource for account with expired paswd
#33365 - logon fails when password expires

Fixed by adding new oci_password_change() call syntax.

#33159 - DB-connect via webserver fails after DB-restart ORA-24327
#30808 - oci8 cannot connect after restarting DB
#30127 - lost oracle connection. need restart apache.
#29902 - oci8 doesn't disconnect sessions, overloads oracle server
#29779 - (the same issue with the Oracle server going offline)
#26829 - Killed Oracle Sessions openned with OCIPLogon()

Fixed by adding oci8.ping_interval option.

#32988ext/oci8: OCI doesn't support DB external authentication

Fixed by adding support of external credentials (turned off by default).

Added new INI options:
----------------------
oci8.ping_interval
oci8.max_persistent
oci8.persistent_timeout
oci8.privileged_connect
oci8.statement_cache_size
oci8.default_prefetch
oci8.old_oci_close_semantics

See the updated docs for the detailed descriptions.

Major changes:
--------------
- connection handling algorithm rewritten. That should add stability and fix all non-reproducible crashes etc;
- extension refactored and divided into several files to improve readability and to make it easier to maintain;
- added support of statement caching;
- added support of privileged connections using external credentials;
- added new INI options to manage persistent connections;
- fixed oci_close() to close connections correctly.

ext/oci8/README [new file with mode: 0644]
ext/oci8/config.m4
ext/oci8/oci8.c
ext/oci8/oci8_collection.c [new file with mode: 0644]
ext/oci8/oci8_interface.c [new file with mode: 0644]
ext/oci8/oci8_lob.c [new file with mode: 0644]
ext/oci8/oci8_statement.c [new file with mode: 0644]
ext/oci8/php_oci8.h
ext/oci8/php_oci8_int.h [new file with mode: 0644]

diff --git a/ext/oci8/README b/ext/oci8/README
new file mode 100644 (file)
index 0000000..b9df41d
--- /dev/null
@@ -0,0 +1,61 @@
+Installing OCI8
+---------------
+
+1. Common requirements.
+2. Installing as shared extension.
+3. Installing as statically compiled extension.
+4. Installing from PECL.
+
+
+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.
+
+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
+
+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 
+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
+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
+
+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.
+
+4. Installing from PECL
+-----------------------
+TBD
index 54342dc32f5d1aa7f4b37f87ca9c3e8b87d4dcab..8cdf41bea136abb3893e0e37e1660f080c6d6b6f 100644 (file)
@@ -19,7 +19,16 @@ AC_DEFUN([PHP_OCI_IF_DEFINED],[
 ])
 
 AC_DEFUN([AC_OCI8_CHECK_LIB_DIR],[
-  PHP_CHECK_64BIT([ TMP_OCI8_LIB_DIR=lib32 ], [ TMP_OCI8_LIB_DIR=lib ])
+  AC_CHECK_SIZEOF(long int, 4)
+  AC_MSG_CHECKING([checking if we're at 64-bit platform])
+  if test "$ac_cv_sizeof_long_int" = "4" ; then
+    AC_MSG_RESULT([no])
+    TMP_OCI8_LIB_DIR=lib32 
+  else
+    AC_MSG_RESULT([yes])
+    TMP_OCI8_LIB_DIR=lib
+  fi
+
   AC_MSG_CHECKING([OCI8 libraries dir])
   if test -d "$OCI8_DIR/lib" -a ! -d "$OCI8_DIR/lib32"; then
        OCI8_LIB_DIR=lib
@@ -76,26 +85,33 @@ AC_DEFUN([AC_OCI8_VERSION],[
   AC_MSG_RESULT($OCI8_VERSION)
 ])
 
-PHP_ARG_WITH(oci8, for Oracle (OCI8) support using ORACLE_HOME installation,
-[  --with-oci8[=DIR]       Include Oracle (OCI8) support using an ORACLE_HOME
-                          install. The default DIR is ORACLE_HOME])
-
-if test "$PHP_OCI8" = "no"; then
-  PHP_ARG_WITH(oci8-instant-client, for Oracle (OCI8) support using Oracle Instant Client,
-  [  --with-oci8-instant-client[=DIR]    
-                          Include Oracle (OCI8) support using
-                          Oracle Instant Client. DIR is the directory with the
-                          Instant Client libraries. On Linux it will default to
-                          /usr/lib/oracle/<most_recent_version>/client/lib
-                          Other platforms will need to have it explicitly specified])
-else 
-  PHP_OCI8_INSTANT_CLIENT="no";
+
+dnl --with-oci8=shared,instantclient,/path/to/client/dir/lib
+dnl or
+dnl --with-oci8=shared,/path/to/oracle/home
+PHP_ARG_WITH(oci8, for Oracle (OCI8) support,
+[  --with-oci8[=DIR]       Include Oracle (OCI8) support. 
+                          The default DIR is ORACLE_HOME.
+                          Use --with-oci8=instantclient,/path/to/oic/lib
+                          to use Oracle Instant Client installation])
+
+PHP_OCI8_INSTANT_CLIENT="no"
+
+if test "`echo $PHP_OCI8 | cut -d, -f2`" = "instantclient"; then
+       PHP_OCI8_INSTANT_CLIENT="`echo $PHP_OCI8 | cut -d, -f3`"
+    PHP_OCI8="`echo $PHP_OCI8 | cut -d, -f1,4`"
+       if test "$PHP_OCI8_INSTANT_CLIENT" = ""; then
+               PHP_OCI8_INSTANT_CLIENT="yes"
+       fi
+elif test "`echo $PHP_OCI8 | cut -d, -f1`" = "instantclient"; then
+       PHP_OCI8_INSTANT_CLIENT="`echo $PHP_OCI8 | cut -d, -f2`"
+    PHP_OCI8="`echo $PHP_OCI8 | cut -d, -f3,4`"
+       if test "$PHP_OCI8_INSTANT_CLIENT" = ""; then
+               PHP_OCI8_INSTANT_CLIENT="yes"
+       fi
 fi
 
-if test "$PHP_OCI8" != "no"; then
-  if test "$PHP_OCI8_INSTANT_CLIENT" != "no"; then
-    AC_MSG_ERROR([--with-oci8 and --with-oci8-instant-client are mutually exclusive])
-  fi
+if test "$PHP_OCI8" != "no" && test "$PHP_OCI8_INSTANT_CLIENT" = "no"; then
 
   AC_MSG_CHECKING([Oracle Install Directory])
   if test "$PHP_OCI8" = "yes"; then
@@ -138,12 +154,40 @@ if test "$PHP_OCI8" != "no"; then
       PHP_ADD_LIBRARY_WITH_PATH(core4, "", OCI8_SHARED_LIBADD)
       PHP_ADD_LIBRARY_WITH_PATH(psa, "", OCI8_SHARED_LIBADD)
       PHP_ADD_LIBRARY_WITH_PATH(clntsh, $OCI8_DIR/$OCI8_LIB_DIR, OCI8_SHARED_LIBADD)
+
+      PHP_CHECK_LIBRARY(clntsh, OCIEnvCreate,
+      [
+        AC_DEFINE(HAVE_OCI_ENV_CREATE,1,[ ])
+      ], [], [
+        -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
+      ])
+
+      PHP_CHECK_LIBRARY(clntsh, OCIStmtPrepare2,
+      [
+        AC_DEFINE(HAVE_OCI_STMT_PREPARE2,1,[ ])
+      ], [], [
+        -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
+      ])
       ;;
 
     8.1)
       PHP_ADD_LIBRARY(clntsh, 1, OCI8_SHARED_LIBADD)
       PHP_ADD_LIBPATH($OCI8_DIR/$OCI8_LIB_DIR, OCI8_SHARED_LIBADD)
 
+      PHP_CHECK_LIBRARY(clntsh, OCIEnvCreate,
+      [
+        AC_DEFINE(HAVE_OCI_ENV_CREATE,1,[ ])
+      ], [], [
+        -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
+      ])
+
+         PHP_CHECK_LIBRARY(clntsh, OCIStmtPrepare2,
+      [
+        AC_DEFINE(HAVE_OCI_STMT_PREPARE2,1,[ ])
+      ], [], [
+        -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
+      ])
       dnl 
       dnl OCI_ATTR_STATEMENT is not available in all 8.1.x versions
       dnl 
@@ -160,7 +204,7 @@ if test "$PHP_OCI8" != "no"; then
       [
         PHP_CHECK_LIBRARY(clntsh, OCINlsCharSetNameToId,
         [
-          AC_DEFINE(HAVE_OCI_9_2,1,[ ])
+          AC_DEFINE(HAVE_OCI_ENV_NLS_CREATE,1,[ ])
           OCI8_VERSION=9.2
         ], [], [
           -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
@@ -168,13 +212,30 @@ if test "$PHP_OCI8" != "no"; then
       ], [], [
         -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
       ])
+
+      PHP_CHECK_LIBRARY(clntsh, OCIEnvCreate,
+      [
+        AC_DEFINE(HAVE_OCI_ENV_CREATE,1,[ ])
+      ], [], [
+        -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
+      ])
+      PHP_CHECK_LIBRARY(clntsh, OCIStmtPrepare2,
+      [
+        AC_DEFINE(HAVE_OCI_STMT_PREPARE2,1,[ ])
+      ], [], [
+        -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
+      ])
       ;;
       
     10.1)
       PHP_ADD_LIBRARY(clntsh, 1, OCI8_SHARED_LIBADD)
       PHP_ADD_LIBPATH($OCI8_DIR/$OCI8_LIB_DIR, OCI8_SHARED_LIBADD)
       AC_DEFINE(HAVE_OCI8_ATTR_STATEMENT,1,[ ])
-      AC_DEFINE(HAVE_OCI_9_2,1,[ ])
+      AC_DEFINE(HAVE_OCI_ENV_NLS_CREATE,1,[ ])
+      AC_DEFINE(HAVE_OCI_ENV_CREATE,1,[ ])
+      AC_DEFINE(HAVE_OCI_STMT_PREPARE2,1,[ ])
       AC_DEFINE(HAVE_OCI8_TEMP_LOB,1,[ ])
       AC_DEFINE(PHP_OCI8_HAVE_COLLECTIONS,1,[ ])
       ;;
@@ -207,18 +268,22 @@ if test "$PHP_OCI8" != "no"; then
   PHP_CHECK_LIBRARY(clntsh, OCICollAssign,
   [
     AC_DEFINE(PHP_OCI8_HAVE_COLLECTIONS,1,[ ])
-  ], [], [
+    PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c, $ext_shared)
+  ], 
+  [
+    PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_interface.c, $ext_shared)
+  ], 
+  [
     -L$OCI8_DIR/$OCI8_LIB_DIR $OCI8_SHARED_LIBADD
   ])
 
-  PHP_NEW_EXTENSION(oci8, oci8.c, $ext_shared)
   AC_DEFINE(HAVE_OCI8,1,[ ])
 
   PHP_SUBST_OLD(OCI8_SHARED_LIBADD)
   PHP_SUBST_OLD(OCI8_DIR)
   PHP_SUBST_OLD(OCI8_VERSION)
   
-elif test "$PHP_OCI8_INSTANT_CLIENT" != "no"; then
+elif test "$PHP_OCI8" != "no" && test "$PHP_OCI8_INSTANT_CLIENT" != "no"; then
 
   AC_MSG_CHECKING([Oracle Instant Client directory])
   if test "$PHP_OCI8_INSTANT_CLIENT" = "yes"; then
@@ -227,7 +292,7 @@ dnl directory to the libraries.  But on Linux we default to the most recent
 dnl version in /usr/lib
     PHP_OCI8_INSTANT_CLIENT=`ls -d /usr/lib/oracle/*/client/lib  2> /dev/null | tail -1`
     if test -z "$PHP_OCI8_INSTANT_CLIENT"; then
-      AC_MSG_ERROR([Oracle Instant Client directory not found. Try --with-oci8-instant-client=DIR])
+      AC_MSG_ERROR([Oracle Instant Client directory not found. Try --with-oci8=instantclient,DIR])
     fi
   fi
   AC_MSG_RESULT($PHP_OCI8_INSTANT_CLIENT)
@@ -242,6 +307,9 @@ dnl Header directory for Instant Client SDK RPM install
 dnl Header directory for Instant Client SDK zip file install
   OCISDKZIPINC=$PHP_OCI8_INSTANT_CLIENT/sdk/include
 
+dnl Header directory for manual installation
+  OCISDKMANINC=`echo "$PHP_OCI8_INSTANT_CLIENT" | sed -e 's!\(.*\)/lib[[/]]*$!\1/include!'`
+  
   if test -f "$OCISDKRPMINC/oci.h"; then
     AC_MSG_RESULT($OCISDKRPMINC)
     PHP_ADD_INCLUDE($OCISDKRPMINC)
@@ -250,6 +318,10 @@ dnl Header directory for Instant Client SDK zip file install
     AC_MSG_RESULT($OCISDKZIPINC)
     PHP_ADD_INCLUDE($OCISDKZIPINC)
     OCI8INCDIR=$OCISDKZIPINC
+  elif test -f "$OCISDKMANINC/oci.h"; then
+    AC_MSG_RESULT($OCISDKMANINC)
+    PHP_ADD_INCLUDE($OCISDKMANINC)
+    OCI8INCDIR=$OCISDKMANINC
   else
     AC_MSG_ERROR([Oracle Instant Client SDK header files not found])
   fi
@@ -271,13 +343,15 @@ dnl Header directory for Instant Client SDK zip file install
       ;;
   esac
 
+  AC_DEFINE(HAVE_OCI_INSTANT_CLIENT,1,[ ])
   AC_DEFINE(HAVE_OCI8_ATTR_STATEMENT,1,[ ])
-  AC_DEFINE(HAVE_OCI_9_2,1,[ ])
+  AC_DEFINE(HAVE_OCI_ENV_NLS_CREATE,1,[ ])
+  AC_DEFINE(HAVE_OCI_ENV_CREATE,1,[ ])
+  AC_DEFINE(HAVE_OCI_STMT_PREPARE2,1,[ ])
   AC_DEFINE(HAVE_OCI8_TEMP_LOB,1,[ ])
   AC_DEFINE(PHP_OCI8_HAVE_COLLECTIONS,1,[ ])
-  AC_DEFINE(HAVE_OCI_INSTANT_CLIENT,1,[ ])
 
-  PHP_NEW_EXTENSION(oci8, oci8.c, $ext_shared)
+  PHP_NEW_EXTENSION(oci8, oci8.c oci8_lob.c oci8_statement.c oci8_collection.c oci8_interface.c, $ext_shared)
   AC_DEFINE(HAVE_OCI8,1,[ ])
 
   PHP_SUBST_OLD(OCI8_SHARED_LIBADD)
index 9b7c195bc9b142c6f156c9dca86746cf52e23362..9d615b43afea54ab2b3163a264529f7ebbe38f43 100644 (file)
    | obtain it through the world-wide-web, please send a note to          |
    | license@php.net so we can mail you a copy immediately.               |
    +----------------------------------------------------------------------+
-   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
    |          Thies C. Arntzen <thies@thieso.net>                         |
-   |          Maxim Maletsky <maxim@maxim.cx>                             |
-   |                                                                      |
-   | Collection support by Andy Sautins <asautins@veripost.net>           |
-   | Temporary LOB support by David Benson <dbenson@mancala.com>          |
-   | ZTS per process OCIPLogon by Harald Radi <harald.radi@nme.at>        |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
    +----------------------------------------------------------------------+
- */
+*/
 
 /* $Id$ */
-
-/* TODO list:
+/* TODO
+ *
+ * file://localhost/www/docs/oci10/ociaahan.htm#423823 - implement lob_empty() with OCI_ATTR_LOBEMPTY
+ *
+ * get OCI_ATTR_CHARSET_ID attr of column to detect UTF string and multiply buffer in 4 times
  *
- * - php.ini flags 
- *   especialliy important for things like oci_ping
- *             allowpconns
- *             timeout
- *             maxlifetime
- *             maxpconns
- * - Change return-value for OCIFetch*() (1-row read, 0-Normal end, false-error) 
- * - Error mode (print or shut up?)
- * - binding of arrays
- * - Character sets for NCLOBS
- * - split the module into an upper (php-callable) and lower (c-callable) layer!
- * - remove all XXXs
- * - clean up and documentation
- * - make OCIInternalDebug accept a mask of flags....
- * - have one ocifree() call.
- * - make it possible to have persistent statements?
- * - failover
- * - change all the lob stuff to work without classes (optional)! 
- * - make sure that the callbacks terminate the strings with \0
- * - cleanup the ociexecute semantics for refcursors
- * - make $lob->savefile use O_BINARY
- * - line 2728: ub4 length = -1; needs fixing
- * - delay OCIInitialize() as far as we can.
- * - add PHP Array <-> OCICollection conversion
- * - add Collection iterator object for INDEX BY tables
- * - make auto-rollback only happen if we have an outstanding transaction
- * - implement ocidisconnect
- * - add OCI9-specific functions and separate them from OCI8 with ifdefs
- */
-
-/* {{{ includes & stuff */
+ * */
 
 #ifdef HAVE_CONFIG_H
 #include "config.h"
 #include "php.h"
 #include "ext/standard/info.h"
 #include "php_ini.h"
+#include "ext/standard/php_smart_str.h"
 
 #if HAVE_OCI8
 
 #include "php_oci8.h"
+#include "php_oci8_int.h"
 
-/* True globals, only used by thread safe functions */
-static TsHashTable *persistent_servers;
-static TsHashTable *persistent_sessions;
-
-static long num_persistent = 0;
-static long num_links = 0;
+ZEND_DECLARE_MODULE_GLOBALS(oci)
 
 /* True globals, no need for thread safety */
-static int le_conn;
-static int le_stmt;
-static int le_desc;
+int le_connection;
+int le_pconnection;
+int le_statement;
+int le_descriptor;
 #ifdef PHP_OCI8_HAVE_COLLECTIONS 
-static int le_coll;
+int le_collection;
 #endif
-static int le_server;
-static int le_session;
-static zend_class_entry *oci_lob_class_entry_ptr;
+
+zend_class_entry *oci_lob_class_entry_ptr;
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
-static zend_class_entry *oci_coll_class_entry_ptr;
+zend_class_entry *oci_coll_class_entry_ptr;
 #endif
 
 #ifndef SQLT_BFILEE
@@ -98,72 +66,27 @@ static zend_class_entry *oci_coll_class_entry_ptr;
 #define SQLT_CFILEE 115
 #endif
 
-#define SAFE_STRING(s) ((s)?(s):"")
-
-#ifdef ZTS
-MUTEX_T mx_lock;
+#define PHP_OCI_ERRBUF_LEN 512
 
-#define mutex_alloc(mutex) mutex = tsrm_mutex_alloc()
-#define mutex_free(mutex) tsrm_mutex_free(mutex)
-#define mutex_lock(mutex) tsrm_mutex_lock(mutex)
-#define mutex_unlock(mutex) tsrm_mutex_unlock(mutex)
-#define thread_id()    tsrm_thread_id()
+#if ZEND_MODULE_API_NO > 20020429
+#define ONUPDATELONGFUNC OnUpdateLong
 #else
-#define mutex_alloc(mutex)
-#define mutex_free(mutex)
-#define mutex_lock(mutex)
-#define mutex_unlock(mutex)
-#define thread_id() 1
+#define ONUPDATELONGFUNC OnUpdateInt
 #endif
 
-/* dirty marcos to make sure we _never_ call oracle-functions recursivly 
- *
- * i'm well aware that we should _never_ call exit directly - this core is for
- * pure testing and commented out - as you can see;-)
- * thies@thieso.net 20010723
- */
-
-#define CALL_OCI(call) \
-{ \
-       if (OCI(in_call)) { \
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI8 Recursive call!"); \
-               exit(-1); \
-       } else { \
-               OCI(in_call)=1; \
-               call; \
-               OCI(in_call)=0; \
-       } \
-}
-
-#define CALL_OCI_RETURN(retcode,call) \
-{ \
-       if (OCI(in_call)) { \
-               retcode=-1; \
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI8 Recursive call!"); \
-               exit(-1); \
-       } else { \
-               OCI(in_call)=1; \
-               retcode=call; \
-               OCI(in_call)=0; \
-       } \
-}
-
-#include <fcntl.h>
-
-#ifndef O_BINARY
-#define O_BINARY 0
-#endif
+/* static protos {{{ */
+static void php_oci_connection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
+static void php_oci_pconnection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
+static void php_oci_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_collection_list_dtor (zend_rsrc_list_entry * TSRMLS_DC);
 
+static int php_oci_persistent_helper(list_entry *le 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);
 /* }}} */
-/* {{{ thread safety stuff */
 
-#ifdef ZTS
-int oci_globals_id;
-#else
-PHP_OCI_API php_oci_globals oci_globals;
-#endif
-
-/* }}} */
 /* {{{ dynamically loadable module stuff */
 
 #ifdef COMPILE_DL_OCI8
@@ -174,115 +97,6 @@ ZEND_GET_MODULE(oci8)
 #endif /* COMPILE_DL */
 
 /* }}} */
-/* {{{ startup/shutdown/info/internal function prototypes */
-
-PHP_MINIT_FUNCTION(oci);
-PHP_RINIT_FUNCTION(oci);
-PHP_MSHUTDOWN_FUNCTION(oci);
-PHP_RSHUTDOWN_FUNCTION(oci);
-PHP_MINFO_FUNCTION(oci);
-
-static ub4 oci_handle_error(oci_connection *connection, ub4 errcode);
-static ub4 oci_error(OCIError *err_p, char *what, sword status);
-static int oci_ping(oci_server *server);
-static void oci_debug(const char *format, ...);
-
-static void _oci_conn_list_dtor(oci_connection *connection TSRMLS_DC);
-static void _oci_stmt_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-static void _oci_descriptor_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-static void _oci_coll_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-#endif
-static void _oci_server_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-static void _oci_session_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-static void php_oci_free_conn_list(zend_rsrc_list_entry *rsrc TSRMLS_DC);
-
-static void _oci_column_hash_dtor(void *data);
-static void _oci_define_hash_dtor(void *data);
-static void _oci_bind_hash_dtor(void *data);
-static void _oci_desc_flush_hash_dtor(void *data);
-
-static oci_connection *oci_get_conn(zval ** TSRMLS_DC);
-static oci_statement *oci_get_stmt(zval ** TSRMLS_DC);
-static oci_descriptor *oci_get_desc(int TSRMLS_DC);
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-/* Questionable name.  Very close to oci_get_col */
-static oci_collection *oci_get_coll(int TSRMLS_DC);
-#endif
-static oci_out_column *oci_get_col(oci_statement *, int, zval **);
-
-static int _oci_make_zval(zval *, oci_statement *, oci_out_column *, char *, int mode TSRMLS_DC);
-static oci_statement *oci_parse(oci_connection *, char *, int);
-static int oci_execute(oci_statement *, char *, ub4 mode);
-static int oci_fetch(oci_statement *, ub4, char * TSRMLS_DC);
-static int oci_lobgetlen(oci_connection *, oci_descriptor *, ub4 *length);
-static int oci_loadlob(oci_connection *, oci_descriptor *, char **, ub4 *length);
-static int oci_readlob(oci_connection *, oci_descriptor *, char **, ub4 *len);
-static int oci_setprefetch(oci_statement *statement, int size);
-
-static void oci_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent,int exclusive);
-
-static oci_server *_oci_open_server(char *dbname,int persistent);
-static void _oci_close_server(oci_server *server);
-
-static oci_session *_oci_open_session(oci_server* server,char *username,char *password,int persistent,int exclusive, char *charset);
-static void _oci_close_session(oci_session *session);
-
-static sb4 oci_bind_in_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 *, ub1 *, dvoid **);
-static sb4 oci_bind_out_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 **, ub1 *, dvoid **, ub2 **);
-
-#if 0
-static sb4 oci_failover_callback(dvoid *svchp,dvoid* envhp,dvoid *fo_ctx,ub4 fo_type, ub4 fo_event);
-#endif
-
-static int oci_lob_flush(oci_descriptor *, int flush_flag TSRMLS_DC);
-
-/* }}} */
-
-/* {{{ extension macros 
-*/
-#define OCI_GET_STMT(statement,value) \
-       statement = oci_get_stmt(value TSRMLS_CC); \
-       if (statement == NULL) { \
-               RETURN_FALSE; \
-       }
-
-#define OCI_GET_CONN(connection,value) \
-       connection = oci_get_conn(value TSRMLS_CC); \
-       if (connection == NULL) { \
-               RETURN_FALSE; \
-       }
-
-#define OCI_GET_DESC(descriptor,index) \
-       descriptor = oci_get_desc(index TSRMLS_CC); \
-       if (descriptor == NULL) { \
-               RETURN_FALSE; \
-       }
-
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-#define OCI_GET_COLL(collection,index) \
-       collection = oci_get_coll(index TSRMLS_CC); \
-       if (collection == NULL) { \
-               RETURN_FALSE; \
-       }
-#endif
-
-#define IS_LOB_INTERNAL(lob) \
-       if (lob->type != OCI_DTYPE_LOB) { \
-               switch (lob->type) { \
-                       case OCI_DTYPE_FILE: \
-                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "internal LOB was expected, FILE locator is given"); \
-                               break; \
-                       case OCI_DTYPE_ROWID: \
-                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "internal LOB was expected, ROWID locator is given"); \
-                               break; \
-                       default: \
-                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "internal LOB was expected, locator of unknown type is given"); \
-                               break; \
-               } \
-               RETURN_FALSE; \
-       }
-/* }}} */
 
 /* {{{ extension function prototypes
 */
@@ -363,17 +177,6 @@ PHP_FUNCTION(oci_collection_trim);
 
 /* {{{ extension definition structures
 */
-#define OCI_ASSOC               1<<0
-#define OCI_NUM                 1<<1
-#define OCI_BOTH                (OCI_ASSOC|OCI_NUM)
-
-#define OCI_RETURN_NULLS        1<<2
-#define OCI_RETURN_LOBS         1<<3
-
-#define OCI_FETCHSTATEMENT_BY_COLUMN    1<<4
-#define OCI_FETCHSTATEMENT_BY_ROW       1<<5
-#define OCI_FETCHSTATEMENT_BY           (OCI_FETCHSTATEMENT_BY_COLUMN | OCI_FETCHSTATEMENT_BY_ROW)
-
 static zend_function_entry php_oci_functions[] = {
        PHP_FE(oci_define_by_name,          third_arg_force_ref)
        PHP_FE(oci_bind_by_name,            third_arg_force_ref)
@@ -511,6 +314,8 @@ static zend_function_entry php_oci_lob_class_functions[] = {
        PHP_FALIAS(append,      oci_lob_append,         NULL)
        PHP_FALIAS(size,        oci_lob_size,           NULL)
        PHP_FALIAS(writetofile, oci_lob_export,         NULL)
+       PHP_FALIAS(export,      oci_lob_export,         NULL)
+       PHP_FALIAS(import,      oci_lob_import,         NULL)
 #ifdef HAVE_OCI8_TEMP_LOB
        PHP_FALIAS(writetemporary,  oci_lob_write_temporary,    NULL)
        PHP_FALIAS(close,           oci_lob_close,              NULL)
@@ -544,58 +349,98 @@ 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 */
-       NO_VERSION_YET,
+       "1.1",
        STANDARD_MODULE_PROPERTIES
 };
 /* }}} */
 
+/* {{{ 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.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)
+PHP_INI_END()
+/* }}} */
+
 /* {{{ startup, shutdown and info functions
 */
-static void php_oci_init_globals(php_oci_globals *oci_globals_p TSRMLS_DC)
-{ 
-       OCI(shutdown)   = 0;
-       OCI(in_call)    = 0;
-
-       CALL_OCI(
-               OCIEnvInit(
-                       &OCI(pEnv), 
-                       OCI_DEFAULT, 
-                       0, 
-                       NULL
-               )
-       );
-       
-       CALL_OCI(
-               OCIHandleAlloc(
-                       OCI(pEnv), 
-                       (dvoid **)&OCI(pError), 
-                       OCI_HTYPE_ERROR, 
-                       0, 
-                       NULL
-               )
-       );
-}
 
-static int _sessions_pcleanup(zend_llist *session_list)
+/* {{{  php_oci_init_global_handles()
+ Initialize global handles only when they are needed 
+*/
+static void php_oci_init_global_handles(TSRMLS_D)
 {
-       zend_llist_destroy(session_list);
+       sword errcode;
+       sb4 error_code = 0;
+       text tmp_buf[PHP_OCI_ERRBUF_LEN];
 
-       return 1;
-}
+       errcode = OCIEnvInit (&OCI_G(env), OCI_DEFAULT, 0, NULL);
+       
+       if (errcode == OCI_ERROR) {
+               goto oci_error;
+       }
+       
+       errcode = OCIHandleAlloc (OCI_G(env), (dvoid **)&OCI_G(err), OCI_HTYPE_ERROR, 0, NULL);
+       
+       if (errcode == OCI_ERROR || errcode == OCI_SUCCESS_WITH_INFO) {
+               goto oci_error;
+       }
 
-static int _session_pcleanup(oci_session *session)
-{
-       _oci_close_session(session);
+       return;
+       
+oci_error:
+       
+       OCIErrorGet(OCI_G(env), (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR);
 
-       return 1;
-}
+       if (error_code) {
+               int tmp_buf_len = strlen(tmp_buf);
+
+               if (tmp_buf[tmp_buf_len - 1] == '\n') {
+                       tmp_buf[tmp_buf_len - 1] = '\0';
+               }
+                       
+               if (errcode != OCI_SUCCESS_WITH_INFO) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_ERROR: %s", tmp_buf);
+                       
+                       OCIHandleFree((dvoid *) OCI_G(env), OCI_HTYPE_ENV);
+                       
+                       OCI_G(env) = NULL;
+                       OCI_G(err) = NULL;
+               }
+               else {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_SUCCESS_WITH_INFO: %s", tmp_buf);
+               }
+       }
+} /* }}} */
 
-static int _server_pcleanup(oci_server *server)
+/* {{{ php_oci_cleanup_global_handles()
+ Free global handles (if they were initialized before)
+*/
+static void php_oci_cleanup_global_handles(TSRMLS_C)
 {
-       _oci_close_server(server);
+       if (OCI_G(err)) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(err), OCI_HTYPE_ENV));
+               OCI_G(err) = NULL;
+       }
+       
+       if (OCI_G(env)) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) OCI_G(env), OCI_HTYPE_ENV));
+               OCI_G(env) = NULL;
+       }
+} /* }}} */
 
-       return 1;
+/* {{{ php_oci_init_globals()
+ Zerofill globals during module init
+*/
+static void php_oci_init_globals(zend_oci_globals *oci_globals TSRMLS_DC)
+{
+       memset(oci_globals, 0, sizeof(zend_oci_globals));
 }
+/* }}} */
 
 PHP_MINIT_FUNCTION(oci)
 {
@@ -604,53 +449,32 @@ PHP_MINIT_FUNCTION(oci)
        zend_class_entry oci_coll_class_entry;
 #endif
 
-#ifdef HAVE_OCI8_SHARED_MODE
-
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-#define PHP_OCI_INIT_MODE_TMP OCI_SHARED | OCI_OBJECT
-#else
-#define PHP_OCI_INIT_MODE_TMP OCI_SHARED
-#endif
-
-#else
-
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
 #define PHP_OCI_INIT_MODE_TMP OCI_DEFAULT | OCI_OBJECT
 #else
 #define PHP_OCI_INIT_MODE_TMP OCI_DEFAULT
 #endif
 
-#endif
-
 #ifdef ZTS
 #define PHP_OCI_INIT_MODE PHP_OCI_INIT_MODE_TMP | OCI_THREADED
 #else
 #define PHP_OCI_INIT_MODE PHP_OCI_INIT_MODE_TMP
 #endif
 
-       mutex_alloc(mx_lock);
-
-       persistent_servers = malloc(sizeof(TsHashTable));
-       persistent_sessions = malloc(sizeof(TsHashTable));
-       zend_ts_hash_init(persistent_servers, 13, NULL, (dtor_func_t) _server_pcleanup, 1); 
-       zend_ts_hash_init(persistent_sessions, 13, NULL, (dtor_func_t) _sessions_pcleanup, 1); 
-
+#if !HAVE_OCI_ENV_CREATE
        OCIInitialize(PHP_OCI_INIT_MODE, NULL, NULL, NULL, NULL);
-
-#ifdef ZTS
-       ts_allocate_id(&oci_globals_id, sizeof(php_oci_globals), (ts_allocate_ctor) php_oci_init_globals, NULL);
-#else
-       php_oci_init_globals(&oci_globals TSRMLS_CC);
 #endif
 
-       le_stmt = zend_register_list_destructors_ex(_oci_stmt_list_dtor, NULL, "oci8 statement", module_number);
-       le_conn = zend_register_list_destructors_ex(php_oci_free_conn_list, NULL, "oci8 connection", module_number);
-       le_desc = zend_register_list_destructors_ex(_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number);
+       ZEND_INIT_MODULE_GLOBALS(oci, php_oci_init_globals, NULL);
+       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_descriptor = zend_register_list_destructors_ex(php_oci_descriptor_list_dtor, NULL, "oci8 descriptor", module_number);
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
-       le_coll = zend_register_list_destructors_ex(_oci_coll_list_dtor, NULL, "oci8 collection", module_number);
+       le_collection = zend_register_list_destructors_ex(php_oci_collection_list_dtor, NULL, "oci8 collection", module_number);
 #endif
-       le_server = zend_register_list_destructors_ex(_oci_server_list_dtor, NULL, "oci8 server", module_number);
-       le_session = zend_register_list_destructors_ex(_oci_session_list_dtor, NULL, "oci8 session", module_number);
 
        INIT_CLASS_ENTRY(oci_lob_class_entry, "OCI-Lob", php_oci_lob_class_functions);
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
@@ -664,14 +488,16 @@ PHP_MINIT_FUNCTION(oci)
 
 /* thies@thieso.net 990203 i do not think that we will need all of them - just in here for completeness for now! */
        REGISTER_LONG_CONSTANT("OCI_DEFAULT",OCI_DEFAULT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_SYSOPER",OCI_SYSOPER, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_SYSDBA",OCI_SYSDBA, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_DESCRIBE_ONLY",OCI_DESCRIBE_ONLY, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_COMMIT_ON_SUCCESS",OCI_COMMIT_ON_SUCCESS, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_EXACT_FETCH",OCI_EXACT_FETCH, CONST_CS | CONST_PERSISTENT);
 
 /* for $LOB->seek() */
-       REGISTER_LONG_CONSTANT("OCI_SEEK_SET",OCI_SEEK_SET, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_SEEK_CUR",OCI_SEEK_CUR, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_SEEK_END",OCI_SEEK_END, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_SEEK_SET",PHP_OCI_SEEK_SET, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_SEEK_CUR",PHP_OCI_SEEK_CUR, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_SEEK_END",PHP_OCI_SEEK_END, CONST_CS | CONST_PERSISTENT);
 
 /*     for $LOB->flush() */
        REGISTER_LONG_CONSTANT("OCI_LOB_BUFFER_FREE",OCI_LOB_BUFFER_FREE, CONST_CS | CONST_PERSISTENT);
@@ -682,11 +508,14 @@ PHP_MINIT_FUNCTION(oci)
        REGISTER_LONG_CONSTANT("SQLT_CLOB",SQLT_CLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_BLOB",SQLT_BLOB, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_RDD",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("SQLT_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);       
+       REGISTER_LONG_CONSTANT("SQLT_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);       
+       REGISTER_LONG_CONSTANT("SQLT_RSET",SQLT_RSET, CONST_CS | CONST_PERSISTENT);
 
 #ifdef PHP_OCI8_HAVE_COLLECTIONS
        REGISTER_LONG_CONSTANT("OCI_B_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("SQLT_NTY",SQLT_NTY, CONST_CS | CONST_PERSISTENT);       
-       REGISTER_STRING_CONSTANT("OCI_SYSDATE","SYSDATE",CONST_PERSISTENT);
+       REGISTER_STRING_CONSTANT("OCI_SYSDATE","SYSDATE", CONST_CS | CONST_PERSISTENT);
 #endif
 
        REGISTER_LONG_CONSTANT("OCI_B_BFILE",SQLT_BFILEE, CONST_CS | CONST_PERSISTENT);
@@ -696,17 +525,19 @@ PHP_MINIT_FUNCTION(oci)
        REGISTER_LONG_CONSTANT("OCI_B_ROWID",SQLT_RDD, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_B_CURSOR",SQLT_RSET, CONST_CS | CONST_PERSISTENT);
        REGISTER_LONG_CONSTANT("OCI_B_BIN",SQLT_BIN, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_B_INT",SQLT_INT, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_B_NUM",SQLT_NUM, CONST_CS | CONST_PERSISTENT);
 
 /* for OCIFetchStatement */
-       REGISTER_LONG_CONSTANT("OCI_FETCHSTATEMENT_BY_COLUMN", OCI_FETCHSTATEMENT_BY_COLUMN, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_FETCHSTATEMENT_BY_ROW", OCI_FETCHSTATEMENT_BY_ROW, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_FETCHSTATEMENT_BY_COLUMN", PHP_OCI_FETCHSTATEMENT_BY_COLUMN, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_FETCHSTATEMENT_BY_ROW", PHP_OCI_FETCHSTATEMENT_BY_ROW, CONST_CS | CONST_PERSISTENT);
 
 /* for OCIFetchInto &  OCIResult */
-       REGISTER_LONG_CONSTANT("OCI_ASSOC",OCI_ASSOC, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_NUM",OCI_NUM, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_BOTH",OCI_BOTH, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT);
-       REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_ASSOC",PHP_OCI_ASSOC, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_NUM",PHP_OCI_NUM, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_BOTH",PHP_OCI_BOTH, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_RETURN_NULLS",PHP_OCI_RETURN_NULLS, CONST_CS | CONST_PERSISTENT);
+       REGISTER_LONG_CONSTANT("OCI_RETURN_LOBS",PHP_OCI_RETURN_LOBS, CONST_CS | CONST_PERSISTENT);
 
 /* for OCINewDescriptor (real "oci" names + short "php" names*/
        REGISTER_LONG_CONSTANT("OCI_DTYPE_FILE",OCI_DTYPE_FILE, CONST_CS | CONST_PERSISTENT);
@@ -730,53 +561,39 @@ PHP_MINIT_FUNCTION(oci)
 
 PHP_RINIT_FUNCTION(oci)
 {
-       OCI(debug_mode) = 0; /* start "fresh" */
-/*     OCI(in_call) = 0; i don't think we want this! */
-
-       oci_debug("php_rinit_oci");
+       OCI_G(debug_mode) = 0; /* start "fresh" */
+       OCI_G(num_links) = OCI_G(num_persistent);
+       OCI_G(errcode) = 0;
 
        return SUCCESS;
 }
 
 PHP_MSHUTDOWN_FUNCTION(oci)
 {
-       OCI(shutdown) = 1;
-
-       oci_debug("START php_mshutdown_oci");
-
-       zend_ts_hash_destroy(persistent_sessions);
-       zend_ts_hash_destroy(persistent_servers);
-
-       free(persistent_sessions);
-       free(persistent_servers);
-
-       mutex_free(mx_lock);
+       OCI_G(shutdown) = 1;
+       
+       UNREGISTER_INI_ENTRIES();
 
-       CALL_OCI(
-               OCIHandleFree(
-                               (dvoid *) OCI(pEnv), 
-                               OCI_HTYPE_ENV
-               )
-       );
+#ifndef ZTS
+       php_oci_cleanup_global_handles(TSRMLS_C);
+#endif
 
-       oci_debug("END   php_mshutdown_oci");
+#if !HAVE_OCI_ENV_CREATE
+       OCITerminate(OCI_DEFAULT);
+#endif
 
        return SUCCESS;
 }
 
 PHP_RSHUTDOWN_FUNCTION(oci)
 {
-       oci_debug("START php_rshutdown_oci");
-
-#if 0
-       /* XXX free all statements, rollback all outstanding transactions */
+       /* check persistent connections and do the necessary actions if needed */
+       zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC);
 
-       zend_ts_hash_apply(persistent_sessions, (apply_func_t) _session_cleanup TSRMLS_CC);
-       zend_ts_hash_apply(persistent_servers, (apply_func_t) _server_cleanup TSRMLS_CC);
+#ifdef ZTS
+       php_oci_cleanup_global_handles(TSRMLS_C);
 #endif
 
-       oci_debug("END   php_rshutdown_oci");
-
        return SUCCESS;
 }
 
@@ -788,12 +605,12 @@ PHP_MINFO_FUNCTION(oci)
        php_info_print_table_row(2, "OCI8 Support", "enabled");
        php_info_print_table_row(2, "Revision", "$Revision$");
 
-       sprintf(buf, "%ld", num_persistent);
+       sprintf(buf, "%ld", OCI_G(num_persistent));
        php_info_print_table_row(2, "Active Persistent Links", buf);
-       sprintf(buf, "%ld", num_links);
+       sprintf(buf, "%ld", OCI_G(num_links));
        php_info_print_table_row(2, "Active Links", buf);
 
-#ifndef PHP_WIN32
+#if !defined(PHP_WIN32) && !defined(HAVE_OCI_INSTANT_CLIENT)
        php_info_print_table_row(2, "Oracle Version", PHP_OCI8_VERSION );
        php_info_print_table_row(2, "Compile-time ORACLE_HOME", PHP_OCI8_DIR );
        php_info_print_table_row(2, "Libraries Used", PHP_OCI8_SHARED_LIBADD );
@@ -812,111 +629,102 @@ PHP_MINFO_FUNCTION(oci)
 #endif
 
        php_info_print_table_end();
+       
+       DISPLAY_INI_ENTRIES();
 }
 /* }}} */
 
-/* {{{ _oci_define_hash_dtor()
-*/
-static void _oci_define_hash_dtor(void *data)
-{
-       oci_define *define = (oci_define *) data;
-
-       oci_debug("_oci_define_hash_dtor: %s",define->name);
+/* list destructors {{{ */
 
-       zval_ptr_dtor(&define->zval);
+/* {{{ php_oci_connection_list_dtor()
+ Non-persistent connection destructor */
+static void php_oci_connection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
+{
+       php_oci_connection *connection = (php_oci_connection *)entry->ptr;
+       php_oci_connection_close(connection TSRMLS_CC);
+       OCI_G(num_links)--;
+} /* }}} */
 
-       if (define->name) {
-               efree(define->name);
-               define->name = 0;
-       }
-}
-/* }}} */
+/* {{{ php_oci_pconnection_list_dtor()
+ Persistent connection destructor */
+static void php_oci_pconnection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
+{
+       php_oci_connection *connection = (php_oci_connection *)entry->ptr;
+       php_oci_connection_close(connection TSRMLS_CC);
+       OCI_G(num_persistent)--;
+} /* }}} */
 
-/* {{{ _oci_desc_flush_hash_dtor()
- */
-static void _oci_desc_flush_hash_dtor(void *data)
+/* {{{ php_oci_statement_list_dtor()
Statement destructor */
+static void php_oci_statement_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
 {
-       oci_descriptor *descr = *(oci_descriptor **)data;
-       TSRMLS_FETCH();
-       
-       if (descr->buffering == 2 && (descr->type == OCI_DTYPE_LOB || descr->type == OCI_DTYPE_FILE)) {
-               oci_lob_flush(descr,OCI_LOB_BUFFER_FREE TSRMLS_CC);
-               descr->buffering = 1;
-       }
-}
-/* }}} */
+       php_oci_statement *statement = (php_oci_statement *)entry->ptr;
+       php_oci_statement_free(statement TSRMLS_CC);
+} /* }}} */
 
-/* {{{ _oci_bind_hash_dtor()
-*/
-static void _oci_bind_hash_dtor(void *data)
+/* {{{ php_oci_descriptor_list_dtor()
+ Descriptor destructor */
+static void php_oci_descriptor_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
 {
-       oci_bind *bind = (oci_bind *) data;
+       php_oci_descriptor *descriptor = (php_oci_descriptor *)entry->ptr;
+       php_oci_lob_free(descriptor TSRMLS_CC);
+} /* }}} */
 
-       oci_debug("_oci_bind_hash_dtor:");
+/* {{{ php_oci_collection_list_dtor()
+ Collection destructor */
+static void php_oci_collection_list_dtor(zend_rsrc_list_entry *entry TSRMLS_DC)
+{
+       php_oci_collection *collection = (php_oci_collection *)entry->ptr;
+       php_oci_collection_close(collection TSRMLS_CC);
+} /* }}} */
 
-       zval_ptr_dtor(&(bind->zval));
-}
 /* }}} */
 
-/* {{{ _oci_bind_pre_exec()
-*/
-static int _oci_bind_pre_exec(void *data TSRMLS_DC)
-{
-       oci_bind *bind = (oci_bind *) data;
+/* hash destructors {{{ */
 
-       /* reset all bind stuff to a normal state..-. */
+/* {{{ php_oci_define_hash_dtor()
+ Define hash destructor */
+void php_oci_define_hash_dtor(void *data)
+{
+       php_oci_define *define = (php_oci_define *) data;
 
-       bind->indicator = 0; 
+       zval_ptr_dtor(&define->zval);
 
-       return 0;
+       if (define->name) {
+               efree(define->name);
+               define->name = NULL;
+       }
 }
 /* }}} */
 
-/* {{{ _oci_bind_post_exec()
-*/
-static int _oci_bind_post_exec(void *data TSRMLS_DC)
+/* {{{ php_oci_bind_hash_dtor()
+ Bind hash destructor */
+void php_oci_bind_hash_dtor(void *data)
 {
-       oci_bind *bind = (oci_bind *) data;
-
-       if (bind->indicator == -1) { /* NULL */
-               zval *val = bind->zval;
-               if (Z_TYPE_P(val) == IS_STRING) {
-                       *Z_STRVAL_P(val) = '\0'; /* XXX avoid warning in debug mode */
-               }
-               zval_dtor(val);
-               ZVAL_NULL(val);
-       } else if (Z_TYPE_P(bind->zval) == IS_STRING) {
-               Z_STRVAL_P(bind->zval) = erealloc(Z_STRVAL_P(bind->zval), Z_STRLEN_P(bind->zval)+1);
-               Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] = '\0';
-       }
+       php_oci_bind *bind = (php_oci_bind *) data;
 
-
-       return 0;
+       zval_ptr_dtor(&bind->zval);
 }
 /* }}} */
 
-/* {{{ _oci_column_hash_dtor()
-*/
-static void _oci_column_hash_dtor(void *data)
+/* {{{ php_oci_column_hash_dtor()
+ Column hash destructor */
+void php_oci_column_hash_dtor(void *data)
 {      
-       oci_out_column *column = (oci_out_column *) data;
+       php_oci_out_column *column = (php_oci_out_column *) data;
        TSRMLS_FETCH();
 
-       oci_debug("START _oci_column_hash_dtor: %s",column->name);
-
        if (column->stmtid) {
                zend_list_delete(column->stmtid);
        }
 
        if (column->is_descr) {
                zend_list_delete(column->descid);
-       } else {
-               if (column->data) {
-                       efree(column->data);
-               }
        }
 
-       oci_debug("END   _oci_column_hash_dtor: %s",column->name);
+       if (column->data) {
+               efree(column->data);
+       }
 
        if (column->name) {
                efree(column->name);
@@ -924,6236 +732,922 @@ static void _oci_column_hash_dtor(void *data)
 }
 /* }}} */
 
-/* {{{ _oci_stmt_list_dtor()
-*/
-static void _oci_stmt_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
-       oci_statement *statement = (oci_statement *)rsrc->ptr;
-       oci_debug("START _oci_stmt_list_dtor: id=%d last_query=\"%s\"",statement->id,SAFE_STRING(statement->last_query));
-
-       if (statement->pStmt) {
-               CALL_OCI(
-                       OCIHandleFree(
-                               statement->pStmt, 
-                               OCI_HTYPE_STMT
-                       )
-               );
-               
-               statement->pStmt = 0;
-       }
-
-       if (statement->pError) {
-               CALL_OCI(
-                       OCIHandleFree(
-                               statement->pError, 
-                               OCI_HTYPE_ERROR
-                       )
-               );
-               
-               statement->pError = 0;
-       }
-
-       if (statement->last_query) {
-               efree(statement->last_query);
-       }
-
-       if (statement->columns) {
-               zend_hash_destroy(statement->columns);
-               efree(statement->columns);
-       }
-
-       if (statement->binds) {
-               zend_hash_destroy(statement->binds);
-               efree(statement->binds);
-       }
-
-       if (statement->defines) {
-               zend_hash_destroy(statement->defines);
-               efree(statement->defines);
-       }
-
-       oci_debug("END   _oci_stmt_list_dtor: id=%d",statement->id);
-
-       efree(statement);
-}
-/* }}} */
-
-/* {{{ _oci_conn_list_dtor()
-*/
-static void _oci_conn_list_dtor(oci_connection *connection TSRMLS_DC)
+/* {{{ php_oci_descriptor_flush_hash_dtor()
+ Flush descriptors on commit */
+void php_oci_descriptor_flush_hash_dtor(void *data)
 {
-       /* 
-          as the connection is "only" a in memory service context we do not disconnect from oracle.
-       */
-
-       oci_debug("START _oci_conn_list_dtor: id=%d",connection->id);
-
-       if (connection->pServiceContext) {
-
-               if (connection->needs_commit) {
-                       oci_debug("OCITransRollback");
-                       CALL_OCI_RETURN(connection->error,
-                               OCITransRollback(
-                                       connection->pServiceContext,
-                                       connection->pError,
-                                       (ub4)0
-                               )
-                       );
-        
-                       if (connection->error) {
-                               oci_error(connection->pError, "failed to rollback outstanding transactions!", connection->error);
-                       }
-                       connection->needs_commit = 0;
-               } else {
-                       oci_debug("nothing to do..");
-               }
-
-               CALL_OCI(
-                       OCIHandleFree(
-                               (dvoid *) connection->pServiceContext, 
-                               (ub4) OCI_HTYPE_SVCCTX
-                       )
-               );
-       }
+       php_oci_descriptor *descriptor = *(php_oci_descriptor **)data;
+       TSRMLS_FETCH();
        
-       if (connection->pError) {
-               CALL_OCI(
-                       OCIHandleFree(
-                               (dvoid *) connection->pError, 
-                               (ub4) OCI_HTYPE_ERROR
-                       )
-               );
-       }
-
-       if (connection->session && connection->session->exclusive) {
-               /* close associated session when destructed */
-               zend_list_delete(connection->session->num);
-       }
-
-       if (connection->descriptors) {
-               zend_hash_destroy(connection->descriptors);
-               efree(connection->descriptors);
-       }
-
-       oci_debug("END   _oci_conn_list_dtor: id=%d",connection->id);
-
-       efree(connection);
-}
-/* }}} */
-
-/* {{{ php_oci_free_conn_list
- */
-static void php_oci_free_conn_list(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
-       oci_connection *conn = (oci_connection *)rsrc->ptr;
-       _oci_conn_list_dtor(conn TSRMLS_CC);
-}
-/* }}} */
-
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-
-/* {{{ _oci_coll_list_dtor()
- */
-static void _oci_coll_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
-       oci_collection *coll = (oci_collection *)rsrc->ptr;
-       oci_debug("START _oci_coll_list_dtor: %d",coll->id);
-
-       /* Note sure if we need to free the object.  Have an
-          oracle TAR out on this one.
-          OCIDescriptorFree(descr->ocidescr, descr->type); */
-
-       oci_debug("END   _oci_coll_list_dtor: %d",coll->id);
-
-       efree(coll);
-}
-/* }}} */
-#endif
-
-/* {{{ _oci_descriptor_list_dtor()
- */
-static void _oci_descriptor_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
-       oci_descriptor *descr = (oci_descriptor *)rsrc->ptr;
-       oci_debug("START _oci_descriptor_list_dtor: %d",descr->id);
-
-       /* flushing Lobs & Files with buffering enabled */
-       if ((descr->type == OCI_DTYPE_FILE || descr->type == OCI_DTYPE_LOB) && descr->buffering == 2) {
-               oci_debug("descriptor #%d needs to be flushed. flushing..",descr->id);
-               oci_lob_flush(descr,OCI_LOB_BUFFER_FREE TSRMLS_CC);
-       }
-
-       CALL_OCI(
-               OCIDescriptorFree(
-                       descr->ocidescr, 
-                       descr->type
-               )
-       );
-
-       oci_debug("END   _oci_descriptor_list_dtor: %d",descr->id);
-
-       efree(descr);
-}
-/* }}} */
-
-/* {{{ _oci_server_list_dtor()
- */
-static void _oci_server_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
-#if 0
-       oci_server *server = (oci_server *)rsrc->ptr;
-       if (server->persistent)
-               return;
-
-       _oci_close_server(server);
-#endif
-}
-/* }}} */
-
-/* {{{ _oci_session_list_dtor()
- */
-static void _oci_session_list_dtor(zend_rsrc_list_entry *rsrc TSRMLS_DC)
-{
-       oci_session *session = (oci_session *)rsrc->ptr;
-       if (session->persistent) {
-               /* clear thread assignment */
-               session->thread = 0;
-               return;
+       if (descriptor->buffering == PHP_OCI_LOB_BUFFER_USED && (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE)) {
+               php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
+               descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
        }
-
-       _oci_close_session(session);
 }
 /* }}} */
 
-/* {{{ oci_handle_error
- */
-static ub4 oci_handle_error(oci_connection *connection, ub4 errcode)
-{
-       switch (errcode) {
-               case 1013: /* user requested cancel of current operation */
-                       zend_bailout();
-                       break;
-
-               case 22:   /* ORA-00022 Invalid session id */
-               case 1012: /* ORA-01012: */
-               case 3113: /* ORA-03113: end-of-file on communication channel */
-               case 604:
-               case 1041:
-                       connection->is_open = 0;
-                       connection->session->is_open = 0;
-                       connection->session->server->is_open = 0;
-                       return 1; /* fatal error */
-       }
-
-       return 0; /* no fatal error */
-}
 /* }}} */
 
-/* {{{ oci_error()
-*/
-static ub4 oci_error(OCIError *err_p, char *what, sword status)
+/* {{{ php_oci_error()
+ Fetch & print out error message if we get an error */
+sb4 php_oci_error(OCIError *err_p, sword status TSRMLS_DC)
 {
-       text errbuf[512];
+       text *errbuf = (text *)NULL;
        sb4 errcode = 0;
-       TSRMLS_FETCH();
 
        switch (status) {
                case OCI_SUCCESS:
                        break;
                case OCI_SUCCESS_WITH_INFO:
-                       CALL_OCI(
-                               OCIErrorGet(
-                                       err_p, 
-                                       (ub4)1, 
-                                       NULL, 
-                                       &errcode, 
-                                       errbuf,
-                                       (ub4)sizeof(errbuf), 
-                                       (ub4)OCI_HTYPE_ERROR
-                               )
-                       );
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: OCI_SUCCESS_WITH_INFO: %s", what, errbuf);
+                       errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_SUCCESS_WITH_INFO: %s", errbuf);
+                       efree(errbuf);
                        break;
                case OCI_NEED_DATA:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: OCI_NEED_DATA", what);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NEED_DATA");
                        break;
                case OCI_NO_DATA:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: OCI_NO_DATA", what);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_NO_DATA");
                        break;
-               case OCI_ERROR: {
-                       CALL_OCI(
-                               OCIErrorGet(
-                                       err_p, 
-                                       (ub4)1, 
-                                       NULL, 
-                                       &errcode, 
-                                       errbuf,
-                                       (ub4)sizeof(errbuf), 
-                                       (ub4)OCI_HTYPE_ERROR
-                               )
-                       );
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: %s", what, errbuf);
+               case OCI_ERROR: 
+                       errcode = php_oci_fetch_errmsg(err_p, &errbuf TSRMLS_CC);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s", errbuf);
+                       efree(errbuf);
                        break;
-               }
                case OCI_INVALID_HANDLE:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: OCI_INVALID_HANDLE", what);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_INVALID_HANDLE");
                        break;
                case OCI_STILL_EXECUTING:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: OCI_STILL_EXECUTING", what);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_STILL_EXECUTING");
                        break;
                case OCI_CONTINUE:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "%s: OCI_CONTINUE", what);
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCI_CONTINUE");
                        break;
                default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown OCI error code: %d", status);
                        break;
        }
        return errcode;
 }
 /* }}} */
 
-/* {{{ oci_ping()
-*/
-static int oci_ping(oci_server *server)
+/* {{{ php_oci_fetch_errmsg()
+ Fetch error message into the buffer from the error handle provided */
+sb4 php_oci_fetch_errmsg(OCIError *error_handle, text **error_buf TSRMLS_DC)
 {
-       char version[256];
-       TSRMLS_FETCH();
+       sb4 error_code = 0;
+       text tmp_buf[PHP_OCI_ERRBUF_LEN];
+
+       tmp_buf[0] = '\0';
        
-       CALL_OCI_RETURN(OCI(error),
-               OCIServerVersion(
-                       server->pServer,
-                       OCI(pError), 
-                       (text*)version, 
-                       sizeof(version),
-                       OCI_HTYPE_SERVER
-               )
-       );
-
-       if (OCI(error) == OCI_SUCCESS) {
-               return 1;
+       PHP_OCI_CALL(OCIErrorGet, (error_handle, (ub4)1, NULL, &error_code, tmp_buf, (ub4)PHP_OCI_ERRBUF_LEN, (ub4)OCI_HTYPE_ERROR));
+       
+       if (error_code) {
+               int tmp_buf_len = strlen(tmp_buf);
+               
+               if (tmp_buf[tmp_buf_len - 1] == '\n') {
+                       tmp_buf[tmp_buf_len - 1] = '\0';
+               }
+               if (error_buf) {
+                       *error_buf = NULL;
+                       *error_buf = estrndup(tmp_buf, tmp_buf_len + 1);
+               }
        }
+       return error_code;
+} /* }}} */
 
-       oci_error(OCI(pError), "oci_ping", OCI(error));
-
-       return 0;
-}
-/* }}} */
-
-/************************* INTERNAL FUNCTIONS *************************/
-
-/* {{{ oci_debug()
-*/
-static void oci_debug(const char *format, ...)
+#ifdef HAVE_OCI8_ATTR_STATEMENT
+/* {{{ php_oci_fetch_sqltext_offset()
+ Compute offset in the SQL statement */
+int php_oci_fetch_sqltext_offset(php_oci_statement *statement, text **sqltext, ub2 *error_offset TSRMLS_DC)
 {
-       TSRMLS_FETCH();
-
-       if (OCI(debug_mode)) {
-               char buffer[1024];
-               va_list args;
+       *sqltext = NULL;
+       *error_offset = 0;
 
-               va_start(args, format);
-               vsnprintf(buffer, sizeof(buffer)-1, format, args);
-               va_end(args);
-               buffer[sizeof(buffer)-1] = '\0';
-               php_printf("OCIDebug: %s<br />\n", buffer);
+       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (text *) sqltext, (ub4 *)0, OCI_ATTR_STATEMENT, statement->err));
+       
+       if (statement->errcode != OCI_SUCCESS) { 
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               return 1;
        }
-}
-/* }}} */
 
-/* {{{ oci_get_conn()
-*/
-static oci_connection *oci_get_conn(zval **conn TSRMLS_DC)
-{
-       oci_connection *connection;
-
-       connection = (oci_connection *) zend_fetch_resource(conn TSRMLS_CC, -1, "OCI8-Connection", NULL, 1, le_conn);
-
-       if (connection && connection->is_open) {
-               return connection;
-       } else {
-               return (oci_connection *) NULL;
-       }
-}
-/* }}} */
-
-/* {{{ oci_get_stmt()
-*/
-static oci_statement *oci_get_stmt(zval **stmt TSRMLS_DC)
-{
-       oci_statement *statement;
-
-       statement = (oci_statement *) zend_fetch_resource(stmt TSRMLS_CC, -1, "OCI8-Statement", NULL, 1, le_stmt);
-
-       if (statement && statement->conn->is_open) {
-               return statement;
-       } else {
-               return (oci_statement *) NULL;
-       }
-}
-/* }}} */
-
-/* {{{ oci_get_desc()
-*/
-static oci_descriptor *oci_get_desc(int ind TSRMLS_DC)
-{
-       oci_descriptor *descriptor;
-       int actual_resource_type;
-
-       descriptor = (oci_descriptor *) zend_list_find(ind, &actual_resource_type);
-
-       if (descriptor && (actual_resource_type == le_desc)) {
-               return descriptor;
-       } else {
-               return (oci_descriptor *) NULL;
+       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)error_offset, (ub4 *)0, OCI_ATTR_PARSE_ERROR_OFFSET, statement->err));
+       
+       if (statement->errcode != OCI_SUCCESS) { 
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               return 1;
        }
-}
-/* }}} */
+       return 0;
+} /* }}} */
+#endif
 
-/* {{{ oci_get_col()
-*/
-static oci_out_column *oci_get_col(oci_statement *statement, int col, zval **value)
+/* {{{ php_oci_do_connect() 
+ Connect wrapper */
+void php_oci_do_connect(INTERNAL_FUNCTION_PARAMETERS, int persistent, int exclusive)
 {
-       oci_out_column *outcol = NULL;
-       int i;
-       TSRMLS_FETCH();
+       php_oci_connection *connection;
+       char *username, *password;
+       char *dbname = NULL, *charset = NULL;
+       long username_len, password_len;
+       long dbname_len = 0, charset_len = 0;
+       long session_mode = OCI_DEFAULT;
 
-       if (statement->columns == 0) { /* we release the columns at the end of a fetch */
-               return NULL;
+       /* if a fourth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ss|ssl", &username, &username_len, &password, &password_len, &dbname, &dbname_len, &charset, &charset_len, &session_mode) == FAILURE) {
+               return;
+       } 
+       
+       if (!charset_len) {
+               charset = NULL;
        }
+       
+       connection = php_oci_do_connect_ex(username, username_len, password, password_len, NULL, 0, dbname, dbname_len, charset, session_mode, persistent, exclusive TSRMLS_CC);
 
-       if (value) {
-               if (Z_TYPE_PP(value) == IS_STRING) {
-                       for (i = 0; i < statement->ncolumns; i++) {
-                               outcol = oci_get_col(statement, i + 1, 0);
-                               if (outcol == NULL) {
-                                       continue;
-                               } else if (((int) outcol->name_len == Z_STRLEN_PP(value)) && 
-                                                       (!strncmp(outcol->name, Z_STRVAL_PP(value), Z_STRLEN_PP(value)))
-                               ) {
-                                       return outcol;
-                               }
-                       }
-               } else {
-                       convert_to_long_ex(value);
-                       return oci_get_col(statement,Z_LVAL_PP(value),0);
-               }
-       } else if (col != -1) {
-               if (zend_hash_index_find(statement->columns, col, (void **)&outcol) == FAILURE) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column %d", col);
-                       return NULL;
-               }
-               return outcol;
+       if (!connection) {
+               RETURN_FALSE;
        }
+       RETURN_RESOURCE(connection->rsrc_id);
+       
+} /* }}} */
 
-       return NULL;
-}
-/* }}} */
-
-/* {{{ oci_new_desc()
-*/
-static oci_descriptor *oci_new_desc(int type, oci_connection *connection)
+/* {{{ php_oci_do_connect_ex()
+ * The real connect function. Allocates all the resources needed, establishes the connection and returns the result handle (or NULL) */
+php_oci_connection *php_oci_do_connect_ex(char *username, long username_len, char *password, long password_len, char *new_password, long new_password_len, char *dbname, long dbname_len, char *charset, long session_mode, int persistent, int exclusive TSRMLS_DC) 
 {
-       oci_descriptor *descr;
-       TSRMLS_FETCH();
-
-       descr = emalloc(sizeof(oci_descriptor));
+       list_entry *le;
+       list_entry new_le;
+       php_oci_connection *connection = NULL;
+       smart_str hashed_details = {0};
+       time_t timestamp;
+#if HAVE_OCI_ENV_NLS_CREATE
+       ub2 charsetid = 0;
+#endif
        
-       descr->type = type;
-
-       switch (descr->type) {
-               case OCI_DTYPE_FILE:
-               case OCI_DTYPE_LOB:
-               case OCI_DTYPE_ROWID:
+       switch (session_mode) {
+               case OCI_DEFAULT:
+                       break;
+               case OCI_SYSOPER:
+               case OCI_SYSDBA:
+                       if (!OCI_G(privileged_connect)) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Privileged connect is disabled. Enable oci8.privileged_connect to be able to connect as SYSOPER or SYSDBA");
+                               return NULL;
+                       }
                        break;
-
                default:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown descriptor type %d.", descr->type);
-                       efree(descr);
-                       return 0;
-       }
-       
-       CALL_OCI_RETURN(OCI(error),
-               OCIDescriptorAlloc(
-                       connection->session->pEnv,
-                       (dvoid*)&(descr->ocidescr), 
-                       descr->type, 
-                       (size_t) 0, 
-                       (dvoid **) 0
-               )
-       );
-       
-       if (OCI(error)) {
-               ub4 error;
-               error = oci_error(OCI(pError),"OCIDescriptorAlloc %d",OCI(error));
-               oci_handle_error(connection, error);
-               efree(descr);
-               return 0;
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid session mode specified (%ld)", session_mode);
+                       return NULL;
+                       break;
        }
 
-       descr->id = zend_list_insert(descr,le_desc);
-       descr->conn = connection;
-       descr->lob_current_position = 0;
-       descr->lob_size = -1;                           /* we should set it to -1 to know, that it's just not initialized */
-       descr->buffering = 0;                           /* buffering is off by default */
-       zend_list_addref(connection->id);
-   
-       if (descr->type == OCI_DTYPE_LOB || descr->type == OCI_DTYPE_FILE) {
-               /* add Lobs & Files to hash. we'll flush them ate the end */
-               if (!connection->descriptors) {
-                       ALLOC_HASHTABLE(connection->descriptors);
-                       zend_hash_init(connection->descriptors, 13, NULL, _oci_desc_flush_hash_dtor, 0);
-               }
-
-               zend_hash_next_index_insert(connection->descriptors,&descr,sizeof(oci_descriptor *),NULL);
+       smart_str_appendl_ex(&hashed_details, "oci8___", sizeof("oci8___") - 1, 0);
+       smart_str_appendl_ex(&hashed_details, username, username_len, 0);
+       smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0);
+       if (dbname) {
+               smart_str_appendl_ex(&hashed_details, dbname, dbname_len, 0);
        }
-       oci_debug("oci_new_desc %d",descr->id);
-
-       return descr;
-}
-/* }}} */
+       smart_str_appendl_ex(&hashed_details, "__", sizeof("__") - 1, 0);
 
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
+#if HAVE_OCI_ENV_NLS_CREATE
+       if (charset && *charset) {
+               smart_str_appends_ex(&hashed_details, charset, 1);
+       }
+       else {
+               size_t rsize;
 
-/* {{{ _oci_get_ocicoll()
-*/
-static int _oci_get_ocicoll(zval *id,oci_collection **collection TSRMLS_DC)
-{
-       zval **coll;
-       
-       if (zend_hash_find(Z_OBJPROP_P(id), "collection", sizeof("collection"), (void **)&coll) == FAILURE) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot find collection");
-               return 0;
+               PHP_OCI_CALL(OCINlsEnvironmentVariableGet, (&charsetid, 2, OCI_NLS_CHARSET_ID, 0, &rsize));
+               smart_str_append_unsigned_ex(&hashed_details, charsetid, 0);
        }
-       if ((*collection = oci_get_coll(Z_LVAL_PP(coll) TSRMLS_CC)) == NULL) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "collection not found");
-               return 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");
        }
-       return Z_LVAL_PP(coll);
-}
-/* }}} */
-
 #endif
 
-/* {{{ _oci_get_ocidesc()
-*/
-static int _oci_get_ocidesc(zval *id,oci_descriptor **descriptor TSRMLS_DC)
-{
-       zval **desc;
-       
-       if (zend_hash_find(Z_OBJPROP_P(id), "descriptor", sizeof("descriptor"), (void **)&desc) == FAILURE) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot find descriptor");
-               return 0;
-       }
-
-       if ((*descriptor = oci_get_desc(Z_LVAL_PP(desc) TSRMLS_CC)) == NULL) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "descriptor not found");
-               return 0;
-       }
+       timestamp = time(NULL);
        
-       return Z_LVAL_PP(desc);
-}
-/* }}} */
+       smart_str_append_unsigned_ex(&hashed_details, session_mode, 0);
+       smart_str_0(&hashed_details);
 
-/* {{{ _oci_make_zval()
-*/
-static int _oci_make_zval(zval *value,oci_statement *statement,oci_out_column *column, char *func, int mode TSRMLS_DC)
-{
-       oci_descriptor *descr;
-       ub4 loblen;
-       int size;
-       char *buffer;
+       /* Initialize global handles if the weren't initialized before */
        
-       if (column->indicator || column->retcode)
-               if ((column->indicator != -1) && (column->retcode != 1405))
-                       oci_debug("_oci_make_zval: %16s,retlen = %4d,retlen4 = %d,storage_size4 = %4d,indicator %4d, retcode = %4d",
-                                       column->name,column->retlen,column->retlen4,column->storage_size4,column->indicator,column->retcode);
-       
-       if ((!statement->has_data) || (column->indicator == -1)) { /* column is NULL or statment has no current data */
-               ZVAL_NULL(value); 
-               return 0;
+       if (OCI_G(env) == NULL) {
+               php_oci_init_global_handles(TSRMLS_C);
        }
        
-       if (column->is_cursor) { /* REFCURSOR -> simply return the statement id */
-               ZVAL_RESOURCE(value,column->stmtid);
-               zend_list_addref(column->stmtid);
-       } else if (column->is_descr) {
-               if ((column->data_type != SQLT_RDD) && (mode & OCI_RETURN_LOBS)) {
-                       /* OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
-
-                       descr = oci_get_desc(column->descid TSRMLS_CC);
-                       if (!descr) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "unable to find my descriptor %p",column->data);
-                               return -1;
-                       }
-                       
-                       if (oci_loadlob(statement->conn,descr,&buffer,&loblen)) {
-                               ZVAL_FALSE(value);
+       if (!exclusive && !new_password) {
+               
+               if (persistent && zend_hash_find(&EG(persistent_list), hashed_details.c, hashed_details.len+1, (void **) &le) == SUCCESS) {
+                       /* found */
+                       if (le->type == le_pconnection) {
+                               connection = (php_oci_connection *)le->ptr;     
+                       }
+               }
+               else if (!persistent && zend_hash_find(&EG(regular_list), hashed_details.c, hashed_details.len+1, (void **) &le) == SUCCESS) {
+                       if (le->type == le_index_ptr) {
+                               connection = (php_oci_connection *)le->ptr;
+                       }
+               }
+
+               if (connection) {
+                       if (connection->is_open) {
+                               /* found an open connection. now ping it */
+                               if (connection->is_persistent) {
+                                       /* check connection liveness in the following order:
+                                        * 1) always check OCI_ATTR_SERVER_STATUS
+                                        * 2) see if it's time to ping it
+                                        * 3) ping it if needed 
+                                        * */
+                                       if (php_oci_connection_status(connection TSRMLS_CC)) {
+                                               /* only ping if: 
+                                                * 1) next_ping > 0, which means that ping_interval is not -1 (aka "Off")
+                                                * 2) current_timestamp > next_ping, which means "it's time to check if it's still alive"
+                                                * */
+                                               if ( (connection->next_ping > 0) && (timestamp > connection->next_ping) && !php_oci_connection_ping(connection TSRMLS_CC)) {
+                                                       /* server died */
+                                               }
+                                               else {
+                                                       /* okay, the connection is open and the server is still alive */
+                                                       connection->used_this_request = 1;
+                                                       smart_str_free_ex(&hashed_details, 0);
+                                                       connection->rsrc_id = zend_list_insert(connection, le_pconnection);
+                                                       return connection;
+                                               }
+                                       }
+                                       /* server died */
+                                       zend_hash_del(&EG(persistent_list), hashed_details.c, hashed_details.len+1);
+                                       php_oci_connection_close(connection TSRMLS_CC);
+                                       connection = NULL;
+                                       goto open;
+                               }
+                               else {
+                                       /* we do not ping non-persistent connections */
+                                       smart_str_free_ex(&hashed_details, 0);
+                                       zend_list_addref(connection->rsrc_id);
+                                       return connection;
+                               }
                        } else {
-                               ZVAL_STRINGL(value,buffer,loblen,0);
-                       } 
-               } else { 
-                       /* return the locator */
-                       object_init_ex(value, oci_lob_class_entry_ptr);
-                       add_property_resource(value, "descriptor", column->descid);
-                       zend_list_addref(column->descid);
+                               zend_hash_del(&EG(regular_list), hashed_details.c, hashed_details.len+1);
+                               connection = NULL;
+                               goto open;
+                       }
                }
-       } else {
-               switch (column->retcode) {
-               case 0: 
-                       /* intact value */
-                       if (column->piecewise) {
-                               size = column->retlen4;
-                       } else {
-                               size = column->retlen;
+               else {
+                       /* found something, but it's not a connection, delete it */
+                       if (persistent) {
+                               zend_hash_del(&EG(persistent_list), hashed_details.c, hashed_details.len+1);
                        }
-                       break;
+                       else {
+                               zend_hash_del(&EG(regular_list), hashed_details.c, hashed_details.len+1);
+                       }
+               }
+       }
+open:
+       if (persistent) {
+               zend_bool alloc_non_persistent = 0;
                        
-               default:                                
-                       /* XXX we SHOULD maybe have a different behaviour for unknown results! */
-                       ZVAL_FALSE(value); 
-                       return 0;
+               if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) {
+                       /* try to find an idle connection and kill it */
+                       zend_hash_apply(&EG(persistent_list), (apply_func_t) php_oci_persistent_helper TSRMLS_CC);
+                       
+                       if (OCI_G(max_persistent)!=-1 && OCI_G(num_persistent)>=OCI_G(max_persistent)) {
+                               /* all persistent connactions are in use, fallback to non-persistent connection creation */
+                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Too many open persistent links (%ld)", OCI_G(num_persistent));
+                               alloc_non_persistent = 1;
+                       }
                }
                
-               ZVAL_STRINGL(value,column->data,size,1);
+               if (alloc_non_persistent) {
+                       connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
+                       connection->hash_key = estrndup(hashed_details.c, hashed_details.len+1);
+                       connection->is_persistent = 0;
+               }
+               else {
+                       connection = (php_oci_connection *) calloc(1, sizeof(php_oci_connection));
+                       connection->hash_key = zend_strndup(hashed_details.c, hashed_details.len);
+                       connection->is_persistent = 1;
+               }
        }
-
-       return 0;
-}
-/* }}} */
-
-/* {{{ oci_setprefetch()
-*/
-static int oci_setprefetch(oci_statement *statement,int size)
-{ 
-       ub4   prefetch;
-       sword error;
-       TSRMLS_FETCH();
-
-       prefetch = size * 1024;
-
-       CALL_OCI_RETURN(error,
-               OCIAttrSet(
-                       statement->pStmt,
-                       OCI_HTYPE_STMT,
-                       &prefetch,
-                       0, 
-                       OCI_ATTR_PREFETCH_MEMORY,
-                       statement->pError
-               )
-       );
-
-       statement->error = oci_error(statement->pError, "OCIAttrSet OCI_ATTR_PREFETCH_MEMORY", error);
-
-       if (statement->error) {
-               oci_handle_error(statement->conn, statement->error);
+       else {
+               connection = (php_oci_connection *) ecalloc(1, sizeof(php_oci_connection));
+               connection->hash_key = estrndup(hashed_details.c, hashed_details.len+1);
+               connection->is_persistent = 0;
        }
 
-       prefetch = size;
-       CALL_OCI_RETURN(error,
-               OCIAttrSet(
-                       statement->pStmt,
-                       OCI_HTYPE_STMT,
-                       &prefetch,
-                       0, 
-                       OCI_ATTR_PREFETCH_ROWS,
-                       statement->pError
-               )
-       );
-
-       statement->error = oci_error(statement->pError, "OCIAttrSet OCI_ATTR_PREFETCH_MEMORY", error);
-       if (statement->error) {
-               oci_handle_error(statement->conn, statement->error);
+       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);
        }
-
-       return 1;
-}
-/* }}} */
-
-/* {{{ oci_parse()
-*/
-static oci_statement *oci_parse(oci_connection *connection, char *query, int len)
-{
-       oci_statement *statement;
-       sword error;
-       TSRMLS_FETCH();
-
-       statement = ecalloc(1,sizeof(oci_statement));
-
-       CALL_OCI(
-               OCIHandleAlloc(
-                       connection->session->pEnv,
-                       (dvoid **)&statement->pStmt,
-                       OCI_HTYPE_STMT, 
-                       0, 
-                       NULL
-               )
-       );
-
-       CALL_OCI(
-               OCIHandleAlloc(
-                       connection->session->pEnv,
-                       (dvoid **)&statement->pError,
-                       OCI_HTYPE_ERROR,
-                       0,
-                       NULL
-               )
-       );
-
-       if (len > 0) {
-               CALL_OCI_RETURN(error, 
-                       OCIStmtPrepare(
-                               statement->pStmt,
-                               connection->pError,
-                               (text*)query,
-                               len,
-                               OCI_NTV_SYNTAX,
-                               OCI_DEFAULT
-                       )
-               );
-
-               connection->error = oci_error(connection->pError, "OCIParse", error);
-               if (connection->error) {
-                       CALL_OCI(
-                               OCIHandleFree(
-                                       statement->pStmt, 
-                                       OCI_HTYPE_STMT
-                               )
-                       );
-                       
-                       CALL_OCI(
-                               OCIHandleFree(
-                                       statement->pError, 
-                                       OCI_HTYPE_ERROR
-                               )
-                       );
-
-                       efree(statement);
-                       oci_handle_error(connection, connection->error);
-                       return 0;
-               }
+       else {
+               /* -1 means "Off" */
+               connection->next_ping = 0;
        }
+       
+       smart_str_free_ex(&hashed_details, 0);
 
-       if (query) {
-               statement->last_query = estrdup(query);
+       /* allocate environment handle */
+#if HAVE_OCI_ENV_NLS_CREATE
+#define PHP_OCI_INIT_FUNC_NAME "OCIEnvNlsCreate"
+       
+       if (charset && *charset) {
+               charsetid = PHP_OCI_CALL(OCINlsCharSetNameToId, (OCI_G(env), charset));
+               connection->charset = charsetid;
+       }
+       else if (charsetid) {
+               connection->charset = charsetid;
        }
 
-       statement->conn = connection;
-       statement->has_data = 0;
-
-       statement->id = zend_list_insert(statement,le_stmt);
-
-       oci_debug("oci_parse \"%s\" id=%d conn=%d",
-                               SAFE_STRING(query),
-                               statement->id,
-                               statement->conn->id);
-
-       zend_list_addref(statement->conn->id);
-
-       return statement;
-}
-/* }}} */
+       /* create an environment using the character set id, Oracle 9i+ ONLY */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIEnvNlsCreate, (&(connection->env), PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL, charsetid, charsetid));
 
-/* {{{ oci_execute()
-*/
-static int oci_execute(oci_statement *statement, char *func,ub4 mode)
-{
-       oci_out_column *outcol;
-       oci_out_column column;
-       OCIParam *param = 0;
-       text *colname;
-       ub4 counter;
-       ub2 define_type;
-       ub4 iters;
-       ub4 colcount;
-       ub2 dynamic;
-       int dtype;
-       dvoid *buf;
-       oci_descriptor *descr;
-       sword error;
-       TSRMLS_FETCH();
+#elif HAVE_OCI_ENV_CREATE
+#define PHP_OCI_INIT_FUNC_NAME "OCIEnvCreate"
+       
+       /* allocate env handle without NLS support */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIEnvCreate, (&(connection->env), PHP_OCI_INIT_MODE, 0, NULL, NULL, NULL, 0, NULL));
+#else
+#define PHP_OCI_INIT_FUNC_NAME "OCIEnvInit"
+       
+       /* the simpliest way */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIEnvInit, (&(connection->env), OCI_DEFAULT, 0, NULL));
+#endif
 
-       if (!statement->stmttype) {
-               CALL_OCI_RETURN(error,
-                       OCIAttrGet(
-                               (dvoid *)statement->pStmt,
-                               OCI_HTYPE_STMT,
-                               (ub2 *)&statement->stmttype,
-                               (ub4 *)0,
-                               OCI_ATTR_STMT_TYPE,
-                               statement->pError
-                       )
-               );
-
-               statement->error = oci_error(statement->pError, "OCIAttrGet OCI_HTYPE_STMT/OCI_ATTR_STMT_TYPE", error);
-
-               if (statement->error) {
-                       oci_handle_error(statement->conn, statement->error);
-                       return 0;
-               }
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+#ifdef HAVE_OCI_INSTANT_CLIENT
+               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");
+#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 {{{ */    
+       OCI_G(errcode) = PHP_OCI_CALL(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;
+       } /* }}} */
 
-       if (statement->stmttype == OCI_STMT_SELECT) {
-               iters = 0;
-       } else {
-               iters = 1;
-       }
+       /* attach to the server {{{ */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIServerAttach, (connection->server, OCI_G(err), (text*)dbname, dbname_len, (ub4) OCI_DEFAULT));
        
-       if (statement->last_query) { 
-               /* if we execute refcursors we don't have a query and 
-                  we don't want to execute!!! */
+       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;
 
-               if (statement->binds) {
-                       zend_hash_apply(statement->binds, (apply_func_t) _oci_bind_pre_exec TSRMLS_CC);
-               }
+       /* allocate our session handle {{{ */
+       OCI_G(errcode) = PHP_OCI_CALL(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;
+       } /* }}} */
 
-               CALL_OCI_RETURN(error,
-                       OCIStmtExecute(
-                               statement->conn->pServiceContext,
-                               statement->pStmt,
-                               statement->pError,
-                               iters,
-                               0,
-                               NULL,
-                               NULL,
-                               mode
-                       )
-               );
-
-               statement->error = oci_error(statement->pError, "OCIStmtExecute", error);
-
-               if (statement->binds) {
-                       zend_hash_apply(statement->binds, (apply_func_t) _oci_bind_post_exec TSRMLS_CC);
-               }
+       /* allocate our private error-handle {{{ */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(connection->err), OCI_HTYPE_ERROR, 0, NULL));
 
-               oci_handle_error(statement->conn, statement->error);
+       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 (statement->error) {
-                       return 0;
-               }
+       /* allocate our service-context {{{ */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(connection->svc), OCI_HTYPE_SVCCTX, 0, NULL));
 
-               if (mode & OCI_COMMIT_ON_SUCCESS) {
-                       statement->conn->needs_commit = 0;
-               } else {
-                       statement->conn->needs_commit = 1;
-               }
-       }
+       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 ((statement->stmttype == OCI_STMT_SELECT) && (statement->executed == 0)) {
-               /* we only need to do the define step is this very statement is executed the first time! */
-               statement->executed = 1;
+       /* set the username {{{ */
+       if (username) {
+               OCI_G(errcode) = PHP_OCI_CALL(OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) username, (ub4) username_len, (ub4) OCI_ATTR_USERNAME, OCI_G(err)));
                
-               ALLOC_HASHTABLE(statement->columns);
-               zend_hash_init(statement->columns, 13, NULL, _oci_column_hash_dtor, 0);
-               
-               counter = 1;
-
-               CALL_OCI_RETURN(error,
-                       OCIAttrGet(
-                               (dvoid *)statement->pStmt,
-                               OCI_HTYPE_STMT,
-                               (dvoid *)&colcount,
-                               (ub4 *)0,
-                               OCI_ATTR_PARAM_COUNT,
-                               statement->pError
-                       )
-               );
-
-               statement->error = oci_error(statement->pError, "OCIAttrGet OCI_HTYPE_STMT/OCI_ATTR_PARAM_COUNT", error);
-               if (statement->error) {
-                       oci_handle_error(statement->conn, statement->error);
-                       return 0; /* XXX we loose memory!!! */
-               }
+               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;
+               } 
+       }/* }}} */
 
-               statement->ncolumns = colcount;
+       /* set the password {{{ */
+       if (password) {
+               OCI_G(errcode) = PHP_OCI_CALL(OCIAttrSet, ((dvoid *) connection->session, (ub4) OCI_HTYPE_SESSION, (dvoid *) password, (ub4) password_len, (ub4) OCI_ATTR_PASSWORD, OCI_G(err)));
                
-               for (counter = 1; counter <= colcount; counter++) {
-                       memset(&column,0,sizeof(oci_out_column));
-                       
-                       if (zend_hash_index_update(statement->columns, counter, &column,
-                                                                               sizeof(oci_out_column), (void**) &outcol) == FAILURE) {
-                               efree(statement->columns);
-                               /* out of memory */
-                               return 0;
-                       } 
-                       
-                       outcol->statement = statement;
-
-                       CALL_OCI_RETURN(error,
-                               OCIParamGet(
-                                       (dvoid *)statement->pStmt,
-                                       OCI_HTYPE_STMT,
-                                       statement->pError,
-                                       (dvoid**)&param,
-                                       counter
-                               )
-                       );
-
-                       statement->error = oci_error(statement->pError, "OCIParamGet OCI_HTYPE_STMT", error);
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we loose memory!!! */
-                       }
+               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;
+               } 
+       }/* }}} */
 
-                       CALL_OCI_RETURN(error,
-                               OCIAttrGet(
-                                       (dvoid *)param,
-                                       OCI_DTYPE_PARAM,
-                                       (dvoid *)&outcol->data_type,
-                                       (ub4 *)0,
-                                       OCI_ATTR_DATA_TYPE,
-                                       statement->pError
-                               )
-                       );
-
-                       statement->error = oci_error(statement->pError, "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_DATA_TYPE", error);
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we loose memory!!! */
-                       }
+       /* set the server handle in the service handle {{{ */ 
+       OCI_G(errcode) = PHP_OCI_CALL(OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->server, 0, OCI_ATTR_SERVER, OCI_G(err)));
 
-                       CALL_OCI_RETURN(error,
-                               OCIAttrGet(
-                                       (dvoid *)param,
-                                       OCI_DTYPE_PARAM,
-                                       (dvoid *)&outcol->data_size,
-                                       (dvoid *)0,
-                                       OCI_ATTR_DATA_SIZE,
-                                       statement->pError
-                               )
-                       );
-
-                       statement->error = oci_error(statement->pError, "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_DATA_SIZE", error);
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we loose memory!!! */
-                       }
+       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;
+       } /* }}} */
 
-                       outcol->storage_size4 = outcol->data_size;
-                       outcol->retlen = outcol->data_size;
-       
-                       CALL_OCI_RETURN(error,
-                               OCIAttrGet(
-                                       (dvoid *)param, 
-                                       OCI_DTYPE_PARAM, 
-                                       (dvoid *)&outcol->scale, 
-                                       (dvoid *)0, 
-                                       OCI_ATTR_SCALE, 
-                                       statement->pError
-                               )
-                       );
-                                               
-                       statement->error = oci_error(statement->pError, "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_SCALE", error);
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we lose memory!!! */
-                       }
+       /* set the authentication handle in the service handle {{{ */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIAttrSet, (connection->svc, OCI_HTYPE_SVCCTX, connection->session, 0, OCI_ATTR_SESSION, OCI_G(err)));
 
-                       CALL_OCI_RETURN(error,
-                               OCIAttrGet(
-                                       (dvoid *)param, 
-                                       OCI_DTYPE_PARAM, 
-                                       (dvoid *)&outcol->precision, 
-                                       (dvoid *)0, 
-                                       OCI_ATTR_PRECISION, 
-                                       statement->pError
-                               )
-                       );
-
-                       statement->error = oci_error(statement->pError, "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_PRECISION", error);
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we lose memory!!! */
-                       }
-                                       
-                       CALL_OCI_RETURN(error,
-                               OCIAttrGet(
-                                       (dvoid *)param, 
-                                       OCI_DTYPE_PARAM, 
-                                       (dvoid **)&colname,                                     /* XXX this string is NOT zero terminated!!!! */ 
-                                       (ub4 *)&outcol->name_len, 
-                                       (ub4)OCI_ATTR_NAME, 
-                                       statement->pError
-                               )
-                       );
-
-                       statement->error = oci_error(statement->pError, "OCIAttrGet OCI_DTYPE_PARAM/OCI_ATTR_NAME", error);
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we loose memory!!! */
-                       }
+       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;
+       } /* }}} */
 
-                       outcol->name =  estrndup((char*) colname,outcol->name_len);
+       if (new_password) {
+               /* try to change password if new one was provided {{{ */
+               OCI_G(errcode) = PHP_OCI_CALL(OCIPasswordChange, (connection->svc, OCI_G(err), (text *)username, username_len+1, (text *)password, password_len+1, (text *)new_password, new_password_len+1, OCI_AUTH));
 
-                       /* find a user-setted define */
-                       if (statement->defines) {
-                               zend_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define);
-                       }
+               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;
+               }
 
-                       buf = 0;
-                       switch (outcol->data_type) {
-                               case SQLT_RSET:
-                                       outcol->pstmt = oci_parse(statement->conn,0,0);
-                                       outcol->stmtid = outcol->pstmt->id;
-
-                                       define_type = SQLT_RSET;
-                                       outcol->is_cursor = 1;
-                                       outcol->storage_size4 = -1;
-                                       outcol->retlen = -1;
-                                       dynamic = OCI_DEFAULT;
-                                       buf = &(outcol->pstmt->pStmt);
-                                       break;
-
-                               case SQLT_RDD:   /* ROWID */
-                               case SQLT_BLOB:  /* binary LOB */
-                               case SQLT_CLOB:  /* character LOB */
-                               case SQLT_BFILE: /* binary file LOB */
-                                       define_type = outcol->data_type;
-                                       outcol->is_descr = 1;
-                                       outcol->storage_size4 = -1;
-                                       dynamic = OCI_DEFAULT;
-
-                                       if (outcol->data_type == SQLT_BFILE) {
-                                               dtype = OCI_DTYPE_FILE;
-                                       } else if (outcol->data_type == SQLT_RDD ) {
-                                               dtype = OCI_DTYPE_ROWID;
-                                       } else {
-                                               dtype = OCI_DTYPE_LOB;
-                                       }
-                                       
-                                       descr = oci_new_desc(dtype,statement->conn);
-                                       if (!descr) {
-                                               /* need better error checking XXX */
-                                       }
-                                       outcol->descid = descr->id;
-                                       buf =  &(descr->ocidescr);
-                                       break;
-
-                               case SQLT_LNG:
-                               case SQLT_LBI:
-                                       if (outcol->data_type == SQLT_LBI) {
-                                               define_type = SQLT_BIN;
-                                       } else {
-                                               define_type = SQLT_CHR;
-                                       }
-                                       outcol->storage_size4 = OCI_MAX_DATA_SIZE;
-                                       outcol->piecewise = 1;
-                                       dynamic = OCI_DYNAMIC_FETCH;
-                                       break;
-
-                               case SQLT_BIN:
-                               default:
-                                       define_type = SQLT_CHR;
-                                       if ((outcol->data_type == SQLT_DAT) || (outcol->data_type == SQLT_NUM)
-#ifdef SQLT_TIMESTAMP
-                                               || (outcol->data_type == SQLT_TIMESTAMP)
-#endif
-#ifdef SQLT_TIMESTAMP_TZ
-                                               || (outcol->data_type == SQLT_TIMESTAMP_TZ)
+               OCI_G(errcode) = PHP_OCI_CALL(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);
+                       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+ */
+                               OCI_G(errcode) = PHP_OCI_CALL(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 */
+                               OCI_G(errcode) = PHP_OCI_CALL(OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_RDBMS, (ub4) OCI_DEFAULT));
 #endif
-                                               ) {
-                                               outcol->storage_size4 = 512; /* XXX this should fit "most" NLS date-formats and Numbers */
-                                       } else {
-                                               outcol->storage_size4++; /* add one for string terminator */
-                                       }
-                                       if (outcol->data_type == SQLT_BIN) {
-                                               outcol->storage_size4 *= 3;
-                                       }
-                                       dynamic = OCI_DEFAULT;
-                                       buf = outcol->data = (text *) emalloc(outcol->storage_size4);
-                                       break;
-                       }
+                               break;
+                       case OCI_SYSDBA:
+                       case OCI_SYSOPER:
+                       default:
+                               OCI_G(errcode) = PHP_OCI_CALL(OCISessionBegin, (connection->svc, OCI_G(err), connection->session, (ub4) OCI_CRED_EXT, (ub4) session_mode));
+                               break;
+               }
 
-                       if (dynamic == OCI_DYNAMIC_FETCH) {
-                               CALL_OCI_RETURN(error,
-                                       OCIDefineByPos(
-                                               statement->pStmt,                           /* IN/OUT handle to the requested SQL query */
-                                               (OCIDefine **)&outcol->pDefine,             /* IN/OUT pointer to a pointer to a define handle */
-                                               statement->pError,                          /* IN/OUT An error handle  */
-                                               counter,                                    /* IN     position in the select list */
-                                               (dvoid *)NULL,                              /* IN/OUT pointer to a buffer */
-                                               outcol->storage_size4,                      /* IN     The size of each valuep buffer in bytes */
-                                               define_type,                                /* IN     The data type */
-                                               (dvoid *)&outcol->indicator,                /* IN     pointer to an indicator variable or arr */
-                                               (ub2 *)NULL,                                /* IN/OUT Pointer to array of length of data fetched */
-                                               (ub2 *)NULL,                                /* OUT    Pointer to array of column-level return codes */
-                                               OCI_DYNAMIC_FETCH                               /* IN     mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
-                                       )
-                               );
-
-                               statement->error = oci_error(statement->pError, "OCIDefineByPos", error);
-                       } else {
-                               CALL_OCI_RETURN(error,
-                                       OCIDefineByPos(
-                                               statement->pStmt,                           /* IN/OUT handle to the requested SQL query */ 
-                                               (OCIDefine **)&outcol->pDefine,             /* IN/OUT pointer to a pointer to a define handle */
-                                               statement->pError,                          /* IN/OUT An error handle  */
-                                               counter,                                    /* IN     position in the select list */
-                                               (dvoid *)buf,                               /* IN/OUT pointer to a buffer */
-                                               outcol->storage_size4,                      /* IN     The size of each valuep buffer in bytes */
-                                               define_type,                                /* IN     The data type */
-                                               (dvoid *)&outcol->indicator,                /* IN     pointer to an indicator variable or arr */
-                                               (ub2 *)&outcol->retlen,                     /* IN/OUT Pointer to array of length of data fetched */
-                                               (ub2 *)&outcol->retcode,                    /* OUT    Pointer to array of column-level return codes */
-                                               OCI_DEFAULT                                     /* IN     mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
-                                       )
-                               );
-
-                               statement->error = oci_error(statement->pError, "OCIDefineByPos", error);
-                       }
-                       if (statement->error) {
-                               oci_handle_error(statement->conn, statement->error);
-                               return 0; /* XXX we loose memory!!! */
+               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;
                        }
-               }
+               } /* }}} */
        }
 
-       return 1;
-}
-/* }}} */
+#if HAVE_OCI_STMT_PREPARE2
+       if (connection->is_persistent) {
+               ub4 statement_cache_size = (OCI_G(statement_cache_size) > 0) ? OCI_G(statement_cache_size) : 0;
 
-/* {{{ oci_fetch()
-*/
-static int _oci_column_pre_fetch(void *data TSRMLS_DC)
-{
-       oci_out_column *col = (oci_out_column *) data;
-       
-       if (col->piecewise) {
-               col->retlen4 = 0; 
+               OCI_G(errcode) = PHP_OCI_CALL(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);
+                       php_oci_connection_close(connection TSRMLS_CC);
+                       return NULL;
+               }       
        }
+#endif
        
-       return 0;
-}
-
-static int oci_fetch(oci_statement *statement, ub4 nrows, char *func TSRMLS_DC)
-{
-       int i;
-       oci_out_column *column;
-
-       if (statement->columns) {
-               zend_hash_apply(statement->columns, (apply_func_t) _oci_column_pre_fetch TSRMLS_CC);
-       }
-
-
-       CALL_OCI_RETURN(statement->error,
-               OCIStmtFetch(
-                       statement->pStmt, 
-                       statement->pError, 
-                       nrows, 
-                       OCI_FETCH_NEXT, 
-                       OCI_DEFAULT
-               )
-       );
-
-       if ((statement->error == OCI_NO_DATA) || (nrows == 0)) {
-               if (statement->last_query == 0) {
-                       /* reset define-list for refcursors */
-                       if (statement->columns) {
-                               zend_hash_destroy(statement->columns);
-                               efree(statement->columns);
-                               statement->columns = 0;
-                               statement->ncolumns = 0;
-                       }
-                       statement->executed = 0;
-               }
-
-               statement->error = 0; /* OCI_NO_DATA is NO error for us!!! */
-               statement->has_data = 0;
-
-               return 0;
-       }
+       /* mark it as open */
+       connection->is_open = 1;
 
-       while (statement->error == OCI_NEED_DATA) {
-               for (i = 0; i < statement->ncolumns; i++) {
-                       column = oci_get_col(statement, i + 1, 0);
-                       if (column->piecewise)  {
-                               if (!column->data) {
-                                       column->data = (text *) emalloc(OCI_PIECE_SIZE);
-                               } else {
-                                       column->data = erealloc(column->data,column->retlen4 + OCI_PIECE_SIZE);
-                               }
+       /* register resource and return it */
 
-                               column->cb_retlen = OCI_PIECE_SIZE;
-
-                               CALL_OCI(
-                                       OCIStmtSetPieceInfo(
-                                               (void *) column->pDefine, 
-                                               OCI_HTYPE_DEFINE, 
-                                               statement->pError, 
-                                               ((char*)column->data) + column->retlen4, 
-                                               &(column->cb_retlen), 
-                                               OCI_NEXT_PIECE, 
-                                               &column->indicator, 
-                                               &column->retcode
-                                       )
-                               );
-                       }
-               }
+       new_le.ptr = connection;
 
-               CALL_OCI_RETURN(statement->error,
-                       OCIStmtFetch(
-                               statement->pStmt, 
-                               statement->pError, 
-                               nrows, 
-                               OCI_FETCH_NEXT, 
-                               OCI_DEFAULT
-                       )
-               );
-
-               for (i = 0; i < statement->ncolumns; i++) {
-                       column = oci_get_col(statement, i + 1, 0);
-                       if (column->piecewise)  {
-                               column->retlen4 += column->cb_retlen;
-                       }
-               }
+       /* add to the appropriate hash */
+       if (connection->is_persistent) {
+               new_le.type = le_pconnection;
+               connection->used_this_request = 1;
+               connection->rsrc_id = zend_list_insert(connection, le_pconnection);
+               zend_hash_update(&EG(persistent_list), connection->hash_key, strlen(connection->hash_key)+1, (void *)&new_le, sizeof(list_entry), NULL);
+               OCI_G(num_persistent)++;
        }
-
-       if (statement->error == OCI_SUCCESS_WITH_INFO || statement->error == OCI_SUCCESS) {
-               statement->has_data = 1;
-
-               /* do the stuff needed for OCIDefineByName */
-               for (i = 0; i < statement->ncolumns; i++) {
-                       column = oci_get_col(statement, i + 1, 0);
-                       if (column == NULL) {
-                               continue;
-                       }
-                       
-                       if (!column->define) {
-                               continue;
-                       }
-                       
-                       zval_dtor(column->define->zval);
-                       _oci_make_zval(column->define->zval,statement,column,"OCIFetch",0 TSRMLS_CC);
-               }
-
-               return 1;
-       }
-
-       oci_error(statement->pError, func, statement->error);
-       oci_handle_error(statement->conn, statement->error);
-
-       statement->has_data = 0;
-
-       return 0;
-}
-/* }}} */
-
-/* {{{ oci_lobgetlen()
-*/
-static int oci_lobgetlen(oci_connection *connection, oci_descriptor *mydescr, ub4 *loblen)
-{
-       TSRMLS_FETCH();
-
-       *loblen = 0;
-       
-       /* do we need to ask oracle about LOB's length, if we do already know it? I think no. */
-       if (mydescr->lob_size >= 0) {
-               *loblen = mydescr->lob_size;
-       } else {
-               if (mydescr->type == OCI_DTYPE_FILE) {
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobFileOpen(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       mydescr->ocidescr,
-                                       OCI_FILE_READONLY
-                               )
-                       );
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobFileOpen",connection->error);
-                               oci_handle_error(connection, connection->error);
-                               return -1;
-                       }
-               }
-               
-               CALL_OCI_RETURN(connection->error, 
-                       OCILobGetLength(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       mydescr->ocidescr, 
-                                       loblen
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobGetLength",connection->error);
-                       oci_handle_error(connection, connection->error);
-                       return -1;
-               }
-               mydescr->lob_size = *loblen;
-
-               if (mydescr->type == OCI_DTYPE_FILE) {
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobFileClose(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       mydescr->ocidescr
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobFileClose", connection->error);
-                               oci_handle_error(connection, connection->error);
-                               return -1;
-                       }
-               }
-       }
-       
-       oci_debug("oci_lobgetlen: len=%d",*loblen);
-
-       return 0;
-}
-/* }}} */
-
-/* {{{ oci_loadlob()
-*/
-#define LOBREADSIZE 1048576l /* 1MB */
-static int oci_loadlob(oci_connection *connection, oci_descriptor *mydescr, char **buffer, ub4 *loblen)
-{
-       ub4 siz = 0;
-       ub4 readlen = 0;
-       char *buf;
-       TSRMLS_FETCH();
-
-       *loblen = 0;
-       
-       if (mydescr->type == OCI_DTYPE_FILE) {
-               CALL_OCI_RETURN(connection->error,
-                       OCILobFileOpen(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               mydescr->ocidescr,
-                               OCI_FILE_READONLY
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobFileOpen",connection->error);
-                       oci_handle_error(connection, connection->error);
-                       return -1;
-               }
-       }
-       
-       CALL_OCI_RETURN(connection->error,
-               OCILobGetLength(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       mydescr->ocidescr, 
-                       &readlen
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobGetLength",connection->error);
-               oci_handle_error(connection, connection->error);
-               return -1;
-       }
-
-       buf = emalloc(readlen + 1);
-
-       while (readlen > 0) { /* thies loop should not be entered on readlen == 0 */
-               CALL_OCI_RETURN(connection->error,
-                       OCILobRead(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               mydescr->ocidescr, 
-                               &readlen,                                                               /* IN/OUT bytes toread/read */ 
-                               siz + 1,                                                                /* offset (starts with 1) */ 
-                               (dvoid *) ((char *) buf + siz), 
-                               readlen,                                                                /* size of buffer */ 
-                               (dvoid *)0, 
-                               (OCICallbackLobRead) 0,                                 /* callback... */ 
-                               (ub2) connection->session->charsetId,   /* The character set ID of the buffer data. */ 
-                               (ub1) SQLCS_IMPLICIT                                    /* The character set form of the buffer data. */
-                       )
-               );
-
-               siz += readlen;
-               readlen = LOBREADSIZE;
-
-               if (connection->error == OCI_NEED_DATA) {
-                       buf = erealloc(buf,siz + LOBREADSIZE + 1);      
-                       continue;
-               } else {
-                       break;
-               }
-       }
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobRead", connection->error);
-               oci_handle_error(connection, connection->error);
-               efree(buf);
-               return -1;
-       }
-
-       if (mydescr->type == OCI_DTYPE_FILE) {
-               CALL_OCI_RETURN(connection->error,
-                       OCILobFileClose(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               mydescr->ocidescr
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobFileClose", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       efree(buf);
-                       return -1;
-               }
-       }
-
-       buf = erealloc(buf,siz+1);
-       buf[ siz ] = 0;
-
-       *buffer = buf;
-       *loblen = siz;
-
-       oci_debug("oci_loadlob: size=%d",siz);
-
-       return 0;
-}
-/* }}} */
-
-/* {{{ oci_readlob()
-*/
-static int oci_readlob(oci_connection *connection, oci_descriptor *mydescr, char **buffer, ub4 *len)
-{
-       ub4 siz = 0;
-       ub4 readlen = 0;
-       ub4 loblen = 0;
-       ub4 bytes = 0;
-       char *buf;
-       TSRMLS_FETCH();
-
-       /* we're not going to read LOB, if length is not known */
-       if (!len || (int)*len <= 0) {
-               return -1;
-       }
-
-       if (mydescr->type == OCI_DTYPE_FILE) {
-               CALL_OCI_RETURN(connection->error,
-                       OCILobFileOpen(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               mydescr->ocidescr,
-                               OCI_FILE_READONLY
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobFileOpen",connection->error);
-                       oci_handle_error(connection, connection->error);
-                       return -1;
-               }
-       }
-       
-       if (oci_lobgetlen(connection, mydescr, &loblen) != 0) {
-               *len = 0;
-               return -1;
-       }
-       
-       /* check if we're in LOB's borders */
-       if ((mydescr->lob_current_position + *len) > loblen) {
-               *len = loblen - mydescr->lob_current_position;
-       }
-
-       if ((int)*len > 0) {
-               buf = emalloc(*len + 1);
-
-               /* set offset to current LOB's position */
-               siz = mydescr->lob_current_position;
-
-               /* check if len is smaller, if not - using LOBREADSIZE' sized buffer */
-               if (*len > LOBREADSIZE) {
-                       readlen = LOBREADSIZE;
-               } else {
-                       readlen = *len;
-               }
-       } else {
-               *len = 0;
-               return -1;
-       }
-
-       while (readlen > 0 && bytes < *len && siz < loblen) {  /* paranoia */
-               CALL_OCI_RETURN(connection->error,
-                       OCILobRead(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               mydescr->ocidescr, 
-                               &readlen,                                                               /* IN/OUT bytes toread/read */ 
-                               siz + 1,                                                                /* offset (starts with 1) */ 
-                               (dvoid *) ((char *) buf + bytes),       
-                               readlen,                                                                /* size of buffer */ 
-                               (dvoid *)0, 
-                               (OCICallbackLobRead) 0,                                 /* callback... */ 
-                               (ub2) connection->session->charsetId,   /* The character set ID of the buffer data. */ 
-                               (ub1) SQLCS_IMPLICIT                                    /* The character set form of the buffer data. */
-                       )
-               );
-
-               siz += readlen;
-               bytes += readlen;
-
-               if ((*len - bytes) > LOBREADSIZE) {
-                       readlen = LOBREADSIZE;
-               } else {
-                       readlen = *len - bytes;
-               }
-
-               if (connection->error == OCI_NEED_DATA) {
-                       buf = erealloc(buf,bytes + LOBREADSIZE + 1);    
-                       continue;
-               } else {
-                       break;
-               }
-       }
-
-       /* moving current position */
-       mydescr->lob_current_position = siz;
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobRead", connection->error);
-               oci_handle_error(connection, connection->error);
-               efree(buf);
-               return -1;
-       }
-
-       if (mydescr->type == OCI_DTYPE_FILE) {
-               CALL_OCI_RETURN(connection->error,
-                       OCILobFileClose(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               mydescr->ocidescr
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobFileClose", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       efree(buf);
-                       return -1;
-               }
-       }
-
-       buf = erealloc(buf,bytes+1);
-       buf[ bytes ] = 0;
-
-       *buffer = buf;
-       *len = bytes;
-
-       oci_debug("oci_readlob: size=%d",bytes);
-
-       return 0;
-}
-/* }}} */
-
-/* {{{ oci_failover_callback()
-*/
-#if 0 /* not needed yet ! */
-static sb4 oci_failover_callback(dvoid *svchp, dvoid *envhp, dvoid *fo_ctx, ub4 fo_type, ub4 fo_event)
-{
-       /* 
-          this stuff is from an oci sample - it will get cleaned up as soon as i understand it!!! (thies@thieso.net 990420) 
-          right now i cant get oracle to even call it;-(((((((((((
-       */
-
-       switch (fo_event) {
-               case OCI_FO_BEGIN: {
-                       printf(" Failing Over ... Please stand by \n");
-                       printf(" Failover type was found to be %s \n",
-                                       ((fo_type==OCI_FO_NONE) ? "NONE"
-                                       :(fo_type==OCI_FO_SESSION) ? "SESSION"
-                                       :(fo_type==OCI_FO_SELECT) ? "SELECT"
-                                       : "UNKNOWN!"));
-                       printf(" Failover Context is :%s\n",
-                                       (fo_ctx?(char *)fo_ctx:"NULL POINTER!"));
-                       break;
-               }
-
-               case OCI_FO_ABORT: {
-                       printf(" Failover aborted. Failover will not take place.\n");
-                       break;
-               }
-
-               case OCI_FO_END: {
-                       printf(" Failover ended ...resuming services\n");
-                       break;
-               }
-
-               case OCI_FO_REAUTH: {
-                       printf(" Failed over user. Resuming services\n");
-                               
-                       /* Application can check the OCI_ATTR_SESSION attribute of
-                          the service handle to find out the user being
-                          re-authenticated.
-                                  
-                          After this, the application can replay any ALTER SESSION
-                          commands associated with this session.  These must have
-                          been saved by the application in the fo_ctx
-                       */
-                       break;
-               }
-
-               case OCI_FO_ERROR: {
-                       printf(" Failover error gotten. Sleeping...\n");
-                       php_sleep(3);
-                       /* cannot find this blody define !!! return OCI_FO_RETRY; */
-                       break;
-               }
-                       
-               default: {
-                       printf("Bad Failover Event: %ld.\n",  fo_event);
-                       break;
-               }
-       }
-
-       return 0;  
-}
-#endif
-/* }}} */
-
-/* {{{ oci_bind_in_callback()
-*/
-static sb4 oci_bind_in_callback(
-                                       dvoid *ictxp,     /* context pointer */
-                                       OCIBind *bindp,   /* bind handle */
-                                       ub4 iter,         /* 0-based execute iteration value */
-                                       ub4 index,        /* index of current array for PL/SQL or row index for SQL */
-                                       dvoid **bufpp,    /* pointer to data */
-                                       ub4 *alenp,       /* size after value/piece has been read */
-                                       ub1 *piecep,      /* which piece */
-                                       dvoid **indpp)    /* indicator value */
-{
-       oci_bind *phpbind;
-       zval *val;
-       TSRMLS_FETCH();
-
-       if (!(phpbind=(oci_bind *)ictxp) || !(val = phpbind->zval)) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "!phpbind || !phpbind->val");
-               return OCI_ERROR;
-       }
-
-       if (ZVAL_IS_NULL(val)) {
-               /* we're going to insert a NULL column */
-               phpbind->indicator = -1;
-               *bufpp = 0;
-               *alenp = -1;
-               *indpp = (dvoid *)&phpbind->indicator;
-       } else  if ((phpbind->descr == 0) && (phpbind->pStmt == 0)) {
-               /* "normal string bind */
-               convert_to_string(val); 
-
-               *bufpp = Z_STRVAL_P(val);
-               *alenp = Z_STRLEN_P(val);
-               *indpp = (dvoid *)&phpbind->indicator;
-       } else if (phpbind->pStmt != 0) {
-               /* RSET */
-               *bufpp = phpbind->pStmt;
-               *alenp = -1;            /* seems to be allright */
-               *indpp = (dvoid *)&phpbind->indicator;
-       } else { 
-               /* descriptor bind */
-               *bufpp = phpbind->descr;
-               *alenp = -1;            /* seems to be allright */
-               *indpp = (dvoid *)&phpbind->indicator;
-       }
-
-       *piecep = OCI_ONE_PIECE; /* pass all data in one go */
-
-       return OCI_CONTINUE;
-}
-/* }}} */
-
-/* {{{ oci_bind_out_callback() */
-static sb4 oci_bind_out_callback(
-                                       dvoid *octxp,      /* context pointer */
-                                       OCIBind *bindp,    /* bind handle */
-                                       ub4 iter,          /* 0-based execute iteration value */
-                                       ub4 index,         /* index of current array for PL/SQL or row index for SQL */
-                                       dvoid **bufpp,     /* pointer to data */
-                                       ub4 **alenpp,      /* size after value/piece has been read */
-                                       ub1 *piecep,       /* which piece */
-                                       dvoid **indpp,     /* indicator value */
-                                       ub2 **rcodepp)     /* return code */
-{
-       oci_bind *phpbind;
-       zval *val;
-       sb4 retval = OCI_ERROR;
-       TSRMLS_FETCH();
-
-       if (!(phpbind=(oci_bind *)octxp) || !(val = phpbind->zval)) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "!phpbind || !phpbind->val");
-               return retval;
-       }
-
-       if ((Z_TYPE_P(val) == IS_OBJECT) || (Z_TYPE_P(val) == IS_RESOURCE)) {
-               retval = OCI_CONTINUE;
-       } else {
-               convert_to_string(val);
-               zval_dtor(val);
-               
-               Z_STRLEN_P(val) = OCI_PIECE_SIZE; /* 64K-1 is max XXX */
-               Z_STRVAL_P(val) = emalloc(Z_STRLEN_P(phpbind->zval));
-               
-               /* XXX we assume that zend-zval len has 4 bytes */
-               *alenpp = (ub4*) &Z_STRLEN_P(phpbind->zval); 
-               *bufpp = Z_STRVAL_P(phpbind->zval);
-               *piecep = OCI_ONE_PIECE;
-               *rcodepp = &phpbind->retcode;
-               *indpp = &phpbind->indicator;
-               retval = OCI_CONTINUE;
-       }
-
-       return retval;
-}
-/* }}} */
-
-/* {{{ _oci_open_session()
-*/
-#include "ext/standard/php_smart_str.h"
-static oci_session *_oci_open_session(oci_server* server,char *username,char *password,int persistent,int exclusive,char *charset)
-{
-       zend_llist *session_list;
-       oci_session *session = NULL;
-       OCISvcCtx *svchp = NULL;
-       smart_str hashed_details = {0};
-#ifdef HAVE_OCI_9_2
-       ub2 charsetid = 0;
-#endif
-       TSRMLS_FETCH();
-
-       /* 
-          check if we already have this user authenticated
-
-          we will reuse authenticated users within a request no matter if the user requested a persistent 
-          connections or not!
-          
-          but only as persistent requested connections will be kept between requests!
-       */
-
-#if defined(HAVE_OCI_9_2)
-       if (*charset) {
-               smart_str_appends_ex(&hashed_details, charset, 1);
-       } else {
-               size_t rsize;
-
-               /* Safe, charsetid is initialized to 0 */
-               CALL_OCI(
-                       OCINlsEnvironmentVariableGet(
-                               &charsetid, 
-                               2, 
-                               OCI_NLS_CHARSET_ID, 
-                               0,
-                               &rsize
-                       )
-               );
-
-               smart_str_append_unsigned_ex(&hashed_details, charsetid, 1);
-
-               charsetid = 0;
-       }
-#else
-       {
-               char *nls_lang = getenv("NLS_LANG");
-
-               /* extract charset from NLS_LANG=LANUAGE_TERRITORY.CHARSET */
-               if (nls_lang) {
-                       char *p = strchr(nls_lang, '.');
-
-                       if (p) {
-                               smart_str_appends_ex(&hashed_details, p + 1, 1);
-                       }
-               }
-       }
-#endif
-
-       smart_str_appends_ex(&hashed_details, SAFE_STRING(username), 1);
-       smart_str_appends_ex(&hashed_details, SAFE_STRING(password), 1);
-       smart_str_appends_ex(&hashed_details, SAFE_STRING(server->dbname), 1);
-       smart_str_0(&hashed_details);
-
-       if (!exclusive) {
-               mutex_lock(mx_lock);
-               if (zend_ts_hash_find(persistent_sessions, hashed_details.c, hashed_details.len+1, (void **) &session_list) != SUCCESS) {
-                       zend_llist tmp;
-                       /* first session, set up a session list */
-                       zend_llist_init(&tmp, sizeof(oci_session), (llist_dtor_func_t) _session_pcleanup, 1);
-                       zend_ts_hash_update(persistent_sessions, hashed_details.c, hashed_details.len+1, &tmp, sizeof(zend_llist), (void **) &session_list);
-               } else {
-
-                       /* session list found, search for an idle session or an already opened session by the current thread */
-                       session = zend_llist_get_first(session_list);
-                       while ((session != NULL) && session->thread && (session->thread != thread_id())) {
-                               session = zend_llist_get_next(session_list);
-                       }
-
-                       if (session != NULL) {
-                               /* mark session as busy */
-                               session->thread = thread_id();
-                       }
-
-               }
-
-               if (session) {
-                       if (session->is_open) {
-                               if (persistent) {
-                                       session->persistent = 1;
-                               }
-                               smart_str_free_ex(&hashed_details, 1);
-                               mutex_unlock(mx_lock);
-                               return session;
-                       } else {
-                               _oci_close_session(session);
-                               /* breakthru to open */
-                       }
-               }
-               mutex_unlock(mx_lock);
-       }
-
-       session = ecalloc(1,sizeof(oci_session));
-
-       if (!session) {
-               goto CLEANUP;
-       }
-
-       session->persistent = persistent;
-       session->server = server;
-       session->exclusive = exclusive;
-       session->sessions_list = session_list;
-       session->thread = thread_id();
-
-#ifdef HAVE_OCI_9_2
-
-       /* following chunk is Oracle 9i+ ONLY */
-       if (*charset) {
-               /*
-                  get ub2 charset id based on charset
-                  this is pretty secure, since if we don't have a valid character set name,
-                  0 comes back and we can still use the 0 in all further statements -> OCI uses NLS_LANG
-                  setting in that case
-               */
-               CALL_OCI_RETURN(charsetid,
-                       OCINlsCharSetNameToId(
-                               OCI(pEnv),
-                               charset
-                       )
-               );
-               
-               oci_debug("oci_do_connect: using charset id=%d",charsetid);
-       }
-
-       session->charsetId = charsetid;
-       
-       /* create an environment using the character set id, Oracle 9i+ ONLY */
-       CALL_OCI(
-               OCIEnvNlsCreate(
-                       &session->pEnv,
-                       PHP_OCI_INIT_MODE, 
-                       0, 
-                       NULL,
-                       NULL,
-                       NULL,
-                       0,
-                       NULL,
-                       charsetid,
-                       charsetid
-               )
-       );
-
-#else
-
-       /* fallback solution (simply use global env and charset, same behaviour as always been) */
-       session->pEnv = OCI(pEnv);
-       session->charsetId = 0;
-
-#endif  /* HAVE_OCI_9_2 */
-
-       /* allocate temporary Service Context */
-       CALL_OCI_RETURN(OCI(error),
-               OCIHandleAlloc(
-                       session->pEnv, 
-                       (dvoid **)&svchp, 
-                       OCI_HTYPE_SVCCTX, 
-                       0, 
-                       NULL
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "_oci_open_session: OCIHandleAlloc OCI_HTYPE_SVCCTX", OCI(error));
-               goto CLEANUP;
-       }
-
-       /* allocate private session-handle */
-       CALL_OCI_RETURN(OCI(error),
-               OCIHandleAlloc(
-                       session->pEnv, 
-                       (dvoid **)&session->pSession, 
-                       OCI_HTYPE_SESSION, 
-                       0, 
-                       NULL
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "_oci_open_session: OCIHandleAlloc OCI_HTYPE_SESSION", OCI(error));
-               goto CLEANUP;
-       }
-
-       /* Set the server handle in service handle */ 
-       CALL_OCI_RETURN(OCI(error),
-               OCIAttrSet(
-                       svchp, 
-                       OCI_HTYPE_SVCCTX, 
-                       server->pServer, 
-                       0,
-                       OCI_ATTR_SERVER,
-                       OCI(pError)
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "_oci_open_session: OCIAttrSet OCI_ATTR_SERVER", OCI(error));
-               goto CLEANUP;
-       }
-
-       /* set the username in user handle */
-       CALL_OCI_RETURN(OCI(error),
-               OCIAttrSet(
-                       (dvoid *) session->pSession, 
-                       (ub4) OCI_HTYPE_SESSION, 
-                       (dvoid *) username, 
-                       (ub4) strlen(username), 
-                       (ub4) OCI_ATTR_USERNAME, 
-                       OCI(pError)
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "OCIAttrSet OCI_ATTR_USERNAME", OCI(error));
-               goto CLEANUP;
-       }
-
-       /* set the password in user handle */
-       CALL_OCI_RETURN(OCI(error),
-               OCIAttrSet(
-                       (dvoid *) session->pSession, 
-                       (ub4) OCI_HTYPE_SESSION, 
-                       (dvoid *) password, 
-                       (ub4) strlen(password), 
-                       (ub4) OCI_ATTR_PASSWORD, 
-                       OCI(pError)
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "OCIAttrSet OCI_ATTR_PASSWORD", OCI(error));
-               goto CLEANUP;
-       }
-
-       CALL_OCI_RETURN(OCI(error),
-               OCISessionBegin(
-                       svchp, 
-                       OCI(pError), 
-                       session->pSession, 
-                       (ub4) OCI_CRED_RDBMS, 
-                       (ub4) OCI_DEFAULT
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "OCISessionBegin", OCI(error));
-               /* OCISessionBegin returns OCI_SUCCESS_WITH_INFO when
-                * user's password has expired, but is still usable.
-                * */
-               if (OCI(error) != OCI_SUCCESS_WITH_INFO) {
-                       goto CLEANUP;
-               }
-       }
-
-       /* Free Temporary Service Context */
-       CALL_OCI(
-               OCIHandleFree(
-                       (dvoid *) svchp, 
-                       (ub4) OCI_HTYPE_SVCCTX
-               )
-       );
-
-       session->num = zend_list_insert(session, le_session);
-       session->is_open = 1;
-
-       mutex_lock(mx_lock);
-               num_links++;
-               if (!exclusive) {
-                       zend_llist_add_element(session_list, session);
-                       efree(session);
-                       session = (oci_session*) session_list->tail->data;
-                       num_persistent++;
-               }
-       mutex_unlock(mx_lock);
-
-       oci_debug("_oci_open_session new sess=%d user=%s",session->num,username);
-
-       return session;
-
-CLEANUP:
-       oci_debug("_oci_open_session: FAILURE -> CLEANUP called");
-
-       _oci_close_session(session);
-
-       return 0;
-}
-/* }}} */
-
-/* {{{ _oci_close_session()
-*/
-static int _session_compare(void *a, void *b)
-{
-       oci_session *sess1 = (oci_session*) a;
-       oci_session *sess2 = (oci_session*) b;
-       
-       return sess1->num == sess2->num;
-}
-
-static void _oci_close_session(oci_session *session)
-{
-       OCISvcCtx *svchp;
-       TSRMLS_FETCH();
-
-       if (!session) {
-               return;
-       }
-
-       oci_debug("START _oci_close_session: logging-off sess=%d",session->num);
-
-       if (session->is_open) {
-               /* Temporary Service Context */
-               CALL_OCI_RETURN(OCI(error),
-                       OCIHandleAlloc(
-                               session->pEnv, 
-                               (dvoid **) &svchp, 
-                               (ub4) OCI_HTYPE_SVCCTX, 
-                               (size_t) 0, 
-                               (dvoid **) 0
-                       )
-               );
-
-               if (OCI(error) != OCI_SUCCESS) {
-                       oci_error(OCI(pError), "_oci_close_session OCIHandleAlloc OCI_HTYPE_SVCCTX", OCI(error));
-               }
-               
-               /* Set the server handle in service handle */ 
-               CALL_OCI_RETURN(OCI(error),
-                       OCIAttrSet(
-                               svchp, 
-                               OCI_HTYPE_SVCCTX, 
-                               session->server->pServer, 
-                               0, 
-                               OCI_ATTR_SERVER, 
-                               OCI(pError)
-                       )
-               );
-
-               if (OCI(error) != OCI_SUCCESS) {
-                       oci_error(OCI(pError), "_oci_close_session: OCIAttrSet OCI_ATTR_SERVER", OCI(error));
-               }
-               
-               /* Set the Authentication handle in the service handle */
-               CALL_OCI_RETURN(OCI(error),
-                       OCIAttrSet(
-                               svchp,  
-                               OCI_HTYPE_SVCCTX, 
-                               session->pSession, 
-                               0, 
-                               OCI_ATTR_SESSION, 
-                               OCI(pError)
-                       )
-               );
-
-               if (OCI(error) != OCI_SUCCESS) {
-                       oci_error(OCI(pError), "_oci_close_session: OCIAttrSet OCI_ATTR_SESSION", OCI(error));
-               }
-       
-               CALL_OCI_RETURN(OCI(error),
-                       OCISessionEnd(
-                               svchp, 
-                               OCI(pError), 
-                               session->pSession, 
-                               (ub4) 0
-                       )
-               );
-
-               if (OCI(error) != OCI_SUCCESS) {
-                       oci_error(OCI(pError), "_oci_close_session: OCISessionEnd", OCI(error));
-               }
-
-               CALL_OCI(
-                       OCIHandleFree(
-                               (dvoid *) svchp, 
-                               (ub4) OCI_HTYPE_SVCCTX
-                       )
-               );
-
-       } else {
-               oci_debug("_oci_close_session: logging-off DEAD session");
-       }
-
-       if (session->pSession) {
-               CALL_OCI(
-                       OCIHandleFree(
-                               (dvoid *) session->pSession, 
-                               (ub4) OCI_HTYPE_SESSION
-                       )
-               );
-       }
-
-       mutex_lock(mx_lock);
-               num_links--;
-               if (!OCI(shutdown) && session->persistent) {
-                       zend_llist_del_element(session->sessions_list, session, _session_compare);
-                       num_persistent--;
-               }
-       mutex_unlock(mx_lock);
-
-#ifdef HAVE_OCI_9_2
-       /* free environment handle (and fix bug #29652 with growing .msb FD number under weirdie Solarises) */
-       CALL_OCI(
-               OCIHandleFree(
-                               (dvoid *) session->pEnv, 
-                               OCI_HTYPE_ENV
-               )
-       );
-#endif
-       if (session->exclusive) {
-               efree(session);
-       }
-}
-/* }}} */
-
-/* {{{ _oci_open_server()
-*/
-static oci_server *_oci_open_server(char *dbname,int persistent)
-{ 
-       oci_server *server, *pserver = NULL;
-       TSRMLS_FETCH();
-
-       /* 
-          check if we already have this server open 
-          
-          we will reuse servers within a request no matter if the user requested persistent 
-          connections or not!
-          
-          but only as pesistent requested connections will be kept between requests!
-       */
-
-       /* TODO either keep servers global or don't reuse them at all */
-       zend_ts_hash_find(persistent_servers, dbname, strlen(dbname)+1, (void **) &pserver);
-
-       if (pserver) {
-               /* XXX ini-flag */
-               /*
-               if (!oci_ping(pserver)) {
-                       pserver->is_open = 0;
-               }
-               */
-               if (pserver->is_open) {
-                       /* if our new users uses this connection persistent, we're keeping it! */
-                       if (persistent) {
-                               pserver->persistent = persistent;
-                       }
-
-                       return pserver;
-               } else { /* server "died" in the meantime - try to reconnect! */
-                       _oci_close_server(pserver);
-                       /* breakthru to open */
-               }
-       }
-       
-       server = ecalloc(1,sizeof(oci_server));
-
-       server->persistent = persistent;
-       server->dbname = strdup(SAFE_STRING(dbname));
-
-       CALL_OCI(
-               OCIHandleAlloc(
-                       OCI(pEnv), 
-                       (dvoid **)&server->pServer, 
-                       OCI_HTYPE_SERVER, 
-                       0, 
-                       NULL
-               )
-       );
-
-       CALL_OCI_RETURN(OCI(error),
-               OCIServerAttach(
-                       server->pServer, 
-                       OCI(pError), 
-                       (text*)server->dbname, 
-                       strlen(server->dbname), 
-                       (ub4) OCI_DEFAULT
-               )
-       );
-
-       if (OCI(error)) {
-               oci_error(OCI(pError), "_oci_open_server", OCI(error));
-               goto CLEANUP;
-       }
-       
-       zend_ts_hash_update(persistent_servers,
-                                        server->dbname,
-                                        strlen(server->dbname)+1, 
-                                        (void *)server,
-                                        sizeof(oci_server),
-                                        (void**)&pserver);
-
-       pserver->num  = zend_list_insert(pserver,le_server);
-       pserver->is_open = 1;
-
-       oci_debug("_oci_open_server new conn=%d dname=%s",server->num,server->dbname);
-
-       efree(server);
-
-       return pserver;
-
-CLEANUP:
-       oci_debug("_oci_open_server: FAILURE -> CLEANUP called");
-
-       _oci_close_server(server);
-               
-       return 0;
-}
-
-#if 0 
-       server->failover.fo_ctx = (dvoid *) server;
-       server->failover.callback_function = oci_failover_callback;
-
-       error = OCIAttrSet((dvoid *)server->pServer,
-                                               (ub4) OCI_HTYPE_SERVER,
-                                               (dvoid *) &server->failover, 
-                                               (ub4) 0,
-                                               (ub4) OCI_ATTR_FOCBK,
-                                               OCI(pError));
-
-       if (error) {
-               oci_error(OCI(pError), "_oci_open_server OCIAttrSet OCI_ATTR_FOCBK", error);
-               goto CLEANUP;
-       }
-#endif
-/* }}} */
-
-/* {{{ _oci_close_server()
-*/
-static int _oci_session_cleanup(void *data TSRMLS_DC)
-{
-       zend_rsrc_list_entry *le = (zend_rsrc_list_entry *) data;
-
-       if (le->type == le_session) {
-               oci_server *server = ((oci_session*) le->ptr)->server;
-               if (server && server->is_open == 2) 
-                       return 1;
-       }
-       return 0;
-}
-
-static void _oci_close_server(oci_server *server)
-{
-       char *dbname;
-       int oldopen;
-       TSRMLS_FETCH();
-
-       oldopen = server->is_open;
-       server->is_open = 2;
-       if (!OCI(shutdown)) {
-               zend_hash_apply(&EG(regular_list), (apply_func_t) _oci_session_cleanup TSRMLS_CC);
-       }
-       server->is_open = oldopen;
-
-       oci_debug("START _oci_close_server: detaching conn=%d dbname=%s",server->num,server->dbname);
-
-       /* XXX close server here */
-
-       if (server->is_open) {
-               if (server->pServer && OCI(pError)) {
-                       CALL_OCI_RETURN(OCI(error), 
-                               OCIServerDetach(
-                                       server->pServer, 
-                                       OCI(pError), 
-                                       OCI_DEFAULT
-                               )
-                       );
-
-                       if (OCI(error)) {
-                               oci_error(OCI(pError), "oci_close_server OCIServerDetach", OCI(error));
-                       }
-               }
-       } else {
-               oci_debug("_oci_close_server: closing DEAD server");
-       }
-
-       if (server->pServer) {
-               CALL_OCI(
-                       OCIHandleFree(
-                               (dvoid *) server->pServer, 
-                               (ub4) OCI_HTYPE_SERVER
-                       )
-               );
-       }
-
-       dbname = server->dbname;
-
-       if (!OCI(shutdown)) {
-               zend_ts_hash_del(persistent_servers, dbname, strlen(dbname)+1);
-       }
-
-       free(dbname);
-}
-/* }}} */
-
-/* {{{ oci_do_connect()
-   Connect to an Oracle database and log on. returns a new session. */
-static void oci_do_connect(INTERNAL_FUNCTION_PARAMETERS,int persistent,int exclusive)
-{
-       char *username, *password, *dbname, *charset;
-       zval **userParam, **passParam, **dbParam, **charParam;
-       oci_server *server = 0;
-       oci_session *session = 0;
-       oci_connection *connection = 0;
-       
-       /* if a forth parameter is handed over, it is the charset identifier (but is only used in Oracle 9i+) */
-       if (zend_get_parameters_ex(4, &userParam, &passParam, &dbParam, &charParam) == SUCCESS) {
-               convert_to_string_ex(userParam);
-               convert_to_string_ex(passParam);
-               convert_to_string_ex(dbParam);
-               convert_to_string_ex(charParam);
-
-               username = Z_STRVAL_PP(userParam);
-               password = Z_STRVAL_PP(passParam);
-               dbname = Z_STRVAL_PP(dbParam);
-               charset = Z_STRVAL_PP(charParam);
-               oci_debug("oci_do_connect: using charset=%s",charset);
-       } else if (zend_get_parameters_ex(3, &userParam, &passParam, &dbParam) == SUCCESS) {
-               convert_to_string_ex(userParam);
-               convert_to_string_ex(passParam);
-               convert_to_string_ex(dbParam);
-
-               username = Z_STRVAL_PP(userParam);
-               password = Z_STRVAL_PP(passParam);
-               dbname = Z_STRVAL_PP(dbParam);
-               charset = "";
-       } else if (zend_get_parameters_ex(2, &userParam, &passParam) == SUCCESS) {
-               convert_to_string_ex(userParam);
-               convert_to_string_ex(passParam);
-
-               username = Z_STRVAL_PP(userParam);
-               password = Z_STRVAL_PP(passParam);
-               dbname = "";
-               charset = "";
-       } else {
-               WRONG_PARAM_COUNT;
-       }
-
-       connection = (oci_connection *) ecalloc(1,sizeof(oci_connection));
-
-       if (!connection) {
-               goto CLEANUP;
-       }
-
-       server = _oci_open_server(dbname,persistent);
-
-       if (!server) {
-               goto CLEANUP;
-       }
-
-       if (exclusive) {
-               /* exlusive session can never be persistent!*/
-               persistent = 0;
-       } else {
-               /* if our server-context is not persistent we can't */
-               persistent = (server->persistent) ? persistent : 0;
-       }
-
-       session = _oci_open_session(server,username,password,persistent,exclusive,charset);
-
-       if (!session) {
-               goto CLEANUP;
-       }
-
-       /* set our session */
-       connection->session = session;
-
-       /* allocate our private error-handle */
-       CALL_OCI_RETURN(OCI(error),
-               OCIHandleAlloc(
-                       connection->session->pEnv, 
-                       (dvoid **)&connection->pError, 
-                       OCI_HTYPE_ERROR, 
-                       0, 
-                       NULL
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "oci_do_connect: OCIHandleAlloc OCI_HTYPE_ERROR",OCI(error));
-               goto CLEANUP;
-       }
-
-       /* allocate our service-context */
-       CALL_OCI_RETURN(OCI(error),
-               OCIHandleAlloc(
-                       connection->session->pEnv, 
-                       (dvoid **)&connection->pServiceContext, 
-                       OCI_HTYPE_SVCCTX, 
-                       0, 
-                       NULL
-               )
-       );
-
-       if (OCI(error) != OCI_SUCCESS) {
-               oci_error(OCI(pError), "oci_do_connect: OCIHandleAlloc OCI_HTYPE_SVCCTX",OCI(error));
-               goto CLEANUP;
-       }
-
-       /* Set the server handle in service handle */ 
-       CALL_OCI_RETURN(connection->error,
-               OCIAttrSet(
-                       connection->pServiceContext, 
-                       OCI_HTYPE_SVCCTX, 
-                       server->pServer, 
-                       0, 
-                       OCI_ATTR_SERVER, 
-                       connection->pError
-               )
-       );
-
-       if (connection->error != OCI_SUCCESS) {
-               oci_error(connection->pError, "oci_do_connect: OCIAttrSet OCI_ATTR_SERVER", connection->error);
-               goto CLEANUP;
-       }
-
-       /* Set the Authentication handle in the service handle */
-       CALL_OCI_RETURN(connection->error,
-               OCIAttrSet(
-                       connection->pServiceContext, 
-                       OCI_HTYPE_SVCCTX, 
-                       session->pSession, 
-                       0, 
-                       OCI_ATTR_SESSION, 
-                       connection->pError
-               )
-       );
-
-       if (connection->error != OCI_SUCCESS) {
-               oci_error(connection->pError, "oci_do_connect: OCIAttrSet OCI_ATTR_SESSION", connection->error);
-               goto CLEANUP;
-       }
-
-       /*
-       OCIAttrSet((dvoid *)session->server->pServer, 
-                               OCI_HTYPE_SERVER,
-                               (dvoid *) "demo",
-                               0,
-                               OCI_ATTR_EXTERNAL_NAME,
-                               connection->pError);
-
-       OCIAttrSet((dvoid *)session->server->pServer,
-                               OCI_HTYPE_SERVER,
-                               (dvoid *) "txn demo2",
-                               0,
-                               OCI_ATTR_INTERNAL_NAME,
-                               connection->pError);
-       */
-
-       connection->id = zend_list_insert(connection, le_conn);
-
-       connection->is_open = 1;
-
-       oci_debug("oci_do_connect: id=%d",connection->id);
-
-       RETURN_RESOURCE(connection->id);
-       
-CLEANUP:
-       oci_debug("oci_do_connect: FAILURE -> CLEANUP called");
-
-       if (connection->id) {
-               zend_list_delete(connection->id);
-       } else {
-               _oci_conn_list_dtor(connection TSRMLS_CC);
-       }
-
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ oci_lob_flush()
-*/
-static int oci_lob_flush(oci_descriptor* descr, int flush_flag TSRMLS_DC)
-{
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       
-       mylob = (OCILobLocator *) descr->ocidescr;
-
-       if (!mylob) {
-               return 0;
-       }
-
-       /* do not really flush buffer, but reporting success
-        * to suppress OCI error when flushing not used buffer
-        * */
-       if (descr->buffering != 2) {
-               return 1;
-       }
-
-       connection = descr->conn;
-
-       CALL_OCI_RETURN(connection->error,
-               OCILobFlushBuffer(
-                       connection->pServiceContext,
-                       connection->pError,
-                       mylob,
-                       flush_flag
-               )
-       );
-
-       oci_debug("oci_lob_flush: flush_flag=%d",flush_flag);
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobFlushBuffer", connection->error);
-               oci_handle_error(connection, connection->error);
-               return 0;
-       }
-
-       /* marking buffer as enabled and not used */
-       descr->buffering = 1;
-       return 1;
-}
-/* }}} */
-
-/* {{{ php_oci_fetch_row()
-*/
-static void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_args)
-{
-       zval **stmt, **arg2, **arg3;
-       oci_statement *statement;
-       oci_out_column *column;
-       ub4 nrows = 1;
-       int i;
-
-       if (ZEND_NUM_ARGS() > expected_args) {
-               WRONG_PARAM_COUNT;
-       }
-
-       if (expected_args > 2) {
-               /* only for ocifetchinto BC */
-
-               switch (ZEND_NUM_ARGS()) {
-                       case 2:
-                               if (zend_get_parameters_ex(2, &stmt, &arg2) == FAILURE) {
-                                       RETURN_FALSE;
-                               }
-                               if (!mode) {
-                                       mode = OCI_NUM;
-                               }
-                               break;
-
-                       case 3:
-                               if (zend_get_parameters_ex(3, &stmt, &arg2, &arg3) == FAILURE) {
-                                       RETURN_FALSE;
-                               }
-                               convert_to_long_ex(arg3);
-                               mode = Z_LVAL_PP(arg3);
-                               break;
-
-                       default:
-                               WRONG_PARAM_COUNT;
-                               break;
-               }
-
-       } else {
-
-               switch (ZEND_NUM_ARGS()) {
-                       case 1:
-                               if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-                                       RETURN_FALSE;
-                               }
-                               if (!mode) {
-                                       mode = OCI_BOTH;
-                               }
-                               break;
-
-                       case 2:
-                               if (zend_get_parameters_ex(2, &stmt, &arg2)==FAILURE) {
-                                       RETURN_FALSE;
-                               }
-                               convert_to_long_ex(arg2);
-                               mode = Z_LVAL_PP(arg2);
-                               break;
-                       
-                       default:
-                               WRONG_PARAM_COUNT;
-                               break;
-               }
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       if (!oci_fetch(statement, nrows, "OCIFetchInto" TSRMLS_CC)) {
-               RETURN_FALSE;
-       }
-
-       array_init(return_value);
-
-       for (i = 0; i < statement->ncolumns; i++) {
-               column = oci_get_col(statement, i + 1, 0);
-               if (column == NULL) {
-                       continue;
-               }
-               if ((column->indicator == -1) && ((mode & OCI_RETURN_NULLS) == 0)) {
-                       continue;
-               }
-
-               if (!(column->indicator == -1)) {
-                       zval *element;
-                       
-                       MAKE_STD_ZVAL(element);
-                       _oci_make_zval(element,statement,column,"OCIFetchInto",mode TSRMLS_CC);
-
-                       if (mode & OCI_NUM || !(mode & OCI_ASSOC)) {
-                               add_index_zval(return_value, i, element);
-                       }
-                       if (mode & OCI_ASSOC) {
-                               if (mode & OCI_NUM) {
-                                       ZVAL_ADDREF(element);
-                               }
-                               add_assoc_zval(return_value, column->name, element);
-                       }
-               
-               } else {
-                       if (mode & OCI_NUM || !(mode & OCI_ASSOC)) {
-                               add_index_null(return_value, i);
-                       }
-                       if (mode & OCI_ASSOC) {
-                               add_assoc_null(return_value, column->name);
-                       }
-               }
-       }
-
-       if (expected_args > 2) {
-               /* only for ocifetchinto BC
-                * in all other cases we return array, not long
-                */
-               REPLACE_ZVAL_VALUE(arg2, return_value, 1); /* copy return_value to given reference */
-               zval_dtor(return_value);
-               RETURN_LONG(statement->ncolumns);
-       }
-}
-/* }}} */
-
-/************************* EXTENSION FUNCTIONS *************************/
-
-/* {{{ proto bool oci_define_by_name(resource stmt, string name, mixed &var [, int type])
-   Define a PHP variable to an Oracle column by name */
-/* if you want to define a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE defining!!! */
-PHP_FUNCTION(oci_define_by_name)
-{
-       zval **stmt, **name, **var, **type;
-       oci_statement *statement;
-       oci_define *define, *tmp_define;
-       ub2     ocitype = SQLT_CHR; /* zero terminated string */
-       int ac = ZEND_NUM_ARGS();
-
-       if (ac < 3 || ac > 4 || zend_get_parameters_ex(ac, &stmt, &name, &var, &type) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       switch (ac) {
-               case 4:
-                       convert_to_long_ex(type);
-                       ocitype = (ub2) Z_LVAL_PP(type);
-                       /* possible breakthru */
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       convert_to_string_ex(name);
-
-       if (statement->defines == NULL) {
-               ALLOC_HASHTABLE(statement->defines);
-               zend_hash_init(statement->defines, 13, NULL, _oci_define_hash_dtor, 0);
-       }
-
-       define = ecalloc(1,sizeof(oci_define));
-
-       if (zend_hash_add(statement->defines,
-                                         Z_STRVAL_PP(name),
-                                         Z_STRLEN_PP(name),
-                                         define,
-                                         sizeof(oci_define),
-                                         (void **)&tmp_define) == SUCCESS) {
-               efree(define);
-               define = tmp_define;
-       } else {
-               efree(define);
-               RETURN_FALSE;
-       }
-
-       define->name = (text*) estrndup(Z_STRVAL_PP(name),Z_STRLEN_PP(name));
-       define->name_len = Z_STRLEN_PP(name);
-       define->type = ocitype;
-       define->zval = *var;
-       zval_add_ref(var);
-
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_bind_by_name(resource stmt, string name, mixed &var, [, int maxlength [, int type]])
-   Bind a PHP variable to an Oracle placeholder by name */
-/* if you want to bind a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE binding!!! */
-PHP_FUNCTION(oci_bind_by_name)
-{
-       zval **stmt, **name, **var, **maxlen, **type;
-       oci_statement *statement;
-       oci_statement *bindstmt;
-       oci_bind bind, *bindp;
-       oci_descriptor *descr;
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-       oci_collection *coll;
-       dvoid *mycoll = 0;
-#endif
-       int mode = OCI_DATA_AT_EXEC;
-       ub2     ocitype = SQLT_CHR; /* unterminated string */
-       OCIStmt *mystmt = 0;
-       dvoid *mydescr = 0;
-       sb4 value_sz = -1;
-       int ac = ZEND_NUM_ARGS(), inx;
-
-       if (ac < 3 || ac > 5 || zend_get_parameters_ex(ac, &stmt, &name, &var, &maxlen, &type) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       switch (ac) {
-               case 5:
-                       convert_to_long_ex(type);
-                       ocitype = (ub2) Z_LVAL_PP(type);
-                       /* possible breakthru */
-               case 4:
-                       convert_to_long_ex(maxlen);
-                       value_sz = Z_LVAL_PP(maxlen);
-                       /* possible breakthru */
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       switch (ocitype) {
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-               case SQLT_NTY:
-                       if (Z_TYPE_PP(var) != IS_OBJECT) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Variable must be allocated using OCINewCollection()");
-                               RETURN_FALSE;
-                       }
-                       if ((inx = _oci_get_ocicoll(*var,&coll TSRMLS_CC)) == 0) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Variable must be allocated using OCINewCollection()");
-                               RETURN_FALSE;
-                       }
-                       if (!(mycoll = (dvoid *) coll->coll)) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Collection empty");
-                               RETURN_FALSE;
-                       }
-                       value_sz = sizeof(void*);
-                       mode = OCI_DEFAULT;
-break;
-#endif
-               case SQLT_BFILEE:
-               case SQLT_CFILEE:
-               case SQLT_CLOB:
-               case SQLT_BLOB:
-               case SQLT_RDD:
-                       if (Z_TYPE_PP(var) != IS_OBJECT) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Variable must be allocated using OCINewDescriptor()");
-                               RETURN_FALSE;
-                       }
-
-                       if ((inx = _oci_get_ocidesc(*var,&descr TSRMLS_CC)) == 0) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Variable must be allocated using OCINewDescriptor()");
-                               RETURN_FALSE;
-                       }
-               
-                       if (!(mydescr = (dvoid *) descr->ocidescr)) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Descriptor empty");
-                               RETURN_FALSE;
-                       }
-                       value_sz = sizeof(void*);
-                       break;
-
-               case SQLT_RSET:
-                       OCI_GET_STMT(bindstmt,var);
-
-                       if (!(mystmt = bindstmt->pStmt)) {
-                               RETURN_FALSE;
-                       }
-                       value_sz = sizeof(void*);
-                       break;
-               case SQLT_CHR:
-                       break;
-               default:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %u", ocitype);
-                       RETURN_FALSE;
-                       break;
-       }
-       
-       if ((ocitype == SQLT_CHR) && (value_sz == -1)) {
-               convert_to_string_ex(var);
-               value_sz = Z_STRLEN_PP(var);
-       }
-
-       if (value_sz == 0) { 
-               value_sz = 1;
-       }
-
-       convert_to_string_ex(name);
-
-       if (!statement->binds) {
-               ALLOC_HASHTABLE(statement->binds);
-               zend_hash_init(statement->binds, 13, NULL, _oci_bind_hash_dtor, 0);
-       }
-
-       memset((void*)&bind,0,sizeof(oci_bind));
-       zend_hash_update(statement->binds, Z_STRVAL_PP(name), Z_STRLEN_PP(name) + 1, &bind, sizeof(oci_bind), (void **)&bindp);
-       
-       bindp->descr = mydescr;
-       bindp->pStmt = mystmt;
-       bindp->zval = *var;
-       zval_add_ref(var); 
-       
-       CALL_OCI_RETURN(statement->error,
-               OCIBindByName(
-                       statement->pStmt,                /* statement handle */
-                       (OCIBind **)&bindp->pBind,       /* bind hdl (will alloc) */
-                       statement->pError,               /* error handle */
-                       (text*) Z_STRVAL_PP(name),       /* placeholder name */                                   
-                       Z_STRLEN_PP(name),               /* placeholder length */
-                       (dvoid *)0,                      /* in/out data */
-                       value_sz, /* OCI_MAX_DATA_SIZE, */ /* max size of input/output data */
-                       (ub2)ocitype,                    /* in/out data type */
-                       (dvoid *)&bindp->indicator,      /* indicator (ignored) */
-                       (ub2 *)0,                        /* size array (ignored) */
-                       (ub2 *)&bindp->retcode,          /* return code (ignored) */
-                       (ub4)0,                          /* maxarr_len (PL/SQL only?) */
-                       (ub4 *)0,                        /* actual array size (PL/SQL only?) */
-                       mode                             /* mode */
-               )
-       );
-
-       if (statement->error != OCI_SUCCESS) {
-               oci_error(statement->pError, "OCIBindByName", statement->error);
-               oci_handle_error(statement->conn, statement->error);
-               RETURN_FALSE;
-       }
-
-       if (mode == OCI_DATA_AT_EXEC) {
-               CALL_OCI_RETURN(statement->error,
-                       OCIBindDynamic(
-                               bindp->pBind, 
-                               statement->pError, 
-                               (dvoid *)bindp, 
-                               oci_bind_in_callback, 
-                               (dvoid *)bindp, 
-                               oci_bind_out_callback
-                       )
-               );
-
-               if (statement->error != OCI_SUCCESS) {
-                       oci_error(statement->pError, "OCIBindDynamic", statement->error);
-                       oci_handle_error(statement->conn, statement->error);
-                       RETURN_FALSE;
-               }
-       }
-
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-       if (ocitype == SQLT_NTY) {
-               /* Bind object */
-               CALL_OCI_RETURN(statement->error,
-                       OCIBindObject(
-                               bindp->pBind, 
-                               statement->pError, 
-                               coll->tdo, 
-                               (dvoid **) &(coll->coll), 
-                               (ub4 *) 0, 
-                               (dvoid **) 0, 
-                               (ub4 *) 0
-                       )
-               );
-
-               if (statement->error) {
-                       oci_error(statement->pError, "OCIBindObject", statement->error);
-                       RETURN_FALSE;
-               }
-       }
-#endif
-       
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_free_descriptor()
-   Deletes large object description */
-PHP_FUNCTION(oci_free_descriptor)
-{
-       zval *id;
-       int inx;
-       oci_descriptor *descriptor;
-
-       if ((id = getThis()) != 0) {
-               inx = _oci_get_ocidesc(id,&descriptor TSRMLS_CC);
-               if (inx) {
-                       oci_debug("oci_free_descriptor: descr=%d",inx);
-                       zend_list_delete(inx);
-                       RETURN_TRUE;
-               }
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_free_descriptor() should not be called like this. Use $somelob->free() to free a LOB");
-
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_save( string data [, int offset ])
-   Saves a large object */
-PHP_FUNCTION(oci_lob_save)
-{
-       zval *id, **arg,**oarg;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int offparam,inx;
-       ub4 loblen;
-       ub4 curloblen;
-       ub4 offset;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               offset = 0;     
-               if (zend_get_parameters_ex(2, &arg, &oarg) == SUCCESS) {
-                       convert_to_long_ex(oarg);
-                       offparam = Z_LVAL_PP(oarg);
-
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobGetLength(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       mylob, 
-                                       &curloblen
-                               )
-                       );
-
-                       oci_debug("oci_lob_save: curloblen=%d",curloblen);
-
-                       if (offparam == -1) {
-                               offset = curloblen;
-                       } else if ((ub4)offparam >= curloblen) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset is bigger than current LOB-Size - appending");
-                               offset = curloblen;
-                       } else {
-                               offset = (ub4)offparam;
-                       }
-               } else if (zend_get_parameters_ex(1, &arg) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               convert_to_string_ex(arg);
-               loblen = Z_STRLEN_PP(arg);
-       
-               if (loblen < 1) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot save a lob which size is less than 1 byte");
-                       RETURN_FALSE;
-               }
-
-               if (offset <= 0) {
-                       offset = 1;
-               }
-               
-               CALL_OCI_RETURN(connection->error,
-                       OCILobWrite(
-                               connection->pServiceContext, 
-                               connection->pError,
-                               mylob,
-                               &loblen,
-                               (ub4) offset,
-                               (dvoid *) Z_STRVAL_PP(arg),
-                               (ub4) loblen,
-                               OCI_ONE_PIECE,
-                               (dvoid *)0,
-                               (OCICallbackLobWrite) 0,
-                               (ub2) 0,
-                               (ub1) SQLCS_IMPLICIT
-                       )
-               );
-
-               oci_debug("oci_lob_save: size=%d offset=%d",loblen,offset);
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobWrite", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               RETURN_TRUE;
-       }
-
-  RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_import( string filename )
-   Saves a large object to file */
-PHP_FUNCTION(oci_lob_import)
-{
-       zval *id, **arg;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       char *filename;
-       int fp,inx;
-       char buf[8192];
-       ub4 offset = 1;
-       ub4 loblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (zend_get_parameters_ex(1, &arg) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               convert_to_string_ex(arg);
-
-               if (php_check_open_basedir(Z_STRVAL_PP(arg) TSRMLS_CC)) {
-                       RETURN_FALSE;
-               }
-
-               filename = Z_STRVAL_PP(arg);
-
-               if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't open file %s", filename);
-                       RETURN_FALSE;
-               }
-
-               while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {    
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobWrite(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       mylob, 
-                                       &loblen, 
-                                       (ub4) offset, 
-                                       (dvoid *) &buf, 
-                                       (ub4) loblen, 
-                                       OCI_ONE_PIECE, 
-                                       (dvoid *)0, 
-                                       (OCICallbackLobWrite) 0, 
-                                       (ub2) 0, 
-                                       (ub1) SQLCS_IMPLICIT
-                               )
-                       );
-
-                       oci_debug("oci_lob_import: size=%d",loblen);
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobWrite", connection->error);
-                               oci_handle_error(connection, connection->error);
-                               close(fp);
-                               RETURN_FALSE;
-                       }
-
-                       offset += loblen;
-               }
-               close(fp);
-
-               RETURN_TRUE;
-       }
-
-  RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto string oci_lob_load()
-   Loads a large object */
-PHP_FUNCTION(oci_lob_load)
-{
-       zval *id;
-       oci_descriptor *descr;
-       char *buffer;
-       int inx;
-       ub4 loblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (!oci_loadlob(descr->conn,descr,&buffer,&loblen)) {
-                       RETURN_STRINGL(buffer,loblen,0);
-               } else {
-                       RETURN_FALSE;
-               }
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_load() should not be called like this. Use $somelob->load() to load a LOB");
-
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto string oci_lob_read( int length )
-   Reads particular part of a large object */
-PHP_FUNCTION(oci_lob_read)
-{
-       zval *id;
-       zval **len;
-       oci_descriptor *descr;
-       char *buffer;
-       int inx;
-       ub4 loblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (zend_get_parameters_ex(1, &len) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               loblen = Z_LVAL_PP(len);
-               if (oci_readlob(descr->conn,descr,&buffer,&loblen) == 0) {
-                       RETURN_STRINGL(buffer,loblen,0);
-               } else {
-                       RETURN_FALSE;
-               }
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_read() should not be called like this. Use $somelob->read($len) to read a LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_eof()
-   Checks if EOF is reached */
-PHP_FUNCTION(oci_lob_eof)
-{
-       zval *id;
-       oci_descriptor *descr;
-       int inx;
-       int len;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (oci_lobgetlen(descr->conn,descr,&len) == 0 && descr->lob_size >= 0) {
-                       if (descr->lob_size == descr->lob_current_position) {
-                               RETURN_TRUE;
-                       } else {
-                               RETURN_FALSE;
-                       }
-               }
-               RETURN_FALSE;
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_eof() should not be called like this. Use $somelob->eof() to check if end of LOB is reached");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto int oci_lob_tell()
-   Tells LOB pointer position */
-PHP_FUNCTION(oci_lob_tell)
-{
-       zval *id;
-       oci_descriptor *descr;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               RETURN_LONG(descr->lob_current_position);       
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_tell() should not be called like this. Use $somelob->tell() to get current position of LOB pointer");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_rewind()
-   Rewind pointer of a LOB */
-PHP_FUNCTION(oci_lob_rewind)
-{
-       zval *id;
-       oci_descriptor *descr;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               descr->lob_current_position = 0;
-               RETURN_TRUE;
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_rewind() should not be called like this. Use $somelob->rewind() to set current position of LOB pointer to beginning");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_seek( int offset [, int whence ])
-   Moves the pointer of a LOB */
-PHP_FUNCTION(oci_lob_seek)
-{
-       zval *id;
-       zval **arg1, **arg2;
-       int argcount = ZEND_NUM_ARGS(), whence = OCI_SEEK_SET;
-       oci_descriptor *descr;
-       int inx, len;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-
-               if (argcount < 1 || argcount > 2 || zend_get_parameters_ex(argcount, &arg1, &arg2) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-               
-               convert_to_long_ex(arg1);
-               
-               if (oci_lobgetlen(descr->conn,descr,&len) == 0 && descr->lob_size >= 0) {
-                       if (argcount > 1) {
-                               convert_to_long_ex(arg2);
-                               whence = Z_LVAL_PP(arg2);
-                               switch (whence) {
-                                       case OCI_SEEK_CUR:
-                                               descr->lob_current_position += Z_LVAL_PP(arg1);
-                                               break;
-                                       
-                                       case OCI_SEEK_END:
-                                               if (descr->lob_size + Z_LVAL_PP(arg1) >= 0) {
-                                                       descr->lob_current_position = descr->lob_size + Z_LVAL_PP(arg1);
-                                               } else {
-                                                       descr->lob_current_position = 0;
-                                               }
-                                               break;
-                                       
-                                       case OCI_SEEK_SET:
-                                       default:
-                                               descr->lob_current_position = Z_LVAL_PP(arg1);
-                                               break;
-                               }
-                       } else {
-                               /* OCI_SEEK_SET by default */
-                               descr->lob_current_position = Z_LVAL_PP(arg1);
-                       }
-                       RETURN_TRUE;
-               } else {
-                       RETURN_FALSE;
-               }
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_seek() should not be called like this. Use $somelob->seek($offset) to move pointer");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto int oci_lob_size()
-   Returns size of a large object */
-PHP_FUNCTION(oci_lob_size)
-{
-       zval *id;
-       oci_descriptor *descr;
-       int inx;
-       ub4 loblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-
-               if (!oci_lobgetlen(descr->conn,descr,&loblen)) {
-                       RETURN_LONG(loblen);
-               } else {
-                       RETURN_FALSE;
-               }
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_size() should not be called like this. Use $somelob->size() to get size of a LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto int oci_lob_write( string string [, int length ])
-   Writes data to current position of a LOB */
-PHP_FUNCTION(oci_lob_write)
-{
-       zval *id, **data,**length;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int write_length,inx;
-       ub4 loblen;
-       ub4 curloblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               IS_LOB_INTERNAL(descr);
-                       
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (oci_lobgetlen(descr->conn,descr,&curloblen) != 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (zend_get_parameters_ex(2, &data, &length) == SUCCESS) {
-                       convert_to_string_ex(data);
-                       convert_to_long_ex(length);
-                       write_length = Z_LVAL_PP(length);
-               } else if (zend_get_parameters_ex(1, &data) == SUCCESS) {
-                       convert_to_string_ex(data);     
-                       write_length = Z_STRLEN_PP(data);
-               } else {
-                       WRONG_PARAM_COUNT;
-               }
-
-               if (write_length < 1) {
-                       RETURN_LONG(0);
-               }
-               
-               loblen = write_length;
-               
-               CALL_OCI_RETURN(connection->error,
-                       OCILobWrite(
-                               connection->pServiceContext, 
-                               connection->pError,
-                               mylob,
-                               &loblen,
-                               (ub4) descr->lob_current_position+1,
-                               (dvoid *) Z_STRVAL_PP(data),
-                               (ub4) loblen,
-                               OCI_ONE_PIECE,
-                               (dvoid *)0,
-                               (OCICallbackLobWrite) 0,
-                               (ub2) 0,
-                               (ub1) SQLCS_IMPLICIT
-                       )
-               );
-
-               oci_debug("oci_lob_write: size=%d offset=%d",loblen,descr->lob_current_position);
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobWrite", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               descr->lob_current_position += loblen;
-       
-               if (descr->lob_current_position > descr->lob_size) {
-                       descr->lob_size = descr->lob_current_position;
-               }
-               
-               /* marking buffer as used */
-               if (descr->buffering == 1) {
-                       descr->buffering = 2;
-               }
-               RETURN_LONG(loblen);
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_write() should not be called like this. Use $somelob->write($data,$len) to write to a LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_append( object lob )
-   Appends data from a LOB to another LOB */
-PHP_FUNCTION(oci_lob_append)
-{
-       zval *id, **arg;
-       OCILobLocator *mylob,*my_fromlob;
-       oci_connection *connection;
-       oci_descriptor *descr,*from_descr;
-       int inx;
-       ub4 curloblen,from_curloblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-       
-               IS_LOB_INTERNAL(descr);
-               
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (oci_lobgetlen(descr->conn,descr,&curloblen) != 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (zend_get_parameters_ex(1, &arg) == SUCCESS) {
-                       convert_to_object_ex(arg);
-                       if ((inx = _oci_get_ocidesc(*arg,&from_descr TSRMLS_CC)) == 0) {
-                               RETURN_FALSE;
-                       }
-                       
-                       my_fromlob = (OCILobLocator *) from_descr->ocidescr;
-
-                       if (!my_fromlob) {
-                               RETURN_FALSE;
-                       }
-                       
-                       if (oci_lobgetlen(from_descr->conn,from_descr,&from_curloblen) != 0) {
-                               RETURN_FALSE;
-                       }
-               } else {
-                       WRONG_PARAM_COUNT;
-               }
-
-               if (from_descr->lob_size == 0) {
-                       RETURN_LONG(0);
-               }
-
-               CALL_OCI_RETURN(connection->error,
-                       OCILobAppend(
-                               connection->pServiceContext, 
-                               connection->pError,
-                               mylob,
-                               my_fromlob
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobAppend", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               RETURN_TRUE;
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_append() should not be called like this. Use $somelob->append($LOB_from) to append data from a LOB to another LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_truncate( [ int length ])
-   Truncates a LOB */
-PHP_FUNCTION(oci_lob_truncate)
-{
-       zval *id, **length;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int inx;
-       ub4 trim_length;
-       ub4 curloblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               IS_LOB_INTERNAL(descr);
-
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (oci_lobgetlen(descr->conn,descr,&curloblen) != 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (zend_get_parameters_ex(1, &length) == SUCCESS) {
-                       convert_to_long_ex(length);     
-                       trim_length = Z_LVAL_PP(length);
-               } else {
-                       trim_length = 0;
-               }
-
-               if (trim_length < 0) {
-                       /* negative length is not allowed */
-                       RETURN_FALSE;
-               }
-               
-               CALL_OCI_RETURN(connection->error,
-                       OCILobTrim(
-                               connection->pServiceContext, 
-                               connection->pError,
-                               mylob,
-                               trim_length
-                       )
-               );
-
-               oci_debug("oci_lob_truncate: trim_length=%d",trim_length);
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobTrim", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               descr->lob_size = trim_length;
-               RETURN_TRUE;
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_truncate() should not be called like this. Use $somelob->truncate($length) to truncate a LOB to a specified length");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto int oci_lob_erase( [ int offset [, int length ] ] )
-   Erases a specified portion of the internal LOB, starting at a specified offset */
-PHP_FUNCTION(oci_lob_erase)
-{
-       zval *id, **length, **offset;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int inx;
-       ub4 erase_length, erase_offset;
-       ub4 curloblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               IS_LOB_INTERNAL(descr);
-
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (oci_lobgetlen(descr->conn,descr,&curloblen) != 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (zend_get_parameters_ex(2, &offset, &length) == SUCCESS) {
-                       convert_to_long_ex(offset);
-                       convert_to_long_ex(length);     
-                       
-                       erase_offset = Z_LVAL_PP(offset);
-                       erase_length = Z_LVAL_PP(length);
-               } else if (zend_get_parameters_ex(1, &offset) == SUCCESS) {
-                       convert_to_long_ex(offset);
-
-                       erase_offset = Z_LVAL_PP(offset);
-                       erase_length = descr->lob_size - erase_offset;
-               } else {
-                       erase_offset = 0;
-                       erase_length = descr->lob_size;
-               }
-
-               if (erase_length < 1) {
-                       RETURN_LONG(0);
-               }
-
-               if (erase_offset > descr->lob_size) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "oci_lob_erase(): offset is greater than LOB's length");
-               }
-               
-               CALL_OCI_RETURN(connection->error,
-                       OCILobErase(
-                               connection->pServiceContext, 
-                               connection->pError,
-                               mylob,
-                               &erase_length,
-                               erase_offset+1
-                       )
-               );
-
-               oci_debug("oci_lob_erase: erase_length=%d, erase_offset=%d",erase_length,erase_offset);
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobErase", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               RETURN_LONG(erase_length);
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_erase() should not be called like this. Use $somelob->erase($offset, $length) to erase specified part of LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_flush( [ int flag ] )
-   Flushes the LOB buffer */
-PHP_FUNCTION(oci_lob_flush)
-{
-       zval *id, **flag;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int inx, flush_flag;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               IS_LOB_INTERNAL(descr);
-                       
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (zend_get_parameters_ex(1, &flag) == SUCCESS) {
-                       convert_to_long_ex(flag);       
-                       flush_flag = Z_LVAL_PP(flag);
-               } else {
-                       flush_flag = 0;
-               }
-
-               if (descr->buffering == 0) {
-                       /* buffering wasn't enabled, there is nothing to flush */
-                       RETURN_FALSE;
-               }
-
-               if (oci_lob_flush(descr,flush_flag TSRMLS_CC) == 1) {
-                       RETURN_TRUE;
-               }
-               RETURN_FALSE;
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_flush() should not be called like this. Use $somelob->flush() to flush LOB buffer");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool ocisetbufferinglob( boolean flag )
-   Enables/disables buffering for a LOB */
-PHP_FUNCTION(ocisetbufferinglob)
-{
-       zval *id, **flag;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int inx, buffering_flag;
-       ub4 curloblen;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               IS_LOB_INTERNAL(descr);
-                       
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (oci_lobgetlen(descr->conn,descr,&curloblen) != 0) {
-                       RETURN_FALSE;
-               }
-               
-               if (zend_get_parameters_ex(1, &flag) == SUCCESS) {
-                       convert_to_boolean_ex(flag);
-                       buffering_flag = Z_LVAL_PP(flag);
-               } else {
-                       WRONG_PARAM_COUNT;
-               }
-
-               /* we'll return true if function was called twice with the same parameter */
-               if (buffering_flag == 0 && descr->buffering == 0) {
-                       RETURN_TRUE;
-               } else if (buffering_flag == 1 && descr->buffering > 0) {
-                       RETURN_TRUE;
-               }
-               
-               switch (buffering_flag) {
-                       case 0:
-                               CALL_OCI_RETURN(connection->error,
-                                       OCILobDisableBuffering(
-                                               connection->pServiceContext, 
-                                               connection->pError,
-                                               mylob
-                                       )
-                               );
-                               break;
-                       case 1:
-                               CALL_OCI_RETURN(connection->error, 
-                                       OCILobEnableBuffering(
-                                               connection->pServiceContext,
-                                               connection->pError,
-                                               mylob
-                                       )
-                               );
-                       break;
-               }
-               
-               oci_debug("oci_lob_set_buffering: buffering_flag=%d",buffering_flag);
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobFlushBuffer", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               descr->buffering = buffering_flag;
-               RETURN_TRUE;
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OCISetBufferingLob() should not be called like this. Use $somelob->setBuffering($flag) to set buffering on/off for a LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool ocigetbufferinglob()
-   Returns current state of buffering for a LOB */
-PHP_FUNCTION(ocigetbufferinglob)
-{
-       zval *id;
-       OCILobLocator *mylob;
-       oci_descriptor *descr;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               IS_LOB_INTERNAL(descr);
-                       
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               switch (descr->buffering) {
-                       case 1:
-                       case 2:
-                               RETURN_TRUE;
-                               break;
-
-                       case 0:
-                       default:
-                               RETURN_FALSE;
-                               break;
-               }
-       }
-       
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "OCIGetBufferingLob() should not be called like this. Use $somelob->getBuffering() to get current state of buffering for a LOB");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_copy( object lob_to, object lob_from [, int length ] )
-   Copies data from a LOB to another LOB */
-PHP_FUNCTION(oci_lob_copy)
-{
-       zval **arg1, **arg2, **arg3;
-       OCILobLocator *mylob,*my_fromlob;
-       oci_connection *connection;
-       oci_descriptor *descr,*from_descr;
-       int inx, ac = ZEND_NUM_ARGS();
-       ub4 curloblen,from_curloblen, copylen;
-
-               if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &arg1, &arg2, &arg3) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               convert_to_object_ex(arg1);
-               convert_to_object_ex(arg2);
-               
-               if ((inx = _oci_get_ocidesc(*arg1,&descr TSRMLS_CC)) == 0 || (inx = _oci_get_ocidesc(*arg2,&from_descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-
-               IS_LOB_INTERNAL(descr);
-               IS_LOB_INTERNAL(from_descr);
-
-               mylob = (OCILobLocator *) descr->ocidescr;
-               my_fromlob = (OCILobLocator *) from_descr->ocidescr;
-                       
-               if (!mylob || !my_fromlob) {
-                       RETURN_FALSE;
-               }
-                       
-               if (oci_lobgetlen(descr->conn,descr,&curloblen) != 0 || oci_lobgetlen(from_descr->conn,from_descr,&from_curloblen) != 0) {
-                       RETURN_FALSE;
-               }
-
-               if (ac == 3) {
-                       convert_to_long_ex(arg3);
-                       copylen = Z_LVAL_PP(arg3);
-               } else {
-                       copylen = from_descr->lob_size - from_descr->lob_current_position;
-               }
-
-               if ((int)copylen <= 0) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               CALL_OCI_RETURN(connection->error,
-                       OCILobCopy(
-                               connection->pServiceContext, 
-                               connection->pError,
-                               mylob,
-                               my_fromlob,
-                               copylen,
-                               descr->lob_current_position+1,
-                               from_descr->lob_current_position+1
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobCopy", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_is_equal( object lob1, object lob2 )
-   Tests to see if two LOB/FILE locators are equal */
-PHP_FUNCTION(oci_lob_is_equal)
-{
-       zval **arg1, **arg2;
-       OCILobLocator *first_lob,*second_lob;
-       oci_connection *connection;
-       oci_descriptor *first_descr,*second_descr;
-       int inx;
-       boolean is_equal;
-
-               if (zend_get_parameters_ex(2, &arg1, &arg2) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               convert_to_object_ex(arg1);
-               convert_to_object_ex(arg2);
-               
-               if ((inx = _oci_get_ocidesc(*arg1,&first_descr TSRMLS_CC)) == 0 || (inx = _oci_get_ocidesc(*arg2,&second_descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               
-               first_lob = (OCILobLocator *) first_descr->ocidescr;
-               second_lob = (OCILobLocator *) second_descr->ocidescr;
-                       
-               if (!first_lob || !second_lob) {
-                       RETURN_FALSE;
-               }
-                       
-               connection = first_descr->conn;
-
-               CALL_OCI_RETURN(connection->error,
-                       OCILobIsEqual(
-                               connection->session->pEnv, 
-                               first_lob,
-                               second_lob,
-                               &is_equal
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobIsEqual", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       RETURN_FALSE;
-               }
-
-               if (is_equal == TRUE) {
-                       RETURN_TRUE;
-               } else {
-                       RETURN_FALSE;
-               }
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_export([string filename [, int start [, int length]]])
-   Writes a large object into a file */
-PHP_FUNCTION(oci_lob_export)
-{
-       zval *id, **zfilename, **zstart, **zlength;
-       char *filename = NULL;
-       int start = -1;
-       ub4 length = -1;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       char *buffer=0;
-       ub4 loblen;
-       int ac = ZEND_NUM_ARGS();
-       int fp = -1,inx;
-       OCILobLocator *mylob;
-       int coffs;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocidesc(id,&descr TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-
-               mylob = (OCILobLocator *) descr->ocidescr;
-
-               if (!mylob) {
-                       RETURN_FALSE;
-               }
-
-               connection = descr->conn;
-
-               if (ac < 0 || ac > 3 || zend_get_parameters_ex(ac, &zfilename, &zstart, &zlength) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               switch (ac) {
-               case 3:
-                       convert_to_long_ex(zlength);
-                       length = Z_LVAL_PP(zlength);
-               case 2:
-                       convert_to_long_ex(zstart);
-                       start = Z_LVAL_PP(zstart);
-               case 1:
-                       convert_to_string_ex(zfilename);
-                       filename = Z_STRVAL_PP(zfilename);
-               }
-
-               if (filename && *filename) {
-                       if (php_check_open_basedir(filename TSRMLS_CC)) {
-                               goto bail;
-                       }
-
-                       if ((fp = VCWD_OPEN_MODE(filename,O_CREAT | O_RDWR | O_BINARY | O_TRUNC, 0600)) == -1) {
-                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't create file %s", filename);
-                               goto bail;
-                       } 
-               }
-       
-               CALL_OCI_RETURN(connection->error,
-                       OCILobGetLength(
-                               connection->pServiceContext, 
-                               connection->pError, 
-                               descr->ocidescr, 
-                               &loblen
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCILobGetLength", connection->error);
-                       oci_handle_error(connection, connection->error);
-                       goto bail;
-               }
-               
-               if (descr->type == OCI_DTYPE_FILE) {
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobFileOpen(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       descr->ocidescr, 
-                                       OCI_FILE_READONLY
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobFileOpen",connection->error);
-                               oci_handle_error(connection, connection->error);
-                               goto bail;
-                       }
-               }
-
-               if (start == -1) {
-                       start = 0;
-               }
-
-               if (length == -1) {
-                       length = loblen - start;
-               }
-               
-               if ((start + length) > loblen) {
-                       length = loblen - start;
-               }
-
-#define OCI_LOB_READ_BUFFER 128*1024
-
-               buffer = emalloc(OCI_LOB_READ_BUFFER);
-
-               coffs = start;
-
-               oci_debug("oci_lob_export(start = %d, length = %d, loblen = %d",start,length,loblen);
-
-               while (length > 0) {
-                       ub4 toread;
-
-                       if (length > OCI_LOB_READ_BUFFER) {
-                               toread = OCI_LOB_READ_BUFFER;
-                       } else {
-                               toread = length;
-                       }
-
-                       oci_debug("oci_lob_read(coffs = %d, toread = %d",coffs,toread);
-
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobRead(
-                                       connection->pServiceContext, 
-                                       connection->pError,
-                                       descr->ocidescr,
-                                       &toread,                /* IN/OUT bytes toread/read */
-                                       coffs+1,                /* offset (starts with 1) */ 
-                                       (dvoid *) buffer,
-                                       toread,                 /* size of buffer */
-                                       (dvoid *)0,
-                                       (OCICallbackLobRead) 0, /* callback... */
-                                       (ub2) 0,                /* The character set ID of the buffer data. */
-                                       (ub1) SQLCS_IMPLICIT    /* The character set form of the buffer data. */
-                               )
-                       );
-
-                       oci_debug("oci_lob_read(read - %d",toread);
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobRead", connection->error);
-                               oci_handle_error(connection, connection->error);
-                               goto bail;
-                       }
-
-                       if (fp != -1) {
-                               if ((ub4) write(fp,buffer,toread) != toread) {
-                                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "cannot write file!");
-                                       goto bail;
-                               }
-                       } else {
-                               PHPWRITE(buffer,toread);
-                       }
-
-                       length -= toread;
-                       coffs += toread;
-               }
-
-               efree(buffer);
-               buffer = 0;
-               
-               if (fp != -1) {
-                       close(fp);
-                       fp = 0;
-               }
-
-               if (descr->type == OCI_DTYPE_FILE) {
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobFileClose(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       descr->ocidescr
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobFileClose", connection->error);
-                               oci_handle_error(connection, connection->error);
-                               goto bail;
-                       }
-               }
-               RETURN_TRUE;
-       }
-       
-bail:
-       if (fp != -1) {
-               close(fp);
-       }
-       
-       if (buffer) {
-               efree(buffer);
-       }
-
-       RETURN_FALSE;
-}
-/* }}} */
-
-#ifdef HAVE_OCI8_TEMP_LOB
-/* {{{ proto bool oci_lob_write_temporary(string var [, int lob_type])
-   Writes temporary blob */
-PHP_FUNCTION(oci_lob_write_temporary)
-{
-       zval *id, *var;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       ub4 offset = 1;
-       ub4 loblen;
-       long lob_type = OCI_TEMP_CLOB;
-
-       oci_debug ("oci_write_temporary_lob");
-
-       if ((id = getThis()) == 0) {
-               RETURN_FALSE;
-       }
-
-       if (_oci_get_ocidesc(id,&descr TSRMLS_CC) == 0) {
-               RETURN_FALSE;
-       }
-
-       mylob = (OCILobLocator *) descr->ocidescr;
-
-       if (!mylob) {
-               RETURN_FALSE;
-       }
-
-       connection = descr->conn;
-
-       if (ZEND_NUM_ARGS() < 1) WRONG_PARAM_COUNT;
-       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "z|l", &var, &lob_type) == FAILURE) {
-               RETURN_FALSE;
-       }
-
-       CALL_OCI_RETURN(connection->error,
-               OCILobCreateTemporary(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       mylob, 
-                       OCI_DEFAULT, 
-                       OCI_DEFAULT, 
-                       lob_type, 
-                       OCI_ATTR_NOCACHE, 
-                       OCI_DURATION_SESSION
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobCreateTemporary", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
-       }
-
-       CALL_OCI_RETURN(connection->error,
-               OCILobOpen(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       mylob, 
-                       OCI_LOB_READWRITE
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobOpen", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
-       }
-
-       convert_to_string_ex(&var);
-       loblen = Z_STRLEN_P(var);
-       
-       if (loblen < 1) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Cannot save a lob that is less than 1 byte");
-               RETURN_FALSE;
-       }
-
-       CALL_OCI_RETURN(connection->error,
-               OCILobWrite(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       mylob, 
-                       (ub4 *) &loblen, 
-                       (ub4) offset, 
-                       (dvoid *) Z_STRVAL_P(var), 
-                       (ub4) loblen, 
-                       OCI_ONE_PIECE, 
-                       (dvoid *)0, 
-                       (sb4 (*)(dvoid *, dvoid *, ub4 *, ub1 *)) 0, 
-                       (ub2) 0, 
-                       (ub1) SQLCS_IMPLICIT
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCILobWrite", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
-       }
-
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_lob_close()
-   Closes lob descriptor */
-PHP_FUNCTION(oci_lob_close)
-{
-       zval *id;
-       int inx;
-       OCILobLocator *mylob;
-       oci_connection *connection;
-       oci_descriptor *descriptor;
-       int is_temporary;
-
-       if ((id = getThis()) != 0) {
-               inx = _oci_get_ocidesc(id,&descriptor TSRMLS_CC);
-               if (inx) {
-
-                       mylob = (OCILobLocator *) descriptor->ocidescr;
-
-                       if (!mylob) {
-                               RETURN_FALSE;
-                       }
-
-                       connection = descriptor->conn;
-
-                       CALL_OCI_RETURN(connection->error,
-                               OCILobClose(
-                                       connection->pServiceContext, 
-                                       connection->pError, 
-                                       mylob
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCILobClose", connection->error);
-                               oci_handle_error(connection, connection->error);
-                               RETURN_FALSE;
-                       }
-
-                       connection->error = 
-                               OCILobIsTemporary(connection->session->pEnv,
-                                                                       connection->pError,
-                                                                       mylob,
-                                                                       &is_temporary);
-                       if (is_temporary) {
-                               connection->error = 
-                                       OCILobFreeTemporary(connection->pServiceContext,
-                                                                               connection->pError,
-                                                                               mylob);
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCILobFreeTemporary", 
-                                                         connection->error);
-                                       oci_handle_error(connection, connection->error);
-                                       RETURN_FALSE;
-                               }
-                               oci_debug("oci_lob_free_temporary: descr=%d",inx);
-                       }
-
-                       oci_debug("oci_close_lob: descr=%d",inx);
-                       RETURN_TRUE;
-               }
-       }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_lob_close() should not be called like this. Use $somelob->close() to close a LOB");
-
-       RETURN_FALSE;
-}
-/* }}} */
-#endif 
-
-/* {{{ proto object oci_new_descriptor(resource connection [, int type])
-   Initialize a new empty descriptor LOB/FILE (LOB is default) */
-PHP_FUNCTION(oci_new_descriptor)
-{
-       zval **conn, **type;
-       oci_connection *connection;
-       oci_descriptor *descr;
-       int dtype;
-
-       dtype = OCI_DTYPE_LOB;
-
-       if (zend_get_parameters_ex(2, &conn, &type) == SUCCESS) {
-               convert_to_long_ex(type);
-               dtype = Z_LVAL_PP(type);
-       } else if (zend_get_parameters_ex(1, &conn) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       descr = oci_new_desc(dtype,connection);
-
-       if (!descr) {
-               RETURN_NULL();
-       }
-
-       object_init_ex(return_value, oci_lob_class_entry_ptr);
-       add_property_resource(return_value, "descriptor", descr->id);
-}
-/* }}} */
-
-/* {{{ proto bool oci_rollback(resource conn)
-   Rollback the current context */
-PHP_FUNCTION(oci_rollback)
-{
-       zval **conn;
-       oci_connection *connection;
-
-       if (zend_get_parameters_ex(1, &conn) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       if (connection->descriptors) {
-               zend_hash_apply(connection->descriptors,(apply_func_t) _oci_desc_flush_hash_dtor TSRMLS_CC);
-       }
-
-       oci_debug("<OCITransRollback");
-
-       CALL_OCI_RETURN(connection->error,
-               OCITransRollback(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       (ub4) 0
-               )
-       );
-
-       connection->needs_commit = 0;
-
-       oci_debug(">OCITransRollback");
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCIRollback", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
-       }
-       
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_commit(resource conn)
-   Commit the current context */
-PHP_FUNCTION(oci_commit)
-{
-       zval **conn;
-       oci_connection *connection;
-
-       if (zend_get_parameters_ex(1, &conn) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       if (connection->descriptors) {
-               zend_hash_apply(connection->descriptors,(apply_func_t) _oci_desc_flush_hash_dtor TSRMLS_CC);
-       }
-
-       oci_debug("<OCITransCommit");
-
-       CALL_OCI_RETURN(connection->error,
-               OCITransCommit(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       (ub4) 0
-               )
-       );
-
-       connection->needs_commit = 0;
-
-       oci_debug(">OCITransCommit");
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCICommit", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
-       }
-       
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto string oci_field_name(resource stmt, int col)
-   Tell the name of a column */
-PHP_FUNCTION(oci_field_name)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-
-       RETURN_STRINGL(outcol->name, outcol->name_len, 1);
-}
-/* }}} */
-
-/* {{{ proto int oci_field_size(resource stmt, int col)
-   Tell the maximum data size of a column */
-PHP_FUNCTION(oci_field_size)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-
-       oci_debug("oci_field_size: %16s, retlen = %4d, retlen4 = %d, data_size = %4d, storage_size4 = %4d, indicator %4d, retcode = %4d",
-                                 outcol->name,outcol->retlen,outcol->retlen4,outcol->data_size,outcol->storage_size4,outcol->indicator,outcol->retcode);
-               
-       /* Handle data type of LONG */
-       if (outcol->data_type == SQLT_LNG){
-               RETURN_LONG(outcol->storage_size4);
-       } else {
-               RETURN_LONG(outcol->data_size);
-       }
-}
-/* }}} */
-
-/* {{{ proto int oci_field_scale(resource stmt, int col)
-   Tell the scale of a column */
-PHP_FUNCTION(oci_field_scale)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-       RETURN_LONG(outcol->scale);
-}
-/* }}} */
-
-/* {{{ proto int oci_field_precision(resource stmt, int col)
-   Tell the precision of a column */
-PHP_FUNCTION(oci_field_precision)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-       RETURN_LONG(outcol->precision);
-}
-/* }}} */
-
-/* {{{ proto mixed oci_field_type(resource stmt, int col)
-   Tell the data type of a column */
-PHP_FUNCTION(oci_field_type)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-       
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-       switch (outcol->data_type) {
-#ifdef SQLT_TIMESTAMP
-               case SQLT_TIMESTAMP:
-                       RETVAL_STRING("TIMESTAMP",1);
-                       break;
-#endif
-#ifdef SQLT_TIMESTAMP_TZ
-               case SQLT_TIMESTAMP_TZ:
-                       RETVAL_STRING("TIMESTAMP_TZ",1);
-                       break;
-#endif
-               case SQLT_DAT:
-                       RETVAL_STRING("DATE",1);
-                       break;
-               case SQLT_NUM:
-                       RETVAL_STRING("NUMBER",1);
-                       break;
-               case SQLT_LNG:
-                       RETVAL_STRING("LONG",1);
-                       break;
-               case SQLT_BIN:
-                       RETVAL_STRING("RAW",1);
-                       break;
-               case SQLT_LBI:
-                       RETVAL_STRING("LONG RAW",1);
-                       break;
-               case SQLT_CHR:
-                       RETVAL_STRING("VARCHAR",1);
-                       break;
-               case SQLT_RSET:
-                       RETVAL_STRING("REFCURSOR",1);
-                       break;
-               case SQLT_AFC:
-                       RETVAL_STRING("CHAR",1);
-                       break;
-               case SQLT_BLOB:
-                       RETVAL_STRING("BLOB",1);
-                       break;
-               case SQLT_CLOB:
-                       RETVAL_STRING("CLOB",1);
-                       break;
-               case SQLT_BFILE:
-                       RETVAL_STRING("BFILE",1);
-                       break;
-               case SQLT_RDD:
-                       RETVAL_STRING("ROWID",1);
-                       break;
-               default:
-                       RETVAL_LONG(outcol->data_type);
-       }
-}
-/* }}} */
-
-/* {{{ proto int oci_field_type_raw(resource stmt, int col)
-   Tell the raw oracle data type of a column */
-PHP_FUNCTION(oci_field_type_raw)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-       
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-       RETVAL_LONG(outcol->data_type);
-}
-/* }}} */
-
-/* {{{ proto bool oci_field_is_null(resource stmt, int col)
-   Tell whether a column is NULL */
-PHP_FUNCTION(oci_field_is_null)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol;
-
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-       if (outcol == NULL) {
-               RETURN_FALSE;
-       }
-       if (outcol->indicator == -1) {
-               RETURN_TRUE;
-       } else {
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto void oci_internal_debug(int onoff)
-   Toggle internal debugging output for the OCI extension */
-PHP_FUNCTION(oci_internal_debug)
-{
-       zval **arg;
-
-       if (zend_get_parameters_ex(1, &arg) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-       convert_to_long_ex(arg);
-       OCI(debug_mode) = Z_LVAL_PP(arg);
-}
-/* }}} */
-
-/* {{{ proto bool oci_execute(resource stmt [, int mode])
-   Execute a parsed statement */
-PHP_FUNCTION(oci_execute)
-{
-       zval **stmt,**mode;
-       oci_statement *statement;
-       ub4 execmode;
-
-       if (zend_get_parameters_ex(2, &stmt, &mode) == SUCCESS) {
-               convert_to_long_ex(mode);
-               execmode = Z_LVAL_PP(mode);
-       } else if (zend_get_parameters_ex(1, &stmt) == SUCCESS) {
-               execmode = OCI_COMMIT_ON_SUCCESS;
-       } else {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       if (oci_execute(statement, "OCIExecute",execmode)) {
-               RETURN_TRUE;
-       } else {
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto bool oci_cancel(resource stmt)
-   Cancel reading from a cursor */
-PHP_FUNCTION(oci_cancel)
-{
-       zval **stmt;
-       oci_statement *statement;
-
-       if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       if (oci_fetch(statement, 0, "OCICancel" TSRMLS_CC)) {
-               RETURN_TRUE;
-       } else {
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto bool oci_fetch(resource stmt)
-   Prepare a new row of data for reading */
-PHP_FUNCTION(oci_fetch)
-{
-       zval **stmt;
-       oci_statement *statement;
-       ub4 nrows = 1; /* only one row at a time is supported for now */
-
-       if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       if (oci_fetch(statement, nrows, "OCIFetch" TSRMLS_CC)) {
-               RETURN_TRUE;
-       } else {
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto int ocifetchinto(resource stmt, array &output [, int mode])
-   Fetch a row of result data into an array */
-PHP_FUNCTION(ocifetchinto)
-{
-       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 3);
-}
-/* }}} */
-
-/* {{{ proto int oci_fetch_all(resource stmt, array &output[, int skip[, int maxrows[, int flags]]])
-   Fetch all rows of result data into an array */
-PHP_FUNCTION(oci_fetch_all)
-{
-       zval **stmt, **array, *element, **zskip, **zmaxrows, **zflags, *tmp;
-       oci_statement *statement;
-       oci_out_column **columns;
-       zval ***outarrs;
-       ub4 nrows = 1;
-       int i;
-       int skip = 0, maxrows = -1;
-       int flags = 0;
-       int rows = 0;
-       int ac = ZEND_NUM_ARGS();
-
-       if (ac < 2 || ac > 5 || zend_get_parameters_ex(ac, &stmt, &array, &zskip, &zmaxrows, &zflags) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-       
-       switch (ac) {
-               case 5:
-                       convert_to_long_ex(zflags);
-                       flags = Z_LVAL_PP(zflags);
-               case 4:
-                       convert_to_long_ex(zmaxrows);
-                       maxrows = Z_LVAL_PP(zmaxrows);
-               case 3:
-                       convert_to_long_ex(zskip);
-                       skip = Z_LVAL_PP(zskip);
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       zval_dtor(*array);
-       array_init(*array);
-
-       while (skip--) {
-               if (!oci_fetch(statement, nrows, "OCIFetchStatement" TSRMLS_CC)) {
-                       RETURN_LONG(0);
-               }
-       }
-
-       if (flags & OCI_FETCHSTATEMENT_BY_ROW) {
-               columns = safe_emalloc(statement->ncolumns, sizeof(oci_out_column *), 0);
-
-               for (i = 0; i < statement->ncolumns; i++) {
-                       columns[ i ] = oci_get_col(statement, i + 1, 0);
-               }
-
-               while (oci_fetch(statement, nrows, "OCIFetchStatement" TSRMLS_CC)) {
-                       zval *row;
-
-                       MAKE_STD_ZVAL(row);
-                       array_init(row);
-
-                       for (i = 0; i < statement->ncolumns; i++) {
-                               MAKE_STD_ZVAL(element);
-
-                               _oci_make_zval(element,statement,columns[ i ], "OCIFetchStatement",OCI_RETURN_LOBS TSRMLS_CC);
-
-                               if (flags & OCI_NUM) {
-                                       zend_hash_next_index_insert(Z_ARRVAL_P(row), &element, sizeof(zval*), NULL);
-                               } else { /* default to ASSOC */
-                                       zend_hash_update(Z_ARRVAL_P(row), 
-                                                       columns[ i ]->name, columns[ i ]->name_len+1, 
-                                                       &element, sizeof(zval*), NULL);
-                               }
-                       }
-
-                       zend_hash_next_index_insert(Z_ARRVAL_PP(array), &row, sizeof(zval*), NULL);
-
-                       rows++;
-
-                       if ((maxrows != -1) && (rows == maxrows)) {
-                               oci_fetch(statement, 0, "OCIFetchStatement" TSRMLS_CC);
-                               break;
-                       }
-               }
-               efree(columns);
-
-       } else { /* default to BY_COLUMN */
-               columns = safe_emalloc(statement->ncolumns, sizeof(oci_out_column *), 0);
-               outarrs = safe_emalloc(statement->ncolumns, sizeof(zval*), 0);
-               
-               if (flags & OCI_NUM) {
-                       for (i = 0; i < statement->ncolumns; i++) {
-                               columns[ i ] = oci_get_col(statement, i + 1, 0);
-                               
-                               MAKE_STD_ZVAL(tmp);
-                               array_init(tmp);
-                                               
-                               zend_hash_next_index_insert(Z_ARRVAL_PP(array), 
-                                               &tmp, sizeof(zval*), (void **) &(outarrs[ i ]));
-                       }
-               } else { /* default to ASSOC */
-                       for (i = 0; i < statement->ncolumns; i++) {
-                               columns[ i ] = oci_get_col(statement, i + 1, 0);
-                               
-                               MAKE_STD_ZVAL(tmp);
-                               array_init(tmp);
-                                               
-                               zend_hash_update(Z_ARRVAL_PP(array), 
-                                               columns[ i ]->name, columns[ i ]->name_len+1, 
-                                               (void *) &tmp, sizeof(zval*), (void **) &(outarrs[ i ]));
-                       }
-               }
-
-               while (oci_fetch(statement, nrows, "OCIFetchStatement" TSRMLS_CC)) {
-                       for (i = 0; i < statement->ncolumns; i++) {
-                               MAKE_STD_ZVAL(element);
-
-                               _oci_make_zval(element,statement,columns[ i ], "OCIFetchStatement",OCI_RETURN_LOBS TSRMLS_CC);
-
-                               zend_hash_index_update((*(outarrs[ i ]))->value.ht, rows, (void *)&element, sizeof(zval*), NULL);
-                       }
-
-                       rows++;
-
-                       if ((maxrows != -1) && (rows == maxrows)) {
-                               oci_fetch(statement, 0, "OCIFetchStatement" TSRMLS_CC);
-                               break;
-                       }
-               }
-               
-               efree(columns);
-               efree(outarrs);
-       } 
-
-       RETURN_LONG(rows);
-}
-/* }}} */
-
-/* {{{ proto object oci_fetch_object( resource stmt )
-   Fetch a result row as an object */
-PHP_FUNCTION(oci_fetch_object)
-{
-       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, OCI_ASSOC, 2);
-
-       if (Z_TYPE_P(return_value) == IS_ARRAY) {
-               object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
-       }
-}
-/* }}} */
-
-/* {{{ proto array oci_fetch_row( resource stmt )
-   Fetch a result row as an enumerated array */
-PHP_FUNCTION(oci_fetch_row)
-{
-       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, OCI_NUM, 1);
-}
-/* }}} */
-
-/* {{{ proto array oci_fetch_assoc( resource stmt )
-   Fetch a result row as an associative array */
-PHP_FUNCTION(oci_fetch_assoc)
-{
-       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, OCI_ASSOC, 1);
-}
-/* }}} */
-
-/* {{{ proto array oci_fetch_array( resource stmt [, int mode ])
-   Fetch a result row as an array */
-PHP_FUNCTION(oci_fetch_array)
-{
-       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, OCI_BOTH, 2);
-}
-/* }}} */
-
-/* {{{ proto bool oci_free_statement(resource stmt)
-   Free all resources associated with a statement */
-PHP_FUNCTION(oci_free_statement)
-{
-       zval **stmt;
-       oci_statement *statement;
-
-       if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       zend_list_delete(statement->id);
-
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_close(resource conn)
-   Disconnect from database */
-PHP_FUNCTION(oci_close)
-{
-#if 0
-       this function does nothing any more. server-connections get automagiclly closed on 
-       request-end. connection handles will "dissappear" as soon as they are no longer 
-       referenced. as this module makes heavy use of zends reference-counting mechanism
-       this is the desired behavior. it has always been a bad idea to close a connection that
-       has outstanding transactions. this way we have a nice-clean approach.
-       (thies@thieso.net 20000110)
-
-       oci_connection *connection;
-       zval **conn;
-
-       if (zend_get_parameters_ex(1, &conn) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       connection->is_open = 0;
-
-       zend_hash_apply(list, (apply_func_t) _stmt_cleanup TSRMLS_CC);
-
-       if (zend_list_delete(connection->id) == SUCCESS) {
-               RETURN_TRUE;
-       } else {
-               RETURN_FALSE;
-       }
-#endif
-}
-/* }}} */
-
-/* {{{ proto resource oci_new_connect(string user, string pass [, string db])
-   Connect to an Oracle database and log on. Returns a new session. */
-PHP_FUNCTION(oci_new_connect)
-{
-       oci_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
-}
-/* }}} */
-
-/* {{{ proto resource oci_connect(string user, string pass [, string db])
-   Connect to an Oracle database and log on. Returns a new session. */
-PHP_FUNCTION(oci_connect)
-{
-       oci_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
-}
-/* }}} */
-
-/* {{{ proto resource oci_pconnect(string user, string pass [, string db])
-   Connect to an Oracle database using a persistent connection and log on. Returns a new session. */
-PHP_FUNCTION(oci_pconnect)
-{
-       oci_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU,1,0);
-}
-/* }}} */
-
-/* {{{ proto array oci_error([resource stmt|conn|global])
-   Return the last error of stmt|conn|global. If no error happened returns false. */
-PHP_FUNCTION(oci_error)
-{
-       zval **arg;
-       oci_statement *statement;
-       oci_connection *connection;
-       text errbuf[512];
-       sb4 errcode = 0;
-       sword error = 0;
-       dvoid *errh = NULL;
-#ifdef HAVE_OCI8_ATTR_STATEMENT
-       ub2 errorofs = 0;
-       text *sqltext = NULL;
-#endif
-
-       if (zend_get_parameters_ex(1, &arg) == SUCCESS) {
-               statement = (oci_statement *) zend_fetch_resource(arg TSRMLS_CC, -1, NULL, NULL, 1, le_stmt);
-               if (statement) {
-                       errh = statement->pError;
-                       error = statement->error;
-
-#ifdef HAVE_OCI8_ATTR_STATEMENT
-                       CALL_OCI_RETURN(statement->error,
-                               OCIAttrGet(
-                                       (dvoid *)statement->pStmt,
-                                       OCI_HTYPE_STMT,
-                                       (text *) &sqltext,
-                                       (ub4 *)0,
-                                       OCI_ATTR_STATEMENT,
-                                       statement->pError
-                               )
-                       );
-
-                       CALL_OCI_RETURN(statement->error,
-                               OCIAttrGet(
-                                       (dvoid *)statement->pStmt,
-                                       OCI_HTYPE_STMT,
-                                       (ub2 *)&errorofs,
-                                       (ub4 *)0,
-                                       OCI_ATTR_PARSE_ERROR_OFFSET,
-                                       statement->pError
-                               )
-                       );
-#endif
-
-               } else {
-                       connection = (oci_connection *) zend_fetch_resource(arg TSRMLS_CC, -1, NULL, NULL, 1, le_conn);
-                       if (connection) {
-                               errh = connection->pError;
-                               error = connection->error;
-                       }
-               }
-       } else {
-               errh = OCI(pError);
-               error = OCI(error);
-       }
-
-       if (!error) { /* no error set in the handle */
-               RETURN_FALSE;
-       }
-
-       if (!errh) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCIError: unable to find Error handle");
-               RETURN_FALSE;
-       }
-
-       CALL_OCI(
-               OCIErrorGet(
-                       errh,
-                       1,
-                       NULL,
-                       &errcode,
-                       errbuf,
-                       (ub4) sizeof(errbuf),
-                       (ub4) OCI_HTYPE_ERROR
-               )
-       );
-
-       if (errcode) {
-               array_init(return_value);
-               add_assoc_long(return_value, "code", errcode);
-               add_assoc_string(return_value, "message", (char*) errbuf, 1);
-#ifdef HAVE_OCI8_ATTR_STATEMENT
-               add_assoc_long(return_value, "offset", errorofs);
-               add_assoc_string(return_value, "sqltext", sqltext ? (char *) sqltext : "", 1);
-#endif
-       } else {
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto int oci_num_fields(resource stmt)
-   Return the number of result columns in a statement */
-PHP_FUNCTION(oci_num_fields)
-{
-       zval **stmt;
-       oci_statement *statement;
-
-       if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       RETURN_LONG(statement->ncolumns);
-}
-/* }}} */
-
-/* {{{ proto resource oci_parse(resource conn, string query)
-   Parse a query and return a statement */
-PHP_FUNCTION(oci_parse)
-{
-       zval **conn, **query;
-       oci_connection *connection;
-       oci_statement *statement;
-
-       if (zend_get_parameters_ex(2, &conn, &query) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       convert_to_string_ex(query);
-
-       statement = oci_parse(connection,Z_STRVAL_PP(query),Z_STRLEN_PP(query));
-
-       if (statement) {
-               RETURN_RESOURCE(statement->id);
-       } else {
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto bool oci_set_prefetch(resource stmt, int prefetch_rows)
-  Sets the number of rows to be prefetched on execute to prefetch_rows for stmt */
-PHP_FUNCTION(oci_set_prefetch)
-{
-       zval **stmt, **size;
-       oci_statement *statement;
-
-       if (zend_get_parameters_ex(2, &stmt, &size) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       convert_to_long_ex(size);
-
-       OCI_GET_STMT(statement,stmt);
-
-       oci_setprefetch(statement,Z_LVAL_PP(size)); 
-
-       RETURN_TRUE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_password_change(resource conn, string username, string old_password, string new_password)
-  Changes the password of an account */
-PHP_FUNCTION(oci_password_change)
-{
-       zval **conn, **user_param, **pass_old_param, **pass_new_param;
-       text *user, *pass_old, *pass_new;
-       oci_connection *connection;
-
-       /*  Disable in Safe Mode  */
-       if (PG(safe_mode)) {
-               php_error_docref(NULL TSRMLS_CC, E_WARNING, "is disabled in Safe Mode");
-               RETURN_FALSE;
-       }
-
-       if (zend_get_parameters_ex(4, &conn, &user_param, &pass_old_param, &pass_new_param) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       convert_to_string_ex(user_param);
-       convert_to_string_ex(pass_old_param);
-       convert_to_string_ex(pass_new_param);
-       
-       user      = Z_STRVAL_PP(user_param);
-       pass_old  = Z_STRVAL_PP(pass_old_param);
-       pass_new  = Z_STRVAL_PP(pass_new_param);
-
-       OCI_GET_CONN(connection, conn);
-
-       CALL_OCI_RETURN(connection->error,
-               OCIPasswordChange(
-                       connection->pServiceContext,
-                       connection->pError,
-                       user,
-                       strlen(user)+1,
-                       pass_old,
-                       strlen(pass_old)+1,
-                       pass_new,
-                       strlen(pass_new)+1,
-                       OCI_DEFAULT
-               )
-       );
-
-       if (connection->error == OCI_SUCCESS) {
-               RETURN_TRUE;
-       } else {
-               oci_error(connection->pError, "OCIPasswordChange", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
-       }
-}
-/* }}} */
-
-/* {{{ proto resource oci_new_cursor(resource conn)
-   Return a new cursor (Statement-Handle) - use this to bind ref-cursors! */
-PHP_FUNCTION(oci_new_cursor)
-{
-       zval **conn;
-       oci_connection *connection;
-       oci_statement *statement;
-
-       if (zend_get_parameters_ex(1, &conn) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       statement = oci_parse(connection,0,0);
-       
-       RETURN_RESOURCE(statement->id);
-}
-/* }}} */
-
-/* {{{ proto string oci_result(resource stmt, mixed column)
-   Return a single column of result data */
-PHP_FUNCTION(oci_result)
-{
-       zval **stmt, **col;
-       oci_statement *statement;
-       oci_out_column *outcol = NULL;
-
-       if (zend_get_parameters_ex(2, &stmt, &col) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_STMT(statement,stmt);
-
-       outcol = oci_get_col(statement, -1, col);
-
-       if (outcol == NULL) {
-               RETURN_FALSE;
+       else if (!exclusive) {
+               new_le.type = le_index_ptr;
+               connection->rsrc_id = zend_list_insert(connection, le_connection);
+               zend_hash_update(&EG(regular_list), connection->hash_key, strlen(connection->hash_key)+1, (void *)&new_le, sizeof(list_entry), NULL);
+               OCI_G(num_links)++;
        }
-
-       _oci_make_zval(return_value,statement,outcol, "OCIResult",0 TSRMLS_CC);
+       else {
+               connection->rsrc_id = zend_list_insert(connection, le_connection);      
+               OCI_G(num_links)++;
+       }
+       return connection;
 }
 /* }}} */
 
-/* {{{ proto string oci_server_version(resource conn)
  Return a string containing server version information */
-PHP_FUNCTION(oci_server_version)
+/* {{{ php_oci_connection_ping()
* Ping connection. Uses OCIPing() or OCIServerVersion() depending on the Oracle Client version */
+static int php_oci_connection_ping(php_oci_connection *connection TSRMLS_DC)
 {
-       oci_connection *connection;
-       zval **conn;
+#if OCI_MAJOR_VERSION >= 10 && OCI_MINOR_VERSION >= 2
+       /* OCIPing() is usable only in 10.2 */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIPing, (connection->svc, OCI_G(err), OCI_DEFAULT));
+#else
        char version[256];
-
-       if (zend_get_parameters_ex(1, &conn) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
-
-       OCI_GET_CONN(connection,conn);
-
-       CALL_OCI_RETURN(connection->error,
-               OCIServerVersion(
-                       connection->pServiceContext,
-                       connection->pError, 
-                       (text*)version, 
-                       sizeof(version), 
-                       OCI_HTYPE_SVCCTX
-               )
-       );
+       /* use good old OCIServerVersion() by default */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIServerVersion, (connection->server, OCI_G(err), (text*)version, sizeof(version), OCI_HTYPE_SERVER));
+#endif
        
-       if (connection->error != OCI_SUCCESS) {
-               oci_error(connection->pError, "OCIServerVersion", connection->error);
-               oci_handle_error(connection, connection->error);
-               RETURN_FALSE;
+       if (OCI_G(errcode) == OCI_SUCCESS) {
+               return 1;
        }
 
-       RETURN_STRING(version,1);
+       /* ignore errors here, just return failure 
+        * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
+       return 0;
 }
 /* }}} */
 
-/* {{{ proto string oci_statement_type(resource stmt)
-   Return the query type of an OCI statement */
-/* XXX it would be better with a general interface to OCIAttrGet() */
-PHP_FUNCTION(oci_statement_type)
+/* {{{ php_oci_connection_status()
+ Check connection status (pre-ping check) */
+static int php_oci_connection_status(php_oci_connection *connection TSRMLS_DC)
 {
-       zval **stmt;
-       oci_statement *statement;
-       ub2 stmttype;
-
-       if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
+       ub4 ss = 0;
 
-       OCI_GET_STMT(statement,stmt);
-
-       CALL_OCI_RETURN(statement->error,
-               OCIAttrGet(
-                       (dvoid *)statement->pStmt, 
-                       OCI_HTYPE_STMT, 
-                       (ub2 *)&stmttype, 
-                       (ub4 *)0, 
-                       OCI_ATTR_STMT_TYPE, 
-                       statement->pError
-               )
-       );
-
-       if (statement->error != OCI_SUCCESS) {
-               oci_error(statement->pError, "OCIStatementType", statement->error);
-               oci_handle_error(statement->conn, statement->error);
-               RETURN_FALSE;
+       /* get OCI_ATTR_SERVER_STATUS */
+       OCI_G(errcode) = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)connection->server, OCI_HTYPE_SERVER, (dvoid *)&ss, (ub4 *)0, OCI_ATTR_SERVER_STATUS, OCI_G(err)));
+       
+       if (OCI_G(errcode) == OCI_SUCCESS && ss == OCI_SERVER_NORMAL) {
+               return 1;
        }
 
-       switch (stmttype) {
-               case OCI_STMT_SELECT:
-                       RETVAL_STRING("SELECT",1);
-                       break;
-               case OCI_STMT_UPDATE:
-                       RETVAL_STRING("UPDATE",1);
-                       break;
-               case OCI_STMT_DELETE:
-                       RETVAL_STRING("DELETE",1);
-                       break;
-               case OCI_STMT_INSERT:
-                       RETVAL_STRING("INSERT",1);
-                       break;
-               case OCI_STMT_CREATE:
-                       RETVAL_STRING("CREATE",1);
-                       break;
-               case OCI_STMT_DROP:
-                       RETVAL_STRING("DROP",1);
-                       break;
-               case OCI_STMT_ALTER:
-                       RETVAL_STRING("ALTER",1);
-                       break;
-               case OCI_STMT_BEGIN:
-                       RETVAL_STRING("BEGIN",1);
-                       break;
-               case OCI_STMT_DECLARE:
-                       RETVAL_STRING("DECLARE",1);
-                       break;
-               default:
-                       RETVAL_STRING("UNKNOWN",1);
-       }
+       /* ignore errors here, just return failure 
+        * php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC); */
+       return 0;
 }
 /* }}} */
 
-/* {{{ proto int oci_num_rows(resource stmt)
  Return the row count of an OCI statement */
-PHP_FUNCTION(oci_num_rows)
+/* {{{ php_oci_connection_rollback()
Rollback connection */
+int php_oci_connection_rollback(php_oci_connection *connection TSRMLS_DC)
 {
-       zval **stmt;
-       oci_statement *statement;
-       ub4 rowcount;
-
-       if (zend_get_parameters_ex(1, &stmt) == FAILURE) {
-               WRONG_PARAM_COUNT;
-       }
+       connection->errcode = PHP_OCI_CALL(OCITransRollback, (connection->svc, connection->err, (ub4) 0));
+       connection->needs_commit = 0;
 
-       OCI_GET_STMT(statement,stmt);
-
-       CALL_OCI_RETURN(statement->error,
-               OCIAttrGet(
-                       (dvoid *)statement->pStmt, 
-                       OCI_HTYPE_STMT, 
-                       (ub2 *)&rowcount, 
-                       (ub4 *)0, 
-                       OCI_ATTR_ROW_COUNT,
-                       statement->pError
-               )
-       );
-
-       if (statement->error != OCI_SUCCESS) {
-               oci_error(statement->pError, "OCIRowCount", statement->error);
-               oci_handle_error(statement->conn, statement->error);
-               RETURN_FALSE;
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
        }
+       return 0;
+} /* }}} */
 
-       RETURN_LONG(rowcount);
-}
-/* }}} */
-
-#ifdef PHP_OCI8_HAVE_COLLECTIONS
-/* {{{ oci_get_coll() */
-static oci_collection *oci_get_coll(int ind TSRMLS_DC)
+/* {{{ php_oci_connection_commit()
+ Commit connection */
+int php_oci_connection_commit(php_oci_connection *connection TSRMLS_DC)
 {
-       oci_collection *collection;
-       int actual_resource_type;
-
-       collection = (oci_collection *) zend_list_find(ind, &actual_resource_type);
-
-       if (collection && (actual_resource_type == le_coll)) {
-               return collection;
-       } else {
-               return (oci_collection *) NULL;
+       if (connection->descriptors) {
+               zend_hash_apply(connection->descriptors,(apply_func_t) php_oci_descriptor_flush_hash_dtor TSRMLS_CC);
        }
-}
-/* }}} */
 
-/* {{{ proto bool oci_free_collection()
-   Deletes collection object*/
-PHP_FUNCTION(oci_free_collection)
-{
-       zval *id;
-       int inx;
-       oci_collection *coll;
-       oci_connection *connection;
-       
-       if ((id = getThis()) != 0) {
-               inx = _oci_get_ocicoll(id,&coll TSRMLS_CC);
-               if (inx) {
-                       /*
-                        * Do we need to free the object?
-                        * 
-                        */
-                       connection = coll->conn;
-                       oci_debug("oci_free_collection: coll=%d",inx);
-
-                       CALL_OCI_RETURN(connection->error,
-                               OCIObjectFree(
-                                       connection->session->pEnv, 
-                                       connection->pError, 
-                                       (dvoid *)coll->coll, 
-                                       (ub2)(OCI_OBJECTFREE_FORCE)
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCIObjectFree", connection->error);
-                               RETURN_FALSE;
-                       }
+       connection->errcode = PHP_OCI_CALL(OCITransCommit, (connection->svc, connection->err, (ub4) 0));
+       connection->needs_commit = 0;
 
-                       zend_list_delete(inx);
-                       RETURN_TRUE;
-               }
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
        }
+       return 0;
+} /* }}} */
 
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_collection_append(string value)
-   Append an object to the collection */
-PHP_FUNCTION(oci_collection_append)
+/* {{{ php_oci_connection_close() 
+ Close the connection and free all its resources */
+static int php_oci_connection_close(php_oci_connection *connection TSRMLS_DC)
 {
-       zval *id, **arg;
-       oci_connection *connection;
-       oci_collection *coll;
-       OCINumber num;
-       OCIString *ocistr = (OCIString *)0;
-       OCIInd new_ind = OCI_IND_NOTNULL;
-       OCIInd null_ind = OCI_IND_NULL;
-       OCIDate dt;
-       int inx;
-       double ndx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
+       int result = 0;
 
-               connection = coll->conn;
-               if (zend_get_parameters_ex(1, &arg) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
+       if (connection->descriptors) {
+               zend_hash_destroy(connection->descriptors);
+               efree(connection->descriptors);
+       }
 
-               /* 
-                * Handle NULLS.  For consistency with the rest of the OCI8 library, when
-                * a value passed in is a 0 length string, consider it a null
-                */
-               convert_to_string_ex(arg);
-               if (Z_STRLEN_PP(arg) == 0) {
-                       CALL_OCI_RETURN(connection->error,
-                               OCICollAppend(
-                                       connection->session->pEnv, 
-                                       connection->pError, 
-                                       (dvoid *)0, 
-                                       &null_ind, 
-                                       coll->coll
-                               )
-                       );
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCICollAppend - NULL", connection->error);
-                               RETURN_FALSE;
+       if (connection->svc) {  
+               /* rollback outstanding transactions */
+               if (connection->needs_commit) {
+                       if (php_oci_connection_rollback(connection TSRMLS_CC)) {
+                               /* rollback failed */
+                               result = 1;
                        }
-
-                       RETURN_TRUE;
                }
+       }
 
-               switch(coll->element_typecode) {
-                       case OCI_TYPECODE_DATE:
-                               convert_to_string_ex(arg);
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCIDateFromText(
-                                               connection->pError, 
-                                               Z_STRVAL_PP(arg), 
-                                               Z_STRLEN_PP(arg), 
-                                               0,
-                                               0,
-                                               0,
-                                               0,
-                                               &dt
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCIDateFromText", connection->error);
-                                       RETURN_FALSE;
-                               }
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCICollAppend(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               (dvoid *) &dt, 
-                                               (dvoid *) &new_ind, 
-                                               (OCIColl *) coll->coll
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCICollAppend", connection->error);
-                                       RETURN_FALSE;
-                               }
-                               RETURN_TRUE;
-                               break;
-                       case OCI_TYPECODE_VARCHAR2 :
-                               convert_to_string_ex(arg);
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCIStringAssignText(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               Z_STRVAL_PP(arg), 
-                                               Z_STRLEN_PP(arg), 
-                                               &ocistr
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCIStringAssignText", connection->error);
-                                       RETURN_FALSE;
-                               }
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCICollAppend(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               (dvoid *) ocistr, 
-                                               (dvoid *) &new_ind, 
-                                               (OCIColl *) coll->coll
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCICollAppend", connection->error);
-                                       RETURN_FALSE;
-                               }
-                               RETURN_TRUE;
-                               break;
-                       case OCI_TYPECODE_UNSIGNED16 :                       /* UNSIGNED SHORT  */
-                       case OCI_TYPECODE_UNSIGNED32 :                        /* UNSIGNED LONG  */
-                       case OCI_TYPECODE_REAL :                                     /* REAL    */
-                       case OCI_TYPECODE_DOUBLE :                                   /* DOUBLE  */
-                       case OCI_TYPECODE_INTEGER :                                     /* INT  */
-                       case OCI_TYPECODE_SIGNED16 :                                  /* SHORT  */
-                       case OCI_TYPECODE_SIGNED32 :                                   /* LONG  */
-                       case OCI_TYPECODE_DECIMAL :                                 /* DECIMAL  */
-                       case OCI_TYPECODE_FLOAT :                                   /* FLOAT    */
-                       case OCI_TYPECODE_NUMBER :                                  /* NUMBER   */
-                       case OCI_TYPECODE_SMALLINT :                                /* SMALLINT */
-                               convert_to_double_ex(arg);
-                               ndx = (double)Z_DVAL_PP(arg);
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCINumberFromReal(
-                                               connection->pError,
-                                               &ndx, 
-                                               sizeof(double),
-                                               &num
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCINumberFromReal", connection->error);
-                                       RETURN_FALSE;
-                               }
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCICollAppend(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               (dvoid *) &num, 
-                                               (dvoid *) &new_ind, 
-                                               (OCIColl *) coll->coll
-                                       )
-                               );
-
-                               RETURN_TRUE;
-                               break;
-                       default:
-                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or unsupported type of element");
-                               RETURN_FALSE;
-                               break;
-               }
+       if (connection->is_attached) {
+               PHP_OCI_CALL(OCIServerDetach, (connection->server, OCI_G(err), OCI_DEFAULT));
        }
        
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_append() should not be called like this. Use $collection->append($element) to append an element to the collection");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto string oci_collection_element_get(int ndx)
-   Retrieve the value at collection index ndx */
-PHP_FUNCTION(oci_collection_element_get)
-{
-       zval *id,**arg;
-       oci_connection *connection;
-       oci_collection *coll;
-       ub4  ndx;
-       int inx;
-       dvoid *elem;
-       OCIInd *elemind;
-       boolean exists;
-       OCIString *ocistr = (OCIString *)0;
-       text *str;
-       char buff[1024];
-       int len;
-       double dnum;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               if (zend_get_parameters_ex(1, &arg) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
+       if (connection->err) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->err, (ub4) OCI_HTYPE_ERROR));
+       }
 
-               convert_to_long_ex(arg);
-               ndx = Z_LVAL_PP(arg);
-
-               connection = coll->conn;
-
-               CALL_OCI_RETURN(connection->error,
-                       OCICollGetElem(
-                               connection->session->pEnv, 
-                               connection->pError, 
-                               coll->coll, 
-                               ndx, 
-                               &exists, 
-                               &elem, 
-                               (dvoid **)&elemind
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCICollGetElem", connection->error);
-                       RETURN_NULL();
+       if (connection->session) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->session, OCI_HTYPE_SESSION));
+       }
+       
+       if (connection->server) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->server, (ub4) OCI_HTYPE_SERVER));
+       }
+       
+       if (connection->svc) {
+               if (connection->session && connection->is_open) {
+                       PHP_OCI_CALL(OCISessionEnd, (connection->svc, OCI_G(err), connection->session, (ub4) 0));
                }
+       
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->svc, (ub4) OCI_HTYPE_SVCCTX));
+       }
                
-               /* Return false if value does not exist at that location */
-               if (exists == 0) {
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCICollGetElem - Invalid index %d", ndx);
-                       RETURN_FALSE;
-               }
-
-               /* Return null if the value is null */
-               if (*elemind == OCI_IND_NULL) {
-                       RETURN_NULL();
-               } 
+       if (connection->env) {
+               PHP_OCI_CALL(OCIHandleFree, ((dvoid *) connection->env, OCI_HTYPE_ENV));
+       }
 
-               switch (coll->element_typecode) {
-                       case OCI_TYPECODE_DATE:
-                               len = 1024;
-                               CALL_OCI(
-                                       OCIDateToText(
-                                               connection->pError, 
-                                               elem, 
-                                               0, /* fmt */ 
-                                               0, /* fmt_length */ 
-                                               0, /* lang_name */ 
-                                               0, /* lang_length */ 
-                                               &len,
-                                               buff
-                                       )
-                               );
-
-                               RETURN_STRINGL(buff,len,1);
-                       case OCI_TYPECODE_VARCHAR2 :
-                               ocistr = *(OCIString **)elem;
-                               str = OCIStringPtr(connection->session->pEnv,ocistr); /* XXX not protected against recursion! */
-                               RETURN_STRINGL(str,strlen(str),1);
-                               break;
-                       case OCI_TYPECODE_UNSIGNED16 :                       /* UNSIGNED SHORT  */
-                       case OCI_TYPECODE_UNSIGNED32 :                       /* UNSIGNED LONG  */
-                       case OCI_TYPECODE_REAL :                             /* REAL    */
-                       case OCI_TYPECODE_DOUBLE :                           /* DOUBLE  */
-                       case OCI_TYPECODE_INTEGER :                          /* INT  */
-                       case OCI_TYPECODE_SIGNED16 :                         /* SHORT  */
-                       case OCI_TYPECODE_SIGNED32 :                         /* LONG  */
-                       case OCI_TYPECODE_DECIMAL :                          /* DECIMAL  */
-                       case OCI_TYPECODE_FLOAT :                            /* FLOAT    */
-                       case OCI_TYPECODE_NUMBER :                           /* NUMBER   */
-                       case OCI_TYPECODE_SMALLINT :                         /* SMALLINT */
-                               CALL_OCI_RETURN(connection->error,
-                                       OCINumberToReal(
-                                               connection->pError, 
-                                               (CONST OCINumber *) elem, 
-                                               (uword) sizeof(dnum), 
-                                               (dvoid *) &dnum
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCINumberToReal", connection->error);
-                                       RETURN_FALSE;
-                               }
-                               RETURN_DOUBLE(dnum);
-                               break;
-                       default:
-                               php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or unsupported type of element");
-                               RETURN_FALSE;
-                               break;
+       if (connection->is_persistent) {
+               if (connection->hash_key) {
+                       free(connection->hash_key);
                }
+               free(connection);
        }
+       else {
+               if (connection->hash_key) {
+                       efree(connection->hash_key);
+               }
+               efree(connection);
+       }
+       connection = NULL;
+       return result;
+} /* }}} */
 
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_element_get() should not be called like this. Use $collection->getelem($index) to get an element of the collection with the given index");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_collection_assign(object from)
-   Assign a collection from another existing collection */
-PHP_FUNCTION(oci_collection_assign)
+/* {{{ php_oci_password_change()
+ Change password for the user with the username given */
+int php_oci_password_change(php_oci_connection *connection, char *user, long user_len, char *pass_old, long pass_old_len, char *pass_new, long pass_new_len TSRMLS_DC)
 {
-       zval *id,**from;
-       oci_connection *connection;
-       oci_collection *coll,*from_coll;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
+       connection->errcode = PHP_OCI_CALL(OCIPasswordChange, (connection->svc, connection->err, (text *)user, user_len+1, (text *)pass_old, pass_old_len+1, (text *)pass_new, pass_new_len+1, OCI_DEFAULT));
 
-               if (zend_get_parameters_ex(1, &from) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       return 0;
+} /* }}} */
 
-               if ((inx = _oci_get_ocicoll(*from,&from_coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
+/* {{{ php_oci_server_get_version() 
+ Get Oracle server version */
+int php_oci_server_get_version(php_oci_connection *connection, char **version TSRMLS_DC) 
+{
+       char version_buff[256];
 
-               connection = coll->conn;
+       connection->errcode = PHP_OCI_CALL(OCIServerVersion, (connection->svc, connection->err, (text*)version_buff, sizeof(version_buff), OCI_HTYPE_SVCCTX));
        
-               CALL_OCI_RETURN(connection->error,
-                       OCICollAssign(
-                               connection->session->pEnv,
-                               connection->pError, 
-                               from_coll->coll,
-                               coll->coll
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCICollAssignElem", connection->error);
-                       RETURN_FALSE;
-               }
-               RETURN_TRUE;
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
        }
+       
+       *version = estrdup(version_buff);
+       return 0;
+} /* }}} */
 
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_assign() should not be called like this. Use $collection->assign($collection_value) to assign value to the collection");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_collection_element_assign(int index, string val)
-   Assign element val to collection at index ndx */
-PHP_FUNCTION(oci_collection_element_assign)
+/* {{{ php_oci_column_to_zval() 
+ Convert php_oci_out_column struct into zval */
+int php_oci_column_to_zval(php_oci_out_column *column, zval *value, int mode TSRMLS_DC)
 {
-       zval *id,**index,**val;
-       oci_connection *connection;
-       oci_collection *coll;
-       OCINumber num;
-       OCIInd new_ind = OCI_IND_NOTNULL;
-       OCIInd null_ind = OCI_IND_NULL;
-       ub4  ndx;
-       int inx;
-       OCIString *ocistr = (OCIString *)0;
-       OCIDate dt;
-       double  dnum;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-
-               if (zend_get_parameters_ex(2, &index,&val) == FAILURE) {
-                       WRONG_PARAM_COUNT;
-               }
-
-               convert_to_long_ex(index);
-               ndx = Z_LVAL_PP(index);
-
-               connection = coll->conn;
+       php_oci_descriptor *descriptor;
+       ub4 lob_length;
+       int column_size;
+       char *lob_buffer;
+       
+       if (column->indicator == -1) { /* column is NULL */ 
+               ZVAL_NULL(value); 
+               return 0;
+       }
+       
+       if (column->is_cursor) { /* REFCURSOR -> simply return the statement id */
+               ZVAL_RESOURCE(value, column->stmtid);
+               zend_list_addref(column->stmtid);
+       } 
+       else if (column->is_descr) {
+               
+               if (column->data_type != SQLT_RDD) {
+                       int rsrc_type;
+                       
+                       /* reset descriptor's length */
+                       descriptor = (php_oci_descriptor *) zend_list_find(column->descid, &rsrc_type);
 
-               if (connection->error) {
-                       oci_error(connection->pError, "OCICollAssignElem", connection->error);
-                       RETURN_FALSE;
+                       if (!descriptor || rsrc_type != le_descriptor) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find LOB descriptor #%d", column->descid);
+                               return 1;
+                       }
+                                                                 
+                       descriptor->lob_size = -1;
+                       descriptor->lob_current_position = 0;
+                       descriptor->buffering = 0;
                }
 
-               /* 
-                * Handle NULLs.  For consistency with the rest of the OCI8 library, when
-                * a value passed in is a 0 length string, consider it a null
-                */
-               convert_to_string_ex(val);
-
-               if (Z_STRLEN_PP(val) == 0) {
-                       CALL_OCI_RETURN(connection->error,
-                               OCICollAssignElem(
-                                       connection->session->pEnv, 
-                                       connection->pError, 
-                                       ndx, 
-                                       (dvoid *)0, 
-                                       &null_ind, 
-                                       coll->coll
-                               )
-                       );
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCICollAssignElem - NULL", connection->error);
-                               RETURN_FALSE;
+               if (column->data_type != SQLT_RDD && (mode & PHP_OCI_RETURN_LOBS)) {
+                       /* PHP_OCI_RETURN_LOBS means that we want the content of the LOB back instead of the locator */
+                       
+                       if (php_oci_lob_read(descriptor, -1, 0, &lob_buffer, &lob_length TSRMLS_CC)) {
+                               ZVAL_FALSE(value);
+                               return 1;
+                       } else {
+                               ZVAL_STRINGL(value, lob_buffer, lob_length, 0);
+                               return 0;
                        }
-
-                       RETURN_TRUE;
+               } else { 
+                       /* return the locator */
+                       object_init_ex(value, oci_lob_class_entry_ptr);
+                       add_property_resource(value, "descriptor", column->descid);
+                       zend_list_addref(column->descid);
                }
-
-               switch (coll->element_typecode) {
-                       case OCI_TYPECODE_DATE:
-                               convert_to_string_ex(val);
-                               CALL_OCI_RETURN(connection->error,
-                                       OCIDateFromText(
-                                               connection->pError, 
-                                               Z_STRVAL_PP(val), 
-                                               Z_STRLEN_PP(val), 
-                                               0,
-                                               0,
-                                               0,
-                                               0,
-                                               &dt
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCIDateFromText", connection->error);
-                                       RETURN_FALSE;
-                               }
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCICollAssignElem(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               ndx, 
-                                               (dvoid *)&dt, 
-                                               &new_ind, 
-                                               coll->coll
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCICollAssignElem", connection->error);
-                                       RETURN_FALSE;
-                               }
-                               break;
-                       case OCI_TYPECODE_VARCHAR2 :
-                               convert_to_string_ex(val);
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCIStringAssignText(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               Z_STRVAL_PP(val), 
-                                               Z_STRLEN_PP(val), 
-                                               &ocistr
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCIStringAssignText", connection->error);
-                                       RETURN_FALSE;
-                               }
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCICollAssignElem(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               ndx, 
-                                               (dvoid *)ocistr, 
-                                               &new_ind, 
-                                               coll->coll
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCICollAssignElem", connection->error);
-                                       RETURN_FALSE;
-                               }
-                               RETURN_TRUE;
-                               break;
-                       case OCI_TYPECODE_UNSIGNED16 :                       /* UNSIGNED SHORT  */
-                       case OCI_TYPECODE_UNSIGNED32 :                       /* UNSIGNED LONG  */
-                       case OCI_TYPECODE_REAL :                             /* REAL    */
-                       case OCI_TYPECODE_DOUBLE :                           /* DOUBLE  */
-                       case OCI_TYPECODE_INTEGER :                          /* INT  */
-                       case OCI_TYPECODE_SIGNED16 :                         /* SHORT  */
-                       case OCI_TYPECODE_SIGNED32 :                         /* LONG  */
-                       case OCI_TYPECODE_DECIMAL :                          /* DECIMAL  */
-                       case OCI_TYPECODE_FLOAT :                            /* FLOAT    */
-                       case OCI_TYPECODE_NUMBER :                           /* NUMBER   */
-                       case OCI_TYPECODE_SMALLINT :                         /* SMALLINT */
-                               convert_to_double_ex(val);
-                               dnum = (double)Z_DVAL_PP(val);
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCINumberFromReal(
-                                               connection->pError,
-                                               &dnum, 
-                                               sizeof(double),
-                                               &num
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCINumberFromReal", connection->error);
-                                       RETURN_FALSE;
-                               }
-
-                               CALL_OCI_RETURN(connection->error,
-                                       OCICollAssignElem(
-                                               connection->session->pEnv, 
-                                               connection->pError, 
-                                               ndx, 
-                                               (dvoid *)&num, 
-                                               &new_ind, 
-                                               coll->coll
-                                       )
-                               );
-
-                               if (connection->error) {
-                                       oci_error(connection->pError, "OCICollAssignElem", connection->error);
-                                       RETURN_FALSE;
+       } 
+       else {
+               switch (column->retcode) {
+                       case 0: 
+                               /* intact value */
+                               if (column->piecewise) {
+                                       column_size = column->retlen4;
+                               } else {
+                                       column_size = column->retlen;
                                }
-                               RETURN_TRUE;
                                break;
+                       
+                       default:                                
+                               ZVAL_FALSE(value); 
+                               return 0;
                }
+               
+               ZVAL_STRINGL(value, column->data, column_size, 1);
        }
-
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_element_assign() should not be called like this. Use $collection->assignelem($index, $value) to assign value to an element of the collection");
-       RETURN_FALSE;
+       return 0;
 }
 /* }}} */
 
-/* {{{ proto int oci_collection_size()
  Return the size of a collection */
-PHP_FUNCTION(oci_collection_size)
+/* {{{ php_oci_fetch_row() 
Fetch the next row from the given statement */
+void php_oci_fetch_row (INTERNAL_FUNCTION_PARAMETERS, int mode, int expected_args)
 {
-       zval *id;
-       oci_connection *connection;
-       oci_collection *coll;
-       sb4 sz;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
-               }
-               connection = coll->conn;
-
-               CALL_OCI_RETURN(connection->error,
-                       OCICollSize(
-                               connection->session->pEnv,
-                               coll->conn->pError,
-                               coll->coll,
-                               &sz
-                       )
-               );
-
-               if (connection->error) {
-                       oci_error(connection->pError, "OCICollSize", connection->error);
-                       RETURN_FALSE;
-               }
-
-               RETURN_LONG(sz);
-       }
+       zval *z_statement, *array;
+       php_oci_statement *statement;
+       php_oci_out_column *column;
+       ub4 nrows = 1;
+       int i;
+       long fetch_mode = 0;
 
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_size() should not be called like this. Use $collection->size() to get size of the collection");
-       RETURN_FALSE;
-}
-/* }}} */
+       if (expected_args > 2) {
+               /* only for ocifetchinto BC */
 
-/* {{{ proto int oci_collection_max()
-   Return the max value of a collection. For a varray this is the maximum length of the array */
-PHP_FUNCTION(oci_collection_max)
-{
-       zval *id;
-       oci_collection *coll;
-       sb4 sz;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz|l", &z_statement, &array, &fetch_mode) == FAILURE) {
+                       return;
+               }
+               
+               if (ZEND_NUM_ARGS() == 2) {
+                       fetch_mode = mode;
                }
-               sz = OCICollMax(OCI(pEnv),coll->coll); /* XXX not protected against recursion */
-
-               RETURN_LONG(sz);
        }
+       else if (expected_args == 2) {
+               /* only for oci_fetch_array() */
 
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_max() should not be called like this. Use $collection->max() to get maximum number of elements in the collection");
-       RETURN_FALSE;
-}
-/* }}} */
-
-/* {{{ proto bool oci_collection_trim(int num)
-   Trim num elements from the end of a collection */
-PHP_FUNCTION(oci_collection_trim)
-{
-       zval *id,**arg;
-       oci_collection *coll;
-       int inx;
-
-       if ((id = getThis()) != 0) {
-               if ((inx = _oci_get_ocicoll(id,&coll TSRMLS_CC)) == 0) {
-                       RETURN_FALSE;
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_statement, &fetch_mode) == FAILURE) {
+                       return;
                }
-               if (zend_get_parameters_ex(1, &arg) == FAILURE) {
-                       WRONG_PARAM_COUNT;
+               
+               if (ZEND_NUM_ARGS() == 1) {
+                       fetch_mode = mode;
                }
-               convert_to_long_ex(arg);
-
-               CALL_OCI_RETURN(coll->conn->error,
-                       OCICollTrim(
-                               OCI(pEnv),
-                               coll->conn->pError,
-                               Z_LVAL_PP(arg),
-                               coll->coll
-                       )
-               );
-
-               if (coll->conn->error) {
-                       oci_error(coll->conn->pError, "OCICollTrim", coll->conn->error);
-                       RETURN_FALSE;
+       } 
+       else {
+               /* for all oci_fetch_*() */
+               
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+                       return;
                }
-               RETURN_TRUE;
+       
+               fetch_mode = mode;
        }
 
-       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "oci_collection_trim() should not be called like this. Use $collection->trim($length) to trim collection to the given length");
-       RETURN_FALSE;
-}
-/* }}} */
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
 
-/* {{{ proto object oci_new_collection(resource connection, string tdo [, string schema])
-   Initialize a new collection */
-PHP_FUNCTION(oci_new_collection)
-{
-       dvoid *dschp1;
-       dvoid *parmp1;
-       dvoid *parmp2;
-       zval **conn, **tdo, **schema;
-       oci_connection *connection;
-       oci_collection *coll;
-       int ac = ZEND_NUM_ARGS();
-
-       if (ac < 2 || ac > 3 || zend_get_parameters_ex(ac, &conn, &tdo, &schema) == FAILURE) {
-               WRONG_PARAM_COUNT;
+       if (php_oci_statement_fetch(statement, nrows TSRMLS_CC)) {
+               RETURN_FALSE;
        }
-    
-       convert_to_string_ex(tdo);
 
-       if (ac == 3) {
-               convert_to_string_ex(schema);
-       }
+       array_init(return_value);
 
-       coll = emalloc(sizeof(oci_collection));
-
-       OCI_GET_CONN(connection,conn);
-
-       coll->conn = connection;
-       coll->id = zend_list_insert(coll,le_coll);
-       zend_list_addref(connection->id);
-
-       CALL_OCI_RETURN(connection->error,
-               OCITypeByName(
-                       connection->session->pEnv, 
-                       connection->pError, 
-                       connection->pServiceContext, 
-                       ac == 3 ? (text *) Z_STRVAL_PP(schema) : (text *) 0, 
-                       ac == 3 ? (ub4) Z_STRLEN_PP(schema) : (ub4) 0, 
-                       (text *) Z_STRVAL_PP(tdo), 
-                       (ub4)    Z_STRLEN_PP(tdo), 
-                       (CONST text *) 0, 
-                       (ub4) 0, 
-                       OCI_DURATION_SESSION, 
-                       OCI_TYPEGET_ALL, 
-                       &(coll->tdo)
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCITypeByName", connection->error);
-               RETURN_FALSE;
-       }
+       for (i = 0; i < statement->ncolumns; i++) {
+               
+               column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+               
+               if (column == NULL) {
+                       continue;
+               }
+               if ((column->indicator == -1) && ((fetch_mode & PHP_OCI_RETURN_NULLS) == 0)) {
+                       continue;
+               }
 
-       CALL_OCI_RETURN(connection->error, 
-               OCIHandleAlloc(
-                       connection->session->pEnv, 
-                       (dvoid **) &dschp1, 
-                       (ub4) OCI_HTYPE_DESCRIBE, 
-                       (size_t) 0, 
-                       (dvoid **) 0
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCI_HTYPE_DESCRIBE", connection->error);
-               RETURN_FALSE;
-       }
+               if (!(column->indicator == -1)) {
+                       zval *element;
+                       
+                       MAKE_STD_ZVAL(element);
+                       php_oci_column_to_zval(column, element, fetch_mode TSRMLS_CC);
 
-       CALL_OCI_RETURN(connection->error,
-               OCIDescribeAny(
-                       connection->pServiceContext, 
-                       connection->pError, 
-                       (dvoid *) coll->tdo, 
-                       (ub4) 0, 
-                       OCI_OTYPE_PTR, 
-                       (ub1)1, 
-                       (ub1) OCI_PTYPE_TYPE, 
-                       dschp1
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCI_OTYPE_PTR", connection->error);
-               RETURN_FALSE;
+                       if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) {
+                               add_index_zval(return_value, i, element);
+                       }
+                       if (fetch_mode & PHP_OCI_ASSOC) {
+                               if (fetch_mode & PHP_OCI_NUM) {
+                                       ZVAL_ADDREF(element);
+                               }
+                               add_assoc_zval(return_value, column->name, element);
+                       }
+               
+               } else {
+                       if (fetch_mode & PHP_OCI_NUM || !(fetch_mode & PHP_OCI_ASSOC)) {
+                               add_index_null(return_value, i);
+                       }
+                       if (fetch_mode & PHP_OCI_ASSOC) {
+                               add_assoc_null(return_value, column->name);
+                       }
+               }
        }
 
-       CALL_OCI_RETURN(connection->error,
-               OCIAttrGet(
-                       (dvoid *) dschp1, 
-                       (ub4) OCI_HTYPE_DESCRIBE, 
-                       (dvoid *)&parmp1, 
-                       (ub4 *)0, 
-                       (ub4)OCI_ATTR_PARAM,
-                       connection->pError
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCI_ATTR_PARAM", connection->error);
-               RETURN_FALSE;
+       if (expected_args > 2) {
+               /* only for ocifetchinto BC
+                * in all other cases we return array, not long
+                */
+               REPLACE_ZVAL_VALUE(&array, return_value, 1); /* copy return_value to given reference */
+               zval_dtor(return_value);
+               RETURN_LONG(statement->ncolumns);
        }
+}
+/* }}} */
 
-       /* get the collection type code of the attribute */
-
-       CALL_OCI_RETURN(connection->error,
-               OCIAttrGet(
-                       (dvoid*) parmp1, 
-                       (ub4) OCI_DTYPE_PARAM, 
-                       (dvoid*) &(coll->coll_typecode), 
-                       (ub4 *) 0, 
-                       (ub4) OCI_ATTR_COLLECTION_TYPECODE, 
-                       connection->pError
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCI_ATTR_COLLECTION_TYPECODE", connection->error);
-               RETURN_FALSE;
-       }
+/* {{{ php_oci_persistent_helper() 
+ Helper function to close/rollback persistent connections at the end of request */
+static int php_oci_persistent_helper(list_entry *le TSRMLS_DC)
+{
+       time_t timestamp;
+       php_oci_connection *connection;
 
-       switch(coll->coll_typecode) {
-               case OCI_TYPECODE_TABLE:
-               case OCI_TYPECODE_VARRAY:
-                       CALL_OCI_RETURN(connection->error,
-                               OCIAttrGet(
-                                       (dvoid*) parmp1, 
-                                       (ub4) OCI_DTYPE_PARAM, 
-                                       (dvoid*) &parmp2, 
-                                       (ub4 *) 0, 
-                                       (ub4) OCI_ATTR_COLLECTION_ELEMENT, 
-                                       connection->pError
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCI_ATTR_COLLECTION_ELEMENT", connection->error);
-                               RETURN_FALSE;
-                       }
+       timestamp = time(NULL);
+       
+       if (le->type == le_pconnection) {
+               connection = (php_oci_connection *)le->ptr;
 
-                       CALL_OCI_RETURN(connection->error,
-                               OCIAttrGet(
-                                       (dvoid*) parmp2, 
-                                       (ub4) OCI_DTYPE_PARAM, 
-                                       (dvoid*) &(coll->elem_ref), 
-                                       (ub4 *) 0, 
-                                       (ub4) OCI_ATTR_REF_TDO, 
-                                       connection->pError
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCI_ATTR_REF_TDO", connection->error);
-                               RETURN_FALSE;
+               if (connection->used_this_request) {
+                       php_oci_connection_rollback(connection TSRMLS_CC);
+                       
+                       if (connection->descriptors) {
+                               zend_hash_destroy(connection->descriptors);
+                               efree(connection->descriptors);
+                               connection->descriptors = NULL;
                        }
-
-                       CALL_OCI_RETURN(connection->error,
-                               OCITypeByRef(
-                                       connection->session->pEnv, 
-                                       connection->pError, 
-                                       coll->elem_ref, 
-                                       OCI_DURATION_SESSION, 
-                                       OCI_TYPEGET_HEADER, 
-                                       &(coll->element_type)
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCI_TYPEGET_HEADER", connection->error);
-                               RETURN_FALSE;
+                       
+                       if (OCI_G(persistent_timeout) > 0) {
+                               connection->idle_expiry = timestamp + OCI_G(persistent_timeout);
+                       }
+               
+                       if (OCI_G(ping_interval) >= 0) {
+                               connection->next_ping = timestamp + OCI_G(ping_interval);
+                       }
+                       else {
+                               /* ping_interval is -1 */
+                               connection->next_ping = 0;
                        }
 
-                       CALL_OCI_RETURN(connection->error,
-                               OCIAttrGet(
-                                       (dvoid*) parmp2, 
-                                       (ub4) OCI_DTYPE_PARAM, 
-                                       (dvoid*) &(coll->element_typecode), 
-                                       (ub4 *) 0, 
-                                       (ub4) OCI_ATTR_TYPECODE, 
-                                       connection->pError
-                               )
-                       );
-
-                       if (connection->error) {
-                               oci_error(connection->pError, "OCI_ATTR_TYPECODE", connection->error);
-                               RETURN_FALSE;
+                       connection->used_this_request = 0;
+               }
+               else if (OCI_G(persistent_timeout) != -1) {
+                       if (connection->idle_expiry < timestamp) {
+                               /* connection has timed out */
+                               return 1;
                        }
-                       break;
-               default:
-                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCINewCollection - Unknown Type %d", coll->coll_typecode);
-                       break;
-       }       
-
-       /* Create object to hold return table */
-       CALL_OCI_RETURN(connection->error,
-               OCIObjectNew(
-                       connection->session->pEnv, 
-                       connection->pError, 
-                       connection->pServiceContext, 
-                       OCI_TYPECODE_TABLE, 
-                       coll->tdo, 
-                       (dvoid *)0, 
-                       OCI_DURATION_DEFAULT, 
-                       TRUE, 
-                       (dvoid **) &(coll->coll)
-               )
-       );
-
-       if (connection->error) {
-               oci_error(connection->pError, "OCIObjectNew", connection->error);
-               RETURN_FALSE;
+               }
        }
-
-       object_init_ex(return_value, oci_coll_class_entry_ptr);
-       add_property_resource(return_value, "collection",coll->id);
-}
-/* }}} */
-#endif
+       return 0;
+} /* }}} */
 
 #endif /* HAVE_OCI8 */
-
-/*
- * Local variables:
- * tab-width: 4
- * c-basic-offset: 4
- * End:
- * vim600: sw=4 ts=4 fdm=marker
- * vim<600: sw=4 ts=4
- */
diff --git a/ext/oci8/oci8_collection.c b/ext/oci8/oci8_collection.c
new file mode 100644 (file)
index 0000000..f0d8e2f
--- /dev/null
@@ -0,0 +1,604 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2005 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   |          Thies C. Arntzen <thies@thieso.net>                         |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "php_ini.h"
+
+#if HAVE_OCI8
+
+#include "php_oci8.h"
+#include "php_oci8_int.h"
+
+/* {{{ php_oci_collection_create() 
+ Create and return connection handle */
+php_oci_collection * php_oci_collection_create(php_oci_connection* connection, char *tdo, long tdo_len, char *schema, long schema_len TSRMLS_DC)
+{      
+       dvoid *dschp1;
+       dvoid *parmp1;
+       dvoid *parmp2;
+       php_oci_collection *collection;
+       
+       collection = emalloc(sizeof(php_oci_collection));
+
+       collection->connection = connection;
+       collection->collection = NULL;
+       
+       /* get type handle by name */
+       connection->errcode = PHP_OCI_CALL(OCITypeByName,       (connection->env, connection->err, connection->svc, (text *) schema, (ub4) schema_len, (text *) tdo, (ub4) tdo_len, (CONST text *) 0, (ub4) 0, OCI_DURATION_SESSION, OCI_TYPEGET_ALL, &(collection->tdo)));
+
+       if (connection->errcode) {
+               goto CLEANUP;
+       }
+
+       /* allocate describe handle */
+       connection->errcode = PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **) &dschp1, (ub4) OCI_HTYPE_DESCRIBE, (size_t) 0, (dvoid **) 0));
+
+       if (connection->errcode) {
+               goto CLEANUP;
+       }
+
+       /* describe TDO */
+       connection->errcode = PHP_OCI_CALL(OCIDescribeAny, (connection->svc, connection->err, (dvoid *) collection->tdo, (ub4) 0, OCI_OTYPE_PTR, (ub1) OCI_DEFAULT, (ub1) OCI_PTYPE_TYPE, dschp1));
+
+       if (connection->errcode) {
+               goto CLEANUP;
+       }
+
+       /* get first parameter handle */
+       connection->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *) dschp1, (ub4) OCI_HTYPE_DESCRIBE, (dvoid *)&parmp1, (ub4 *)0, (ub4)OCI_ATTR_PARAM,    connection->err));
+
+       if (connection->errcode) {
+               goto CLEANUP;
+       }
+
+       /* get the collection type code of the attribute */
+       connection->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid*) parmp1, (ub4) OCI_DTYPE_PARAM, (dvoid*) &(collection->coll_typecode), (ub4 *) 0, (ub4) OCI_ATTR_COLLECTION_TYPECODE, connection->err));
+
+       if (connection->errcode) {
+               goto CLEANUP;
+       }
+
+       switch(collection->coll_typecode) {
+               case OCI_TYPECODE_TABLE:
+               case OCI_TYPECODE_VARRAY:
+                       /* get collection element handle */
+                       connection->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid*) parmp1, (ub4) OCI_DTYPE_PARAM, (dvoid*) &parmp2, (ub4 *) 0, (ub4) OCI_ATTR_COLLECTION_ELEMENT, connection->err));
+
+                       if (connection->errcode) {
+                               goto CLEANUP;
+                       }
+
+                       /* get REF of the TDO for the type */
+                       connection->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid*) parmp2, (ub4) OCI_DTYPE_PARAM, (dvoid*) &(collection->elem_ref), (ub4 *) 0, (ub4) OCI_ATTR_REF_TDO, connection->err));
+
+                       if (connection->errcode) {
+                               goto CLEANUP;
+                       }
+
+                       /* get the TDO (only header) */
+                       connection->errcode = PHP_OCI_CALL(OCITypeByRef, (connection->env, connection->err, collection->elem_ref, OCI_DURATION_SESSION, OCI_TYPEGET_HEADER, &(collection->element_type)));
+
+                       if (connection->errcode) {
+                               goto CLEANUP;
+                       }
+
+                       /* get typecode */
+                       connection->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid*) parmp2, (ub4) OCI_DTYPE_PARAM, (dvoid*) &(collection->element_typecode), (ub4 *) 0, (ub4) OCI_ATTR_TYPECODE, connection->err));
+
+                       if (connection->errcode) {
+                               goto CLEANUP;
+                       }
+                       break;
+                       /* we only support VARRAYs and TABLEs */
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCINewCollection - Unknown Type %d", collection->coll_typecode);
+                       break;
+       }       
+
+       /* Create object to hold return table */
+       connection->errcode = PHP_OCI_CALL(OCIObjectNew, 
+               (
+                       connection->env, 
+                       connection->err, 
+                       connection->svc, 
+                       OCI_TYPECODE_TABLE, 
+                       collection->tdo, 
+                       (dvoid *)0, 
+                       OCI_DURATION_DEFAULT, 
+                       TRUE, 
+                       (dvoid **) &(collection->collection)
+               )
+       );
+
+       if (connection->errcode) {
+               goto CLEANUP;
+       }
+
+       PHP_OCI_REGISTER_RESOURCE(collection, le_collection);
+       return collection;
+       
+CLEANUP:
+
+       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+       php_oci_collection_close(collection TSRMLS_CC); 
+       return NULL;
+} /* }}} */
+
+/* {{{ php_oci_collection_size() 
+ Return size of the collection */
+int php_oci_collection_size(php_oci_collection *collection, sb4 *size TSRMLS_DC)
+{
+       php_oci_connection *connection = collection->connection;
+       
+       connection->errcode = PHP_OCI_CALL(OCICollSize, (connection->env, connection->err, collection->collection, (sb4 *)size));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_max() 
+ Return max number of elements in the collection */
+int php_oci_collection_max(php_oci_collection *collection, long *max TSRMLS_DC)
+{
+       php_oci_connection *connection = collection->connection;
+       
+       *max = PHP_OCI_CALL(OCICollMax, (connection->env, collection->collection));
+
+       /* error handling is not necessary here? */
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_trim() 
+ Trim collection to the given number of elements */
+int php_oci_collection_trim(php_oci_collection *collection, long trim_size TSRMLS_DC)
+{
+       php_oci_connection *connection = collection->connection;
+       
+       connection->errcode = PHP_OCI_CALL(OCICollTrim, (connection->env, connection->err, trim_size, collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_append_null() 
+ Append NULL element to the end of the collection */
+int php_oci_collection_append_null(php_oci_collection *collection TSRMLS_DC)
+{
+       OCIInd null_index = OCI_IND_NULL;
+       php_oci_connection *connection = collection->connection;
+
+       /* append NULL element */
+       connection->errcode = PHP_OCI_CALL(OCICollAppend, (connection->env, connection->err, (dvoid *)0, &null_index, collection->collection));
+       
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_append_date() 
+ Append DATE element to the end of the collection (use "DD-MON-YY" format) */
+int php_oci_collection_append_date(php_oci_collection *collection, char *date, long date_len TSRMLS_DC)
+{
+       OCIInd new_index = OCI_IND_NOTNULL;
+       OCIDate oci_date;
+       php_oci_connection *connection = collection->connection;
+
+       /* format and language are NULLs, so format is "DD-MON-YY" and language is the default language of the session */
+       connection->errcode = PHP_OCI_CALL(OCIDateFromText, (connection->err, date, date_len, NULL, 0, NULL, 0, &oci_date));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               /* failed to convert string to date */
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCICollAppend, (connection->env, connection->err, (dvoid *) &oci_date, (dvoid *) &new_index, (OCIColl *) collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+                       
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_append_number()
+ Append NUMBER to the end of the collection */
+int php_oci_collection_append_number(php_oci_collection *collection, char *number, long number_len TSRMLS_DC)
+{
+       OCIInd new_index = OCI_IND_NOTNULL;
+       double element_double;
+       OCINumber oci_number;
+       php_oci_connection *connection = collection->connection;
+
+       element_double = zend_strtod(number, NULL);
+                       
+       connection->errcode = PHP_OCI_CALL(OCINumberFromReal, (connection->err, &element_double, sizeof(double), &oci_number));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCICollAppend, (connection->env, connection->err, (dvoid *) &oci_number, (dvoid *) &new_index, (OCIColl *) collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_append_string() 
+ Append STRING to the end of the collection */
+int php_oci_collection_append_string(php_oci_collection *collection, char *element, long element_len TSRMLS_DC)
+{
+       OCIInd new_index = OCI_IND_NOTNULL;
+       OCIString *ocistr = (OCIString *)0;
+       php_oci_connection *connection = collection->connection;
+                       
+       connection->errcode = PHP_OCI_CALL(OCIStringAssignText, (connection->env, connection->err, element, element_len, &ocistr));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCICollAppend, (connection->env, connection->err, (dvoid *) ocistr, (dvoid *) &new_index,    (OCIColl *) collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_append() 
+ Append wrapper. Appends any supported element to the end of the collection */
+int php_oci_collection_append(php_oci_collection *collection, char *element, long element_len TSRMLS_DC)
+{
+       if (element_len == 0) {
+               return php_oci_collection_append_null(collection TSRMLS_CC);
+       }
+       
+       switch(collection->element_typecode) {
+               case OCI_TYPECODE_DATE:
+                       return php_oci_collection_append_date(collection, element, element_len TSRMLS_CC);
+                       break;
+                       
+               case OCI_TYPECODE_VARCHAR2 :
+                       return php_oci_collection_append_string(collection, element, element_len TSRMLS_CC);
+                       break;
+
+               case OCI_TYPECODE_UNSIGNED16 :                       /* UNSIGNED SHORT  */
+               case OCI_TYPECODE_UNSIGNED32 :                        /* UNSIGNED LONG  */
+               case OCI_TYPECODE_REAL :                                     /* REAL    */
+               case OCI_TYPECODE_DOUBLE :                                   /* DOUBLE  */
+               case OCI_TYPECODE_INTEGER :                                     /* INT  */
+               case OCI_TYPECODE_SIGNED16 :                                  /* SHORT  */
+               case OCI_TYPECODE_SIGNED32 :                                   /* LONG  */
+               case OCI_TYPECODE_DECIMAL :                                 /* DECIMAL  */
+               case OCI_TYPECODE_FLOAT :                                   /* FLOAT    */
+               case OCI_TYPECODE_NUMBER :                                  /* NUMBER   */
+               case OCI_TYPECODE_SMALLINT :                                /* SMALLINT */
+                       return php_oci_collection_append_number(collection, element, element_len TSRMLS_CC);
+                       break;
+
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or unsupported type of element: %d", collection->element_typecode);
+                       return 1;
+                       break;
+       }
+       /* never reached */
+       return 1;
+} /* }}} */
+
+/* {{{ php_oci_collection_element_get() 
+ Get the element with the given index */
+int php_oci_collection_element_get(php_oci_collection *collection, long index, zval **result_element TSRMLS_DC)
+{
+       php_oci_connection *connection = collection->connection;
+       dvoid *element;
+       OCIInd *element_index;
+       boolean exists;
+       char buff[1024];
+       int buff_len = 1024;
+       
+       MAKE_STD_ZVAL(*result_element);
+       ZVAL_NULL(*result_element);
+
+       connection->errcode = PHP_OCI_CALL(OCICollGetElem, (connection->env, connection->err, collection->collection, (ub4)index, &exists, &element,    (dvoid **)&element_index));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               FREE_ZVAL(*result_element);
+               return 1;
+       }
+       
+       if (exists == 0) {
+               /* element doesn't exist */
+               FREE_ZVAL(*result_element);
+               return 1;
+       }
+
+       if (*element_index == OCI_IND_NULL) {
+               /* this is not an error, we're returning NULL here */
+               return 0;
+       }
+
+       switch (collection->element_typecode) {
+               case OCI_TYPECODE_DATE:
+                       connection->errcode = PHP_OCI_CALL(OCIDateToText, (connection->err, element, 0, 0, 0, 0, &buff_len, buff));
+       
+                       if (connection->errcode != OCI_SUCCESS) {
+                               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                               FREE_ZVAL(*result_element);
+                               return 1;
+                       }
+
+                       ZVAL_STRINGL(*result_element, buff, buff_len, 1);
+                       Z_STRVAL_P(*result_element)[buff_len] = '\0';
+                       
+                       return 0;
+                       break;
+
+               case OCI_TYPECODE_VARCHAR2:
+               {
+                       OCIString *oci_string = *(OCIString **)element;
+                       text *str;
+                       
+                       str = (text *)PHP_OCI_CALL(OCIStringPtr, (connection->env, oci_string));
+                       
+                       if (str) {
+                               ZVAL_STRING(*result_element, str, 1);
+                       }
+                       return 0;
+               }
+                       break;
+
+               case OCI_TYPECODE_UNSIGNED16:                       /* UNSIGNED SHORT  */
+               case OCI_TYPECODE_UNSIGNED32:                       /* UNSIGNED LONG  */
+               case OCI_TYPECODE_REAL:                             /* REAL    */
+               case OCI_TYPECODE_DOUBLE:                           /* DOUBLE  */
+               case OCI_TYPECODE_INTEGER:                          /* INT  */
+               case OCI_TYPECODE_SIGNED16:                         /* SHORT  */
+               case OCI_TYPECODE_SIGNED32:                         /* LONG  */
+               case OCI_TYPECODE_DECIMAL:                          /* DECIMAL  */
+               case OCI_TYPECODE_FLOAT:                            /* FLOAT    */
+               case OCI_TYPECODE_NUMBER:                           /* NUMBER   */
+               case OCI_TYPECODE_SMALLINT:                         /* SMALLINT */
+               {
+                       double double_number;
+                       
+                       connection->errcode = PHP_OCI_CALL(OCINumberToReal, (connection->err, (CONST OCINumber *) element, (uword) sizeof(double), (dvoid *) &double_number));
+
+                       if (connection->errcode != OCI_SUCCESS) {
+                               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                               FREE_ZVAL(*result_element);
+                               return 1;
+                       }
+                       
+                       ZVAL_DOUBLE(*result_element, double_number);
+
+                       return 0;
+               }
+                       break;
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or unsupported type of element: %d", collection->element_typecode);
+                       FREE_ZVAL(*result_element);
+                       return 1;
+                       break;
+       }
+       /* never reached */
+       return 1;
+} /* }}} */
+
+/* {{{ php_oci_collection_element_set_null() 
+ Set the element with the given index to NULL */
+int php_oci_collection_element_set_null(php_oci_collection *collection, long index TSRMLS_DC)
+{
+       OCIInd null_index = OCI_IND_NULL;
+       php_oci_connection *connection = collection->connection;
+
+       /* set NULL element */
+       connection->errcode = PHP_OCI_CALL(OCICollAssignElem, (connection->env, connection->err, (ub4) index, (dvoid *)"", &null_index, collection->collection));
+       
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_element_set_date() 
+ Change element's value to the given DATE */
+int php_oci_collection_element_set_date(php_oci_collection *collection, long index, char *date, long date_len TSRMLS_DC)
+{
+       OCIInd new_index = OCI_IND_NOTNULL;
+       OCIDate oci_date;
+       php_oci_connection *connection = collection->connection;
+
+       /* format and language are NULLs, so format is "DD-MON-YY" and language is the default language of the session */
+       connection->errcode = PHP_OCI_CALL(OCIDateFromText, (connection->err, date, date_len, NULL, 0, NULL, 0, &oci_date));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               /* failed to convert string to date */
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCICollAssignElem, (connection->env, connection->err, (ub4)index, (dvoid *) &oci_date, (dvoid *) &new_index, (OCIColl *) collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+                       
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_element_set_number()
+ Change element's value to the given NUMBER */
+int php_oci_collection_element_set_number(php_oci_collection *collection, long index, char *number, long number_len TSRMLS_DC)
+{
+       OCIInd new_index = OCI_IND_NOTNULL;
+       double element_double;
+       OCINumber oci_number;
+       php_oci_connection *connection = collection->connection;
+
+       element_double = zend_strtod(number, NULL);
+                       
+       connection->errcode = PHP_OCI_CALL(OCINumberFromReal, (connection->err, &element_double, sizeof(double), &oci_number));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCICollAssignElem, (connection->env, connection->err, (ub4) index, (dvoid *) &oci_number, (dvoid *) &new_index, (OCIColl *) collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_element_set_string()
+ Change element's value to the given string */
+int php_oci_collection_element_set_string(php_oci_collection *collection, long index, char *element, long element_len TSRMLS_DC)
+{
+       OCIInd new_index = OCI_IND_NOTNULL;
+       OCIString *ocistr = (OCIString *)0;
+       php_oci_connection *connection = collection->connection;
+                       
+       connection->errcode = PHP_OCI_CALL(OCIStringAssignText, (connection->env, connection->err, element, element_len, &ocistr));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCICollAssignElem, (connection->env, connection->err, (ub4)index, (dvoid *) ocistr, (dvoid *) &new_index,    (OCIColl *) collection->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_element_set()
+ Collection element setter */
+int php_oci_collection_element_set(php_oci_collection *collection, long index, char *value, long value_len TSRMLS_DC)
+{
+       if (value_len == 0) {
+               return php_oci_collection_element_set_null(collection, index TSRMLS_CC);
+       }
+       
+       switch(collection->element_typecode) {
+               case OCI_TYPECODE_DATE:
+                       return php_oci_collection_element_set_date(collection, index, value, value_len TSRMLS_CC);
+                       break;
+                       
+               case OCI_TYPECODE_VARCHAR2 :
+                       return php_oci_collection_element_set_string(collection, index, value, value_len TSRMLS_CC);
+                       break;
+
+               case OCI_TYPECODE_UNSIGNED16 :                       /* UNSIGNED SHORT  */
+               case OCI_TYPECODE_UNSIGNED32 :                        /* UNSIGNED LONG  */
+               case OCI_TYPECODE_REAL :                                     /* REAL    */
+               case OCI_TYPECODE_DOUBLE :                                   /* DOUBLE  */
+               case OCI_TYPECODE_INTEGER :                                     /* INT  */
+               case OCI_TYPECODE_SIGNED16 :                                  /* SHORT  */
+               case OCI_TYPECODE_SIGNED32 :                                   /* LONG  */
+               case OCI_TYPECODE_DECIMAL :                                 /* DECIMAL  */
+               case OCI_TYPECODE_FLOAT :                                   /* FLOAT    */
+               case OCI_TYPECODE_NUMBER :                                  /* NUMBER   */
+               case OCI_TYPECODE_SMALLINT :                                /* SMALLINT */
+                       return php_oci_collection_element_set_number(collection, index, value, value_len TSRMLS_CC);
+                       break;
+
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_NOTICE, "Unknown or unsupported type of element: %d", collection->element_typecode);
+                       return 1;
+                       break;
+       }
+       /* never reached */
+       return 1;
+} /* }}} */
+
+/* {{{ php_oci_collection_assign() 
+ Assigns a value to the collection from another collection */
+int php_oci_collection_assign(php_oci_collection *collection_dest, php_oci_collection *collection_from TSRMLS_DC)
+{
+       php_oci_connection *connection = collection_dest->connection;
+       
+       connection->errcode = PHP_OCI_CALL(OCICollAssign, (connection->env, connection->err, collection_from->collection, collection_dest->collection));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_collection_close()
+ Destroy collection and all associated resources */
+void php_oci_collection_close(php_oci_collection *collection TSRMLS_DC)
+{
+       php_oci_connection *connection = collection->connection;
+
+       if (collection->collection) {
+               connection->errcode = PHP_OCI_CALL(OCIObjectFree, (connection->env, connection->err, (dvoid *)collection->collection, (ub2)OCI_OBJECTFREE_FORCE));
+
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               }
+       }
+
+       efree(collection);
+       return;
+} /* }}} */
+
+#endif /* HAVE_OCI8 */
diff --git a/ext/oci8/oci8_interface.c b/ext/oci8/oci8_interface.c
new file mode 100644 (file)
index 0000000..debdaad
--- /dev/null
@@ -0,0 +1,2065 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2005 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   |          Thies C. Arntzen <thies@thieso.net>                         |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "php_ini.h"
+
+#if HAVE_OCI8
+
+#include "php_oci8.h"
+#include "php_oci8_int.h"
+
+/* {{{ proto bool oci_define_by_name(resource stmt, string name, mixed &var [, int type])
+   Define a PHP variable to an Oracle column by name */
+/* if you want to define a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE defining!!! */
+PHP_FUNCTION(oci_define_by_name)
+{
+       zval *stmt, *var;
+       char *name;
+       long name_len, type = SQLT_CHR;
+       php_oci_statement *statement;
+       php_oci_define *define, *tmp_define;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsz/|l", &stmt, &name, &name_len, &var, &type) == FAILURE) {
+               return;
+       }
+
+       if (!name_len) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Column name cannot be empty");
+               RETURN_FALSE;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(stmt, statement);
+
+       if (statement->defines == NULL) {
+               ALLOC_HASHTABLE(statement->defines);
+               zend_hash_init(statement->defines, 13, NULL, php_oci_define_hash_dtor, 0);
+       }
+
+       define = ecalloc(1,sizeof(php_oci_define));
+
+       if (zend_hash_add(statement->defines, name, name_len, define, sizeof(php_oci_define), (void **)&tmp_define) == SUCCESS) {
+               efree(define);
+               define = tmp_define;
+       } else {
+               efree(define);
+               RETURN_FALSE;
+       }
+
+       define->name = (text*) estrndup(name, name_len);
+       define->name_len = name_len;
+       define->type = type;
+       define->zval = var;
+       zval_add_ref(&var);
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_bind_by_name(resource stmt, string name, mixed &var, [, int maxlength [, int type]])
+   Bind a PHP variable to an Oracle placeholder by name */
+/* if you want to bind a LOB/CLOB etc make sure you allocate it via OCINewDescriptor BEFORE binding!!! */
+PHP_FUNCTION(oci_bind_by_name)
+{
+       ub2     bind_type = SQLT_CHR; /* unterminated string */
+       long name_len, maxlen = -1, type = 0;
+       char *name;
+       zval *z_statement;
+       zval *bind_var = NULL;
+       php_oci_statement *statement;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rsz/|ll", &z_statement, &name, &name_len, &bind_var, &maxlen, &type) == FAILURE) {
+               return;
+       }
+
+       if (type) {
+               bind_type = (ub2) type;
+       }
+       
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_bind_by_name(statement, name, name_len, bind_var, maxlen, bind_type TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_free_descriptor()
+   Deletes large object description */
+PHP_FUNCTION(oci_free_descriptor)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       zend_list_delete(descriptor->id);
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_save( string data [, int offset ])
+   Saves a large object */
+PHP_FUNCTION(oci_lob_save)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       char *data;
+       long data_len;
+       long offset = 0;
+       ub4 bytes_written;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &offset) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &z_descriptor, oci_lob_class_entry_ptr, &data, &data_len, &offset) == FAILURE) {
+                       return;
+               }
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       if (offset < 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset parameter must be greater than or equal to 0");
+               RETURN_FALSE;
+       }
+       
+       if (php_oci_lob_write(descriptor, offset, data, data_len, &bytes_written TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_import( string filename )
+   Loads file into a LOB */
+PHP_FUNCTION(oci_lob_import)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       char *filename;
+       long filename_len;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &filename, &filename_len) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os", &z_descriptor, oci_lob_class_entry_ptr, &filename, &filename_len) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       if (php_oci_lob_import(descriptor, filename TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string oci_lob_load()
+   Loads a large object */
+PHP_FUNCTION(oci_lob_load)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       char *buffer = NULL;
+       ub4 buffer_len;
+
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       if (php_oci_lob_read(descriptor, -1, 0, &buffer, &buffer_len TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_STRINGL(buffer, buffer_len, 0);
+}
+/* }}} */
+
+/* {{{ proto string oci_lob_read( int length )
+   Reads particular part of a large object */
+PHP_FUNCTION(oci_lob_read)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       long length;
+       char *buffer;
+       ub4 buffer_len;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &length) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &z_descriptor, oci_lob_class_entry_ptr, &length) == FAILURE) {
+                       return;
+               }       
+       }
+
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       if (length <= 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
+               RETURN_FALSE;
+       }
+       
+       if (php_oci_lob_read(descriptor, length, descriptor->lob_current_position, &buffer, &buffer_len TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_STRINGL(buffer, buffer_len, 0);
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_eof()
+   Checks if EOF is reached */
+PHP_FUNCTION(oci_lob_eof)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       ub4 lob_length;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (!php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC) && lob_length >= 0) {
+               if (lob_length == descriptor->lob_current_position) {
+                       RETURN_TRUE;
+               }
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int oci_lob_tell()
+   Tells LOB pointer position */
+PHP_FUNCTION(oci_lob_tell)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       RETURN_LONG(descriptor->lob_current_position);  
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_rewind()
+   Rewind pointer of a LOB */
+PHP_FUNCTION(oci_lob_rewind)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       descriptor->lob_current_position = 0;
+
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_seek( int offset [, int whence ])
+   Moves the pointer of a LOB */
+PHP_FUNCTION(oci_lob_seek)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       long offset, whence = PHP_OCI_SEEK_SET;
+       ub4 lob_length;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l|l", &offset, &whence) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol|l", &z_descriptor, oci_lob_class_entry_ptr, &offset, &whence) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       
+       if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+
+       switch(whence) {
+               case PHP_OCI_SEEK_CUR:
+                       descriptor->lob_current_position += offset;
+                       break;
+               case PHP_OCI_SEEK_END:
+                       if (descriptor->lob_size + offset >= 0) {
+                               descriptor->lob_current_position = descriptor->lob_size + offset;
+                       } 
+                       else {
+                               descriptor->lob_current_position = 0;
+                       }
+                       break;
+               case PHP_OCI_SEEK_SET:
+               default:
+                               descriptor->lob_current_position = (offset > 0) ? offset : 0;
+                       break;
+       }
+       
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int oci_lob_size()
+   Returns size of a large object */
+PHP_FUNCTION(oci_lob_size)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       ub4 lob_length;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_LONG(lob_length);
+}
+/* }}} */
+
+/* {{{ proto int oci_lob_write( string string [, int length ])
+   Writes data to current position of a LOB */
+PHP_FUNCTION(oci_lob_write)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       long data_len, write_len = 0; 
+       ub4 bytes_written;
+       char *data;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &write_len) == FAILURE) {
+                       return;
+               }
+               
+               if (ZEND_NUM_ARGS() == 2) {
+                       data_len = MIN(data_len, write_len);
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &z_descriptor, oci_lob_class_entry_ptr, &data, &data_len, &write_len) == FAILURE) {
+                       return;
+               }
+
+               if (ZEND_NUM_ARGS() == 3) {
+                       data_len = MIN(data_len, write_len);
+               }
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (data_len <= 0) {
+               RETURN_LONG(0);
+       }
+       
+       if (php_oci_lob_write(descriptor, descriptor->lob_current_position, data, data_len, &bytes_written TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_LONG(bytes_written);
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_append( object lob )
+   Appends data from a LOB to another LOB */
+PHP_FUNCTION(oci_lob_append)
+{
+       zval **tmp_dest, **tmp_from, *z_descriptor_dest = getThis(), *z_descriptor_from;
+       php_oci_descriptor *descriptor_dest, *descriptor_from;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor_from, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &z_descriptor_dest, oci_lob_class_entry_ptr, &z_descriptor_from, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor_dest), "descriptor", sizeof("descriptor"), (void **)&tmp_dest) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property. The first argument should be valid descriptor object");
+               RETURN_FALSE;
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor_from), "descriptor", sizeof("descriptor"), (void **)&tmp_from) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property. The second argument should be valid descriptor object");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp_dest, descriptor_dest);
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp_from, descriptor_from);
+       
+       if (php_oci_lob_append(descriptor_dest, descriptor_from TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       /* XXX should we increase lob_size here ? */
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_truncate( [ int length ])
+   Truncates a LOB */
+PHP_FUNCTION(oci_lob_truncate)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       ub4 trim_length = 0;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &trim_length) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &z_descriptor, oci_lob_class_entry_ptr, &trim_length) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (php_oci_lob_truncate(descriptor, trim_length TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int oci_lob_erase( [ int offset [, int length ] ] )
+   Erases a specified portion of the internal LOB, starting at a specified offset */
+PHP_FUNCTION(oci_lob_erase)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       ub4 bytes_erased;
+       long offset = -1, length = -1;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|ll", &offset, &length) == FAILURE) {
+                       return;
+               }
+       
+               if (ZEND_NUM_ARGS() > 0 && offset < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+               
+               if (ZEND_NUM_ARGS() > 1 && length < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|ll", &z_descriptor, oci_lob_class_entry_ptr, &offset, &length) == FAILURE) {
+                       return;
+               }
+                       
+               if (ZEND_NUM_ARGS() > 1 && offset < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+               
+               if (ZEND_NUM_ARGS() > 2 && length < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (php_oci_lob_erase(descriptor, offset, length, &bytes_erased TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_LONG(bytes_erased);
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_flush( [ int flag ] )
+   Flushes the LOB buffer */
+PHP_FUNCTION(oci_lob_flush)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       ub4 flush_flag = 0;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|l", &flush_flag) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O|l", &z_descriptor, oci_lob_class_entry_ptr, &flush_flag) == FAILURE) {
+                       return;
+               }
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (descriptor->buffering == PHP_OCI_LOB_BUFFER_DISABLED) {
+               /* buffering wasn't enabled, there is nothing to flush */
+               RETURN_FALSE;
+       }
+
+       if (php_oci_lob_flush(descriptor, flush_flag TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ocisetbufferinglob( boolean flag )
+   Enables/disables buffering for a LOB */
+PHP_FUNCTION(ocisetbufferinglob)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       zend_bool flag;
+       
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &flag) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ob", &z_descriptor, oci_lob_class_entry_ptr, &flag) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (php_oci_lob_set_buffering(descriptor, flag TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool ocigetbufferinglob()
+   Returns current state of buffering for a LOB */
+PHP_FUNCTION(ocigetbufferinglob)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
+               RETURN_TRUE;
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_copy( object lob_to, object lob_from [, int length ] )
+   Copies data from a LOB to another LOB */
+PHP_FUNCTION(oci_lob_copy)
+{
+       zval **tmp_dest, **tmp_from, *z_descriptor_dest, *z_descriptor_from;
+       php_oci_descriptor *descriptor_dest, *descriptor_from;
+       long length = 0;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO|l", &z_descriptor_dest, oci_lob_class_entry_ptr, &z_descriptor_from, oci_lob_class_entry_ptr, &length) == FAILURE) {
+               return;
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor_dest), "descriptor", sizeof("descriptor"), (void **)&tmp_dest) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property. The first argument should be valid descriptor object");
+               RETURN_FALSE;
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor_from), "descriptor", sizeof("descriptor"), (void **)&tmp_from) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property. The second argument should be valid descriptor object");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp_dest, descriptor_dest);
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp_from, descriptor_from);
+       
+       if (ZEND_NUM_ARGS() == 3 && length < 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than 0");
+               RETURN_FALSE;
+       }
+       
+       if (ZEND_NUM_ARGS() == 2) {
+               /* indicate that we want to copy from the current position to the end of the LOB */
+               length = -1;
+       }
+
+       if (php_oci_lob_copy(descriptor_dest, descriptor_from, length TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_is_equal( object lob1, object lob2 )
+   Tests to see if two LOB/FILE locators are equal */
+PHP_FUNCTION(oci_lob_is_equal)
+{
+       zval **tmp_first, **tmp_second, *z_descriptor_first, *z_descriptor_second;
+       php_oci_descriptor *descriptor_first, *descriptor_second;
+       boolean is_equal;
+               
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &z_descriptor_first, oci_lob_class_entry_ptr, &z_descriptor_second, oci_lob_class_entry_ptr) == FAILURE) {
+               return;
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor_first), "descriptor", sizeof("descriptor"), (void **)&tmp_first) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property. The first argument should be valid descriptor object");
+               RETURN_FALSE;
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor_second), "descriptor", sizeof("descriptor"), (void **)&tmp_second) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property. The second argument should be valid descriptor object");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp_first, descriptor_first);
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp_second, descriptor_second);
+
+       if (php_oci_lob_is_equal(descriptor_first, descriptor_second, &is_equal TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       
+       if (is_equal == TRUE) {
+               RETURN_TRUE;
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_export([string filename [, int start [, int length]]])
+   Writes a large object into a file */
+PHP_FUNCTION(oci_lob_export)
+{      
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       char *filename, *buffer;
+       long filename_len, start = -1, length = -1, block_length;
+       php_stream *stream;
+       ub4 lob_length;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|ll", &filename, &filename_len, &start, &length) == FAILURE) {
+                       return;
+               }
+       
+               if (ZEND_NUM_ARGS() > 1 && start < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Start parameter must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+               if (ZEND_NUM_ARGS() > 2 && length < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|ll", &z_descriptor, oci_lob_class_entry_ptr, &filename, &filename_len, &start, &length) == FAILURE) {
+                       return;
+               }
+                       
+               if (ZEND_NUM_ARGS() > 2 && start < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Start parameter must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+               if (ZEND_NUM_ARGS() > 3 && length < 0) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Length parameter must be greater than or equal to 0");
+                       RETURN_FALSE;
+               }
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+       
+       if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
+               RETURN_FALSE;
+       }               
+       
+       if (start == -1) {
+               start = 0;
+       }
+
+       if (length == -1) {
+               length = lob_length - descriptor->lob_current_position;
+       }
+       
+       if (length == 0) {
+               /* nothing to write, fail silently */
+               RETURN_FALSE;
+       }
+       
+       if (PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) {
+               RETURN_FALSE;
+       }
+
+       if (php_check_open_basedir(filename TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+
+       stream = php_stream_open_wrapper_ex(filename, "w", ENFORCE_SAFE_MODE | REPORT_ERRORS, NULL, NULL);
+
+       block_length = PHP_OCI_LOB_BUFFER_SIZE;
+       if (block_length > length) {
+               block_length = length;
+       }
+
+       while(length > 0) {
+               ub4 tmp_bytes_read = 0;
+               if (php_oci_lob_read(descriptor, block_length, start, &buffer, &tmp_bytes_read TSRMLS_CC)) {
+                       php_stream_close(stream);
+                       RETURN_FALSE;
+               }
+               if (tmp_bytes_read && !php_stream_write(stream, buffer, tmp_bytes_read)) {
+                       php_stream_close(stream);
+                       efree(buffer);
+                       RETURN_FALSE;
+               }
+               if (buffer) {
+                       efree(buffer);
+               }
+               
+               length -= tmp_bytes_read;
+               descriptor->lob_current_position += tmp_bytes_read;
+               start += tmp_bytes_read;
+
+               if (block_length > length) {
+                       block_length = length;
+               }
+       }
+
+       php_stream_close(stream);
+       RETURN_TRUE;
+}
+/* }}} */
+
+#ifdef HAVE_OCI8_TEMP_LOB
+/* {{{ proto bool oci_lob_write_temporary(string var [, int lob_type])
+   Writes temporary blob */
+PHP_FUNCTION(oci_lob_write_temporary)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       char *data;
+       long data_len, type = OCI_TEMP_CLOB;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s|l", &data, &data_len, &type) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os|l", &z_descriptor, oci_lob_class_entry_ptr, &data, &data_len, &type) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       if (php_oci_lob_write_tmp(descriptor, type, data, data_len TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_lob_close()
+   Closes lob descriptor */
+PHP_FUNCTION(oci_lob_close)
+{
+       zval **tmp, *z_descriptor = getThis();
+       php_oci_descriptor *descriptor;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_descriptor, oci_lob_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_descriptor), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_DESCRIPTOR(*tmp, descriptor);
+
+       if (php_oci_lob_close(descriptor TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+#endif 
+
+/* {{{ proto object oci_new_descriptor(resource connection [, int type])
+   Initialize a new empty descriptor LOB/FILE (LOB is default) */
+PHP_FUNCTION(oci_new_descriptor)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+       php_oci_descriptor *descriptor;
+       long type = OCI_DTYPE_LOB;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_connection, &type) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+       /* php_oci_lob_create() checks type */
+       descriptor = php_oci_lob_create(connection, type TSRMLS_CC);    
+       
+       if (!descriptor) {
+               RETURN_NULL();
+       }
+
+       object_init_ex(return_value, oci_lob_class_entry_ptr);
+       add_property_resource(return_value, "descriptor", descriptor->id);
+}
+/* }}} */
+
+/* {{{ proto bool oci_rollback(resource connection)
+   Rollback the current context */
+PHP_FUNCTION(oci_rollback)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_connection) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+       if (connection->descriptors) {
+               zend_hash_apply(connection->descriptors,(apply_func_t) php_oci_descriptor_flush_hash_dtor TSRMLS_CC);
+       }
+
+       if (php_oci_connection_rollback(connection TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_commit(resource connection)
+   Commit the current context */
+PHP_FUNCTION(oci_commit)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_connection) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+       if (connection->descriptors) {
+               zend_hash_apply(connection->descriptors,(apply_func_t) php_oci_descriptor_flush_hash_dtor TSRMLS_CC);
+       }
+       
+       if (php_oci_connection_commit(connection TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string oci_field_name(resource stmt, int col)
+   Tell the name of a column */
+PHP_FUNCTION(oci_field_name)
+{
+       php_oci_out_column *column;
+
+       if ( ( column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU) ) ) {
+               RETURN_STRINGL(column->name, column->name_len, 1);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int oci_field_size(resource stmt, int col)
+   Tell the maximum data size of a column */
+PHP_FUNCTION(oci_field_size)
+{
+       php_oci_out_column *column;
+
+       if ( ( column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU) ) ) {
+               /* Handle data type of LONG */
+               if (column->data_type == SQLT_LNG){
+                       RETURN_LONG(column->storage_size4);
+               }
+               RETURN_LONG(column->data_size);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int oci_field_scale(resource stmt, int col)
+   Tell the scale of a column */
+PHP_FUNCTION(oci_field_scale)
+{
+       php_oci_out_column *column;
+
+       if ( ( column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU) ) ) {
+               RETURN_LONG(column->scale);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto int oci_field_precision(resource stmt, int col)
+   Tell the precision of a column */
+PHP_FUNCTION(oci_field_precision)
+{
+       php_oci_out_column *column;
+
+       if ( ( column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU) ) ) {
+               RETURN_LONG(column->precision);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto mixed oci_field_type(resource stmt, int col)
+   Tell the data type of a column */
+PHP_FUNCTION(oci_field_type)
+{
+       php_oci_out_column *column;
+
+       column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+
+       if (!column) {
+               RETURN_FALSE;
+       }
+       
+       switch (column->data_type) {
+#ifdef SQLT_TIMESTAMP
+               case SQLT_TIMESTAMP:
+                       RETVAL_STRING("TIMESTAMP",1);
+                       break;
+#endif
+#ifdef SQLT_TIMESTAMP_TZ
+               case SQLT_TIMESTAMP_TZ:
+                       RETVAL_STRING("TIMESTAMP_TZ",1);
+                       break;
+#endif
+               case SQLT_DAT:
+                       RETVAL_STRING("DATE",1);
+                       break;
+               case SQLT_NUM:
+                       RETVAL_STRING("NUMBER",1);
+                       break;
+               case SQLT_LNG:
+                       RETVAL_STRING("LONG",1);
+                       break;
+               case SQLT_BIN:
+                       RETVAL_STRING("RAW",1);
+                       break;
+               case SQLT_LBI:
+                       RETVAL_STRING("LONG RAW",1);
+                       break;
+               case SQLT_CHR:
+                       RETVAL_STRING("VARCHAR",1);
+                       break;
+               case SQLT_RSET:
+                       RETVAL_STRING("REFCURSOR",1);
+                       break;
+               case SQLT_AFC:
+                       RETVAL_STRING("CHAR",1);
+                       break;
+               case SQLT_BLOB:
+                       RETVAL_STRING("BLOB",1);
+                       break;
+               case SQLT_CLOB:
+                       RETVAL_STRING("CLOB",1);
+                       break;
+               case SQLT_BFILE:
+                       RETVAL_STRING("BFILE",1);
+                       break;
+               case SQLT_RDD:
+                       RETVAL_STRING("ROWID",1);
+                       break;
+               default:
+                       RETVAL_LONG(column->data_type);
+       }
+}
+/* }}} */
+
+/* {{{ proto int oci_field_type_raw(resource stmt, int col)
+   Tell the raw oracle data type of a column */
+PHP_FUNCTION(oci_field_type_raw)
+{
+       php_oci_out_column *column;
+
+       column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU); 
+       if (column) {
+               RETURN_LONG(column->data_type);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_field_is_null(resource stmt, int col)
+   Tell whether a column is NULL */
+PHP_FUNCTION(oci_field_is_null)
+{
+       php_oci_out_column *column;
+
+       if ( ( column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU) ) ) {
+               if (column->indicator == -1) {
+                       RETURN_TRUE;
+               }
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto void oci_internal_debug(int onoff)
+   Toggle internal debugging output for the OCI extension */
+PHP_FUNCTION(oci_internal_debug)
+{
+       zend_bool on_off;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "b", &on_off) == FAILURE) {
+               return;
+       }
+       OCI_G(debug_mode) = on_off;
+}
+/* }}} */
+
+/* {{{ proto bool oci_execute(resource stmt [, int mode])
+   Execute a parsed statement */
+PHP_FUNCTION(oci_execute)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+       ub4 mode = OCI_COMMIT_ON_SUCCESS;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r|l", &z_statement, &mode) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_statement_execute(statement, mode TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_cancel(resource stmt)
+   Cancel reading from a cursor */
+PHP_FUNCTION(oci_cancel)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_statement_cancel(statement TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_fetch(resource stmt)
+   Prepare a new row of data for reading */
+PHP_FUNCTION(oci_fetch)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+       ub4 nrows = 1; /* only one row at a time is supported for now */
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_statement_fetch(statement, nrows TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int ocifetchinto(resource stmt, array &output [, int mode])
+   Fetch a row of result data into an array */
+PHP_FUNCTION(ocifetchinto)
+{
+       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_OCI_NUM, 3);
+}
+/* }}} */
+
+/* {{{ proto int oci_fetch_all(resource stmt, array &output[, int skip[, int maxrows[, int flags]]])
+   Fetch all rows of result data into an array */
+PHP_FUNCTION(oci_fetch_all)
+{
+       zval *z_statement, *array, *element, *tmp;
+       php_oci_statement *statement;
+       php_oci_out_column **columns;
+       zval ***outarrs;
+       ub4 nrows = 1;
+       int i;
+       long rows = 0, flags = 0, skip = 0, maxrows = -1;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz/|lll", &z_statement, &array, &skip, &maxrows, &flags) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       zval_dtor(array);
+       array_init(array);
+
+       while (skip--) {
+               if (php_oci_statement_fetch(statement, nrows TSRMLS_CC)) {
+                       RETURN_LONG(0);
+               }
+       }
+
+       if (flags & PHP_OCI_FETCHSTATEMENT_BY_ROW) {
+               columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0);
+
+               for (i = 0; i < statement->ncolumns; i++) {
+                       columns[ i ] = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+               }
+
+               while (!php_oci_statement_fetch(statement, nrows TSRMLS_CC)) {
+                       zval *row;
+                       
+                       MAKE_STD_ZVAL(row);
+                       array_init(row);
+
+                       for (i = 0; i < statement->ncolumns; i++) {
+                               MAKE_STD_ZVAL(element);
+                               php_oci_column_to_zval(columns[ i ], element, PHP_OCI_RETURN_LOBS TSRMLS_CC);
+
+                               if (flags & PHP_OCI_NUM) {
+                                       zend_hash_next_index_insert(Z_ARRVAL_P(row), &element, sizeof(zval*), NULL);
+                               } else { /* default to ASSOC */
+                                       zend_hash_update(Z_ARRVAL_P(row), columns[ i ]->name, columns[ i ]->name_len+1, &element, sizeof(zval*), NULL);
+                               }
+                       }
+
+                       zend_hash_next_index_insert(Z_ARRVAL_P(array), &row, sizeof(zval*), NULL);
+                       rows++;
+
+                       if (maxrows != -1 && rows == maxrows) {
+                               php_oci_statement_cancel(statement TSRMLS_CC);
+                               break;
+                       }
+               }
+               efree(columns);
+
+       } else { /* default to BY_COLUMN */
+               columns = safe_emalloc(statement->ncolumns, sizeof(php_oci_out_column *), 0);
+               outarrs = safe_emalloc(statement->ncolumns, sizeof(zval*), 0);
+               
+               if (flags & PHP_OCI_NUM) {
+                       for (i = 0; i < statement->ncolumns; i++) {
+                               columns[ i ] = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+                               
+                               MAKE_STD_ZVAL(tmp);
+                               array_init(tmp);
+                               zend_hash_next_index_insert(Z_ARRVAL_P(array), &tmp, sizeof(zval*), (void **) &(outarrs[ i ]));
+                       }
+               } else { /* default to ASSOC */
+                       for (i = 0; i < statement->ncolumns; i++) {
+                               columns[ i ] = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+                               
+                               MAKE_STD_ZVAL(tmp);
+                               array_init(tmp);
+                               zend_hash_update(Z_ARRVAL_P(array), columns[ i ]->name, columns[ i ]->name_len+1, (void *) &tmp, sizeof(zval*), (void **) &(outarrs[ i ]));
+                       }
+               }
+
+               while (!php_oci_statement_fetch(statement, nrows TSRMLS_CC)) {
+                       for (i = 0; i < statement->ncolumns; i++) {
+                               MAKE_STD_ZVAL(element);
+                               php_oci_column_to_zval(columns[ i ], element, PHP_OCI_RETURN_LOBS TSRMLS_CC);
+                               zend_hash_index_update((*(outarrs[ i ]))->value.ht, rows, (void *)&element, sizeof(zval*), NULL);
+                       }
+
+                       rows++;
+
+                       if (maxrows != -1 && rows == maxrows) {
+                               php_oci_statement_cancel(statement TSRMLS_CC);
+                               break;
+                       }
+               }
+               
+               efree(columns);
+               efree(outarrs);
+       } 
+
+       RETURN_LONG(rows);
+}
+/* }}} */
+
+/* {{{ proto object oci_fetch_object( resource stmt )
+   Fetch a result row as an object */
+PHP_FUNCTION(oci_fetch_object)
+{
+       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_OCI_ASSOC, 2);
+
+       if (Z_TYPE_P(return_value) == IS_ARRAY) {
+               object_and_properties_init(return_value, ZEND_STANDARD_CLASS_DEF_PTR, Z_ARRVAL_P(return_value));
+       }
+}
+/* }}} */
+
+/* {{{ proto array oci_fetch_row( resource stmt )
+   Fetch a result row as an enumerated array */
+PHP_FUNCTION(oci_fetch_row)
+{
+       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_OCI_NUM, 1);
+}
+/* }}} */
+
+/* {{{ proto array oci_fetch_assoc( resource stmt )
+   Fetch a result row as an associative array */
+PHP_FUNCTION(oci_fetch_assoc)
+{
+       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_OCI_ASSOC, 1);
+}
+/* }}} */
+
+/* {{{ proto array oci_fetch_array( resource stmt [, int mode ])
+   Fetch a result row as an array */
+PHP_FUNCTION(oci_fetch_array)
+{
+       php_oci_fetch_row(INTERNAL_FUNCTION_PARAM_PASSTHRU, PHP_OCI_BOTH, 2);
+}
+/* }}} */
+
+/* {{{ proto bool oci_free_statement(resource stmt)
+   Free all resources associated with a statement */
+PHP_FUNCTION(oci_free_statement)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+       zend_list_delete(statement->id);
+       
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_close(resource connection)
+   Disconnect from database */
+PHP_FUNCTION(oci_close)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+
+       if (OCI_G(old_oci_close_semantics)) {
+               /* do nothing to keep BC */
+               return;
+       }
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_connection) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+       zend_list_delete(connection->rsrc_id);
+       ZVAL_NULL(z_connection);
+       
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto resource oci_new_connect(string user, string pass [, string db])
+   Connect to an Oracle database and log on. Returns a new session. */
+PHP_FUNCTION(oci_new_connect)
+{
+       php_oci_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 1);
+}
+/* }}} */
+
+/* {{{ proto resource oci_connect(string user, string pass [, string db])
+   Connect to an Oracle database and log on. Returns a new session. */
+PHP_FUNCTION(oci_connect)
+{
+       php_oci_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 0, 0);
+}
+/* }}} */
+
+/* {{{ proto resource oci_pconnect(string user, string pass [, string db])
+   Connect to an Oracle database using a persistent connection and log on. Returns a new session. */
+PHP_FUNCTION(oci_pconnect)
+{
+       php_oci_do_connect(INTERNAL_FUNCTION_PARAM_PASSTHRU, 1, 0);
+}
+/* }}} */
+
+/* {{{ proto array oci_error([resource stmt|connection|global])
+   Return the last error of stmt|connection|global. If no error happened returns false. */
+PHP_FUNCTION(oci_error)
+{
+       zval *arg;
+       php_oci_statement *statement;
+       php_oci_connection *connection;
+       text *errbuf;
+       sb4 errcode = 0;
+       sword error = 0;
+       dvoid *errh = NULL;
+#ifdef HAVE_OCI8_ATTR_STATEMENT
+       ub2 error_offset = 0;
+       text *sqltext = NULL;
+#endif
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "|r", &arg) == SUCCESS) {
+               statement = (php_oci_statement *) zend_fetch_resource(&arg TSRMLS_CC, -1, NULL, NULL, 1, le_statement);
+       
+               if (statement) {
+                       errh = statement->err;
+                       error = statement->errcode;
+
+#ifdef HAVE_OCI8_ATTR_STATEMENT
+                       if (php_oci_fetch_sqltext_offset(statement, &sqltext, &error_offset TSRMLS_CC)) {
+                               RETURN_FALSE;
+                       }
+#endif
+               } else {
+                       connection = (php_oci_connection *) zend_fetch_resource(&arg TSRMLS_CC, -1, NULL, NULL, 1, le_connection);
+                       
+                       if (connection) {
+                               errh = connection->err;
+                               error = connection->errcode;
+                       }
+               }
+       } else {
+               errh = OCI_G(err);
+               error = OCI_G(errcode);
+       }
+
+       if (error == OCI_SUCCESS) { /* no error set in the handle */
+               RETURN_FALSE;
+       }
+
+       if (!errh) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "OCIError: unable to find error handle");
+               RETURN_FALSE;
+       }
+
+       errcode = php_oci_fetch_errmsg(errh, &errbuf TSRMLS_CC);
+
+       if (errcode) {
+               array_init(return_value);
+               add_assoc_long(return_value, "code", errcode);
+               add_assoc_string(return_value, "message", (char*) errbuf, 0);
+#ifdef HAVE_OCI8_ATTR_STATEMENT
+               add_assoc_long(return_value, "offset", error_offset);
+               add_assoc_string(return_value, "sqltext", sqltext ? (char *) sqltext : "", 1);
+#endif
+       } else {
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+/* {{{ proto int oci_num_fields(resource stmt)
+   Return the number of result columns in a statement */
+PHP_FUNCTION(oci_num_fields)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       RETURN_LONG(statement->ncolumns);
+}
+/* }}} */
+
+/* {{{ proto resource oci_parse(resource connection, string query)
+   Parse a query and return a statement */
+PHP_FUNCTION(oci_parse)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+       php_oci_statement *statement;
+       char *query;
+       long query_len;
+       zend_bool cached = 0;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|b", &z_connection, &query, &query_len, &cached) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+       statement = php_oci_statement_create(connection, query, query_len, cached TSRMLS_CC);
+
+       if (statement) {
+               RETURN_RESOURCE(statement->id);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_set_prefetch(resource stmt, int prefetch_rows)
+  Sets the number of rows to be prefetched on execute to prefetch_rows for stmt */
+PHP_FUNCTION(oci_set_prefetch)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+       long size;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rl", &z_statement, &size) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_statement_set_prefetch(statement, size TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_password_change(resource connection, string username, string old_password, string new_password)
+  Changes the password of an account */
+PHP_FUNCTION(oci_password_change)
+{
+       zval *z_connection;
+       text *user, *pass_old, *pass_new, *dbname;
+       long user_len, pass_old_len, pass_new_len, dbname_len;
+       php_oci_connection *connection;
+
+       /*  Disable in Safe Mode  */
+       if (PG(safe_mode)) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "is disabled in Safe Mode");
+               RETURN_FALSE;
+       }
+
+       if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "rsss", &z_connection, &user, &user_len, &pass_old, &pass_old_len, &pass_new, &pass_new_len) == SUCCESS) {
+               PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+               if (php_oci_password_change(connection, user, user_len, pass_old, pass_old_len, pass_new, pass_new_len TSRMLS_CC)) {
+                       RETURN_FALSE;
+               }
+               RETURN_TRUE;
+       } else if (zend_parse_parameters_ex(ZEND_PARSE_PARAMS_QUIET, ZEND_NUM_ARGS() TSRMLS_CC, "ssss", &dbname, &dbname_len, &user, &user_len, &pass_old, &pass_old_len, &pass_new, &pass_new_len) == SUCCESS) {
+
+               connection = php_oci_do_connect_ex(user, user_len, pass_old, pass_old_len, pass_new, pass_new_len, dbname, dbname_len, NULL, OCI_DEFAULT, 0, 0 TSRMLS_CC);
+               if (!connection) {
+                       RETURN_FALSE;
+               }
+               RETURN_RESOURCE(connection->rsrc_id);
+       }
+       WRONG_PARAM_COUNT;
+}
+/* }}} */
+
+/* {{{ proto resource oci_new_cursor(resource connection)
+   Return a new cursor (Statement-Handle) - use this to bind ref-cursors! */
+PHP_FUNCTION(oci_new_cursor)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+       php_oci_statement *statement;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_connection) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+       statement = php_oci_statement_create(connection, NULL, 0, 0 TSRMLS_CC);
+       
+       if (statement) {
+               RETURN_RESOURCE(statement->id);
+       }
+       RETURN_FALSE;
+}
+/* }}} */
+
+/* {{{ proto string oci_result(resource stmt, mixed column)
+   Return a single column of result data */
+PHP_FUNCTION(oci_result)
+{
+       php_oci_out_column *column;
+       
+       column = php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAM_PASSTHRU);
+       if(column) {
+               php_oci_column_to_zval(column, return_value, 0 TSRMLS_CC);
+       }
+       else {
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+/* {{{ proto string oci_server_version(resource connection)
+   Return a string containing server version information */
+PHP_FUNCTION(oci_server_version)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+       char *version = NULL;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_connection) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+
+       if (php_oci_server_get_version(connection, &version TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       
+       RETURN_STRING(version, 0);
+}
+/* }}} */
+
+/* {{{ proto string oci_statement_type(resource stmt)
+   Return the query type of an OCI statement */
+PHP_FUNCTION(oci_statement_type)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+       ub2 type;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_statement_get_type(statement, &type TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+
+       switch (type) {
+               case OCI_STMT_SELECT:
+                       RETVAL_STRING("SELECT",1);
+                       break;
+               case OCI_STMT_UPDATE:
+                       RETVAL_STRING("UPDATE",1);
+                       break;
+               case OCI_STMT_DELETE:
+                       RETVAL_STRING("DELETE",1);
+                       break;
+               case OCI_STMT_INSERT:
+                       RETVAL_STRING("INSERT",1);
+                       break;
+               case OCI_STMT_CREATE:
+                       RETVAL_STRING("CREATE",1);
+                       break;
+               case OCI_STMT_DROP:
+                       RETVAL_STRING("DROP",1);
+                       break;
+               case OCI_STMT_ALTER:
+                       RETVAL_STRING("ALTER",1);
+                       break;
+               case OCI_STMT_BEGIN:
+                       RETVAL_STRING("BEGIN",1);
+                       break;
+               case OCI_STMT_DECLARE:
+                       RETVAL_STRING("DECLARE",1);
+                       break;
+               default:
+                       RETVAL_STRING("UNKNOWN",1);
+       }
+}
+/* }}} */
+
+/* {{{ proto int oci_num_rows(resource stmt)
+   Return the row count of an OCI statement */
+PHP_FUNCTION(oci_num_rows)
+{
+       zval *z_statement;
+       php_oci_statement *statement;
+       ub4 rowcount;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "r", &z_statement) == FAILURE) {
+               return;
+       }
+
+       PHP_OCI_ZVAL_TO_STATEMENT(z_statement, statement);
+
+       if (php_oci_statement_get_numrows(statement, &rowcount TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_LONG(rowcount);
+}
+/* }}} */
+
+#ifdef PHP_OCI8_HAVE_COLLECTIONS
+/* {{{ proto bool oci_free_collection()
+   Deletes collection object*/
+PHP_FUNCTION(oci_free_collection)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_collection, oci_coll_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       zend_list_delete(collection->id);
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_collection_append(string value)
+   Append an object to the collection */
+PHP_FUNCTION(oci_collection_append)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+       char *value;
+       long value_len;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "s", &value, &value_len) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Os", &z_collection, oci_coll_class_entry_ptr, &value, &value_len) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       if (php_oci_collection_append(collection, value, value_len TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto string oci_collection_element_get(int ndx)
+   Retrieve the value at collection index ndx */
+PHP_FUNCTION(oci_collection_element_get)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+       long element_index;
+       zval *value;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &element_index) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &z_collection, oci_coll_class_entry_ptr, &element_index) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       if (php_oci_collection_element_get(collection, element_index, &value TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       
+       *return_value = *value;
+       zval_copy_ctor(return_value);
+       zval_ptr_dtor(&value);
+}
+/* }}} */
+
+/* {{{ proto bool oci_collection_assign(object from)
+   Assign a collection from another existing collection */
+PHP_FUNCTION(oci_collection_assign)
+{
+       zval **tmp_dest, **tmp_from, *z_collection_dest = getThis(), *z_collection_from;
+       php_oci_collection *collection_dest, *collection_from;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_collection_from, oci_coll_class_entry_ptr) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "OO", &z_collection_dest, oci_coll_class_entry_ptr, &z_collection_from, oci_coll_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection_dest), "collection", sizeof("collection"), (void **)&tmp_dest) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property. The first argument should be valid collection object");
+               RETURN_FALSE;
+       }
+
+       if (zend_hash_find(Z_OBJPROP_P(z_collection_from), "collection", sizeof("collection"), (void **)&tmp_from) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property. The second argument should be valid collection object");
+               RETURN_FALSE;
+       }
+
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp_dest, collection_dest);
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp_from, collection_from);
+
+       if (php_oci_collection_assign(collection_dest, collection_from TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto bool oci_collection_element_assign(int index, string val)
+   Assign element val to collection at index ndx */
+PHP_FUNCTION(oci_collection_element_assign)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+       long element_index, value_len;
+       char *value;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "ls", &element_index, &value, &value_len) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ols", &z_collection, oci_coll_class_entry_ptr, &element_index, &value, &value_len) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       if (php_oci_collection_element_set(collection, element_index, value, value_len TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;
+}
+/* }}} */
+
+/* {{{ proto int oci_collection_size()
+   Return the size of a collection */
+PHP_FUNCTION(oci_collection_size)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+       sb4 size = 0;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_collection, oci_coll_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       if (php_oci_collection_size(collection, &size TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_LONG(size);
+}
+/* }}} */
+
+/* {{{ proto int oci_collection_max()
+   Return the max value of a collection. For a varray this is the maximum length of the array */
+PHP_FUNCTION(oci_collection_max)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+       long max;
+       
+       if (!getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "O", &z_collection, oci_coll_class_entry_ptr) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       if (php_oci_collection_max(collection, &max TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_LONG(max);
+}
+/* }}} */
+
+/* {{{ proto bool oci_collection_trim(int num)
+   Trim num elements from the end of a collection */
+PHP_FUNCTION(oci_collection_trim)
+{
+       zval **tmp, *z_collection = getThis();
+       php_oci_collection *collection;
+       long trim_size;
+
+       if (getThis()) {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "l", &trim_size) == FAILURE) {
+                       return;
+               }
+       }
+       else {
+               if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "Ol", &z_collection, oci_coll_class_entry_ptr, &trim_size) == FAILURE) {
+                       return;
+               }       
+       }
+       
+       if (zend_hash_find(Z_OBJPROP_P(z_collection), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+               RETURN_FALSE;
+       }
+       
+       PHP_OCI_ZVAL_TO_COLLECTION(*tmp, collection);
+
+       if (php_oci_collection_trim(collection, trim_size TSRMLS_CC)) {
+               RETURN_FALSE;
+       }
+       RETURN_TRUE;    
+}
+/* }}} */
+
+/* {{{ proto object oci_new_collection(resource connection, string tdo [, string schema])
+   Initialize a new collection */
+PHP_FUNCTION(oci_new_collection)
+{
+       zval *z_connection;
+       php_oci_connection *connection;
+       php_oci_collection *collection;
+       char *tdo, *schema = NULL;
+       long tdo_len, schema_len = 0;
+       
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rs|s", &z_connection, &tdo, &tdo_len, &schema, &schema_len) == FAILURE) {
+               return;
+       }
+    
+       PHP_OCI_ZVAL_TO_CONNECTION(z_connection, connection);
+       
+       if ( (collection = php_oci_collection_create(connection, tdo, tdo_len, schema, schema_len TSRMLS_CC)) ) {
+               object_init_ex(return_value, oci_coll_class_entry_ptr);
+               add_property_resource(return_value, "collection", collection->id);
+       }
+       else {
+               RETURN_FALSE;
+       }
+}
+/* }}} */
+
+#endif
+
+#endif /* HAVE_OCI8 */
diff --git a/ext/oci8/oci8_lob.c b/ext/oci8/oci8_lob.c
new file mode 100644 (file)
index 0000000..d4fd182
--- /dev/null
@@ -0,0 +1,686 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2005 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   |          Thies C. Arntzen <thies@thieso.net>                         |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "php_ini.h"
+
+#if HAVE_OCI8
+
+#include "php_oci8.h"
+#include "php_oci8_int.h"
+
+/* for import/export functions */
+#include <fcntl.h>
+
+#ifndef O_BINARY
+#define O_BINARY 0
+#endif
+
+/* {{{ php_oci_lob_create()
+ Create LOB descriptor and allocate all the resources needed */
+php_oci_descriptor *php_oci_lob_create (php_oci_connection *connection, long type TSRMLS_DC)
+{
+       php_oci_descriptor *descriptor;
+
+       switch (type) {
+               case OCI_DTYPE_FILE:
+               case OCI_DTYPE_LOB:
+               case OCI_DTYPE_ROWID:
+                       /* these three are allowed */
+                       break;
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown descriptor type %ld.", type);
+                       return NULL;
+                       break;
+       }
+
+       descriptor = emalloc(sizeof(php_oci_descriptor));
+       descriptor->type = type;
+
+       OCI_G(errcode) = PHP_OCI_CALL(OCIDescriptorAlloc, (connection->env, (dvoid*)&(descriptor->descriptor), descriptor->type, (size_t) 0, (dvoid **) 0));
+
+       if (OCI_G(errcode) != OCI_SUCCESS) {
+               connection->errcode = php_oci_error(OCI_G(err), OCI_G(errcode) TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               efree(descriptor);
+               return NULL;
+       }
+
+       descriptor->connection = connection;
+
+       PHP_OCI_REGISTER_RESOURCE(descriptor, le_descriptor);
+       
+       descriptor->lob_current_position = 0;
+       descriptor->lob_size = -1;                              /* we should set it to -1 to know, that it's just not initialized */
+       descriptor->buffering = PHP_OCI_LOB_BUFFER_DISABLED;                            /* buffering is off by default */
+
+       if (descriptor->type == OCI_DTYPE_LOB || descriptor->type == OCI_DTYPE_FILE) {
+               /* add Lobs & Files to hash. we'll flush them at the end */
+               if (!connection->descriptors) {
+                       ALLOC_HASHTABLE(connection->descriptors);
+                       zend_hash_init(connection->descriptors, 13, NULL, php_oci_descriptor_flush_hash_dtor, 0);
+               }
+
+               zend_hash_next_index_insert(connection->descriptors,&descriptor,sizeof(php_oci_descriptor *),NULL);
+       }
+       return descriptor;
+
+} /* }}} */
+
+/* {{{ php_oci_lob_get_length() 
+ Get length of the LOB. The length is cached so we don't need to ask Oracle every time */
+int php_oci_lob_get_length (php_oci_descriptor *descriptor, ub4 *length TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+
+       *length = 0;
+       
+       if (descriptor->lob_size >= 0) {
+               *length = descriptor->lob_size;
+               return 0;
+       } else {
+               if (descriptor->type == OCI_DTYPE_FILE) {
+                       connection->errcode = PHP_OCI_CALL(OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
+                       if (connection->errcode != OCI_SUCCESS) {
+                               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                               return 1;
+                       }
+               }
+               
+               connection->errcode = PHP_OCI_CALL(OCILobGetLength, (connection->svc, connection->err, descriptor->descriptor, (ub4 *)length));
+
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       return 1;
+               }
+
+               descriptor->lob_size = *length;
+
+               if (descriptor->type == OCI_DTYPE_FILE) {
+                       connection->errcode = PHP_OCI_CALL(OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
+
+                       if (connection->errcode != OCI_SUCCESS) {
+                               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                               return 1;
+                       }
+               }
+       }
+       return 0;       
+} /* }}} */
+
+/* {{{ php_oci_lob_read() 
+ Read specified portion of the LOB into the buffer */
+int php_oci_lob_read (php_oci_descriptor *descriptor, long read_length, long offset, char **data, ub4 *data_len TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       ub4 length = 0;
+       ub4 block_length = PHP_OCI_LOB_BUFFER_SIZE;
+       int bytes_read;
+       int requested_len = read_length; /* this is by default */
+
+       *data_len = 0;
+       *data = NULL;
+
+       if (php_oci_lob_get_length(descriptor, &length TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if (offset > length) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Offset must be less than size of the LOB");
+               return 1;
+       }
+               
+       if (read_length == -1) {
+               requested_len = length;
+       }
+       
+       if (requested_len > (length - offset)) {
+               requested_len = length - offset;
+       }
+       
+       if (requested_len == 0) {
+               return 0;
+       }
+
+       if (requested_len < block_length) {
+               block_length = requested_len;
+       }
+       
+       if (descriptor->type == OCI_DTYPE_FILE) {
+               connection->errcode = PHP_OCI_CALL(OCILobFileOpen, (connection->svc, connection->err, descriptor->descriptor, OCI_FILE_READONLY));
+
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       return 1;
+               }
+       }
+
+       *data = emalloc(block_length + 1);
+       bytes_read = block_length;
+
+       while (bytes_read > 0 && *data_len < requested_len && offset < length) { 
+               
+               connection->errcode = PHP_OCI_CALL(OCILobRead, 
+                       (
+                               connection->svc, 
+                               connection->err, 
+                               descriptor->descriptor, 
+                               &bytes_read,                                                            /* IN/OUT bytes toread/read */ 
+                               offset + 1,                                                             /* offset (starts with 1) */ 
+                               (dvoid *) ((char *) *data + *data_len), 
+                               block_length,                                                                   /* size of buffer */ 
+                               (dvoid *)0, 
+                               (OCICallbackLobRead) 0,                                 /* callback... */ 
+                               (ub2) connection->charset,      /* The character set ID of the buffer data. */ 
+                               (ub1) SQLCS_IMPLICIT                                    /* The character set form of the buffer data. */
+                       )
+               );
+
+               offset += bytes_read;
+               *data_len += bytes_read;
+               block_length = PHP_OCI_LOB_BUFFER_SIZE;
+               descriptor->lob_current_position += bytes_read;
+
+               if (*data_len < requested_len && connection->errcode == OCI_NEED_DATA) {
+                       *data = erealloc(*data, *data_len + PHP_OCI_LOB_BUFFER_SIZE + 1);       
+                       continue;
+               } else {
+                       break;
+               }
+       }
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               efree(*data);
+               *data = NULL;
+               return 1;
+       }
+
+       if (descriptor->type == OCI_DTYPE_FILE) {
+               connection->errcode = PHP_OCI_CALL(OCILobFileClose, (connection->svc, connection->err, descriptor->descriptor));
+
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       efree(*data);
+                       *data = NULL;
+                       return 1;
+               }
+       }
+
+       *data = erealloc(*data, *data_len + 1);
+       (*data)[ *data_len ] = 0;
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_write() 
+ Write data to the LOB */
+int php_oci_lob_write (php_oci_descriptor *descriptor, ub4 offset, char *data, long data_len, ub4 *bytes_written TSRMLS_DC)
+{
+       OCILobLocator *lob         = (OCILobLocator *) descriptor->descriptor;
+       php_oci_connection *connection = (php_oci_connection *) descriptor->connection;
+       ub4 lob_length;
+       
+       *bytes_written = 0;
+       if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if (!data || data_len <= 0) {
+               return 0;
+       }
+       
+       if (offset < 0) {
+               offset = 0;
+       }
+       
+       if (offset > descriptor->lob_current_position) {
+               offset = descriptor->lob_current_position;
+       }
+       
+       connection->errcode = PHP_OCI_CALL(OCILobWrite, (connection->svc, connection->err, lob, (ub4 *)&data_len, (ub4) offset + 1, (dvoid *) data, (ub4) data_len, OCI_ONE_PIECE, (dvoid *)0, (OCICallbackLobWrite) 0, (ub2) 0, (ub1) SQLCS_IMPLICIT));
+
+       if (connection->errcode) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               *bytes_written = 0;
+               return 1;
+       }
+       *bytes_written = data_len;
+       descriptor->lob_current_position += data_len;
+       
+       if (descriptor->lob_current_position > descriptor->lob_size) {
+               descriptor->lob_size = descriptor->lob_current_position;
+       }
+       
+       /* marking buffer as used */
+       if (descriptor->buffering == PHP_OCI_LOB_BUFFER_ENABLED) {
+               descriptor->buffering = PHP_OCI_LOB_BUFFER_USED;
+       }
+       
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_set_buffering() 
+ Turn buffering off/onn for this particular LOB */
+int php_oci_lob_set_buffering (php_oci_descriptor *descriptor, int on_off TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+
+       if (!on_off && descriptor->buffering == PHP_OCI_LOB_BUFFER_DISABLED) {
+               /* disabling when it's already off */
+               return 0;
+       }
+       
+       if (on_off && descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
+               /* enabling when it's already on */
+               return 0;
+       }
+       
+       if (on_off) {
+               connection->errcode = PHP_OCI_CALL(OCILobEnableBuffering, (connection->svc, connection->err, descriptor->descriptor));
+       }
+       else {
+               connection->errcode = PHP_OCI_CALL(OCILobDisableBuffering, (connection->svc, connection->err, descriptor->descriptor));
+       }
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       descriptor->buffering = on_off ? PHP_OCI_LOB_BUFFER_ENABLED : PHP_OCI_LOB_BUFFER_DISABLED;
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_get_buffering()
+ Return current buffering state for the LOB */
+int php_oci_lob_get_buffering (php_oci_descriptor *descriptor TSRMLS_DC)
+{
+       if (descriptor->buffering != PHP_OCI_LOB_BUFFER_DISABLED) {
+               return 1;
+       } 
+       else {
+               return 0;
+       }
+} /* }}} */
+
+/* {{{ php_oci_lob_copy()
+ Copy one LOB (or its part) to another one */
+int php_oci_lob_copy (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from, long length TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor_dest->connection;
+       int length_dest, length_from, copy_len;
+       
+       if (php_oci_lob_get_length(descriptor_dest, &length_dest TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if (php_oci_lob_get_length(descriptor_from, &length_from TSRMLS_CC)) {
+               return 1;
+       }
+
+       if (length == -1) {
+               copy_len = length_from - descriptor_from->lob_current_position;
+       }
+       else {
+               copy_len = length;
+       }
+
+       if ((int)copy_len <= 0) {
+               /* silently fail, there is nothing to copy */
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCILobCopy, (connection->svc, connection->err, descriptor_dest->descriptor, descriptor_from->descriptor, copy_len, descriptor_dest->lob_current_position+1, descriptor_from->lob_current_position+1));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_close() 
+ Close LOB */
+int php_oci_lob_close (php_oci_descriptor *descriptor TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       int is_temporary;
+       
+       connection->errcode = PHP_OCI_CALL(OCILobClose, (connection->svc, connection->err, descriptor->descriptor));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       
+       connection->errcode = PHP_OCI_CALL(OCILobIsTemporary, (connection->env,connection->err, descriptor->descriptor, &is_temporary));
+       
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       
+       if (is_temporary) {
+               
+               connection->errcode = PHP_OCI_CALL(OCILobFreeTemporary, (connection->svc, connection->err, descriptor->descriptor));
+               
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       return 1;
+               }
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_flush() 
+ Flush buffers for the LOB (only if they have been used) */
+int php_oci_lob_flush(php_oci_descriptor *descriptor, int flush_flag TSRMLS_DC)
+{
+       OCILobLocator *lob = descriptor->descriptor;
+       php_oci_connection *connection = descriptor->connection;
+       
+       if (!lob) {
+               return 1;
+       }
+
+       switch (flush_flag) {
+               case 0:
+               case OCI_LOB_BUFFER_FREE:
+                       /* only these two are allowed */
+                       break;
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid flag value: %d", flush_flag);
+                       return 1;
+                       break;
+       }
+       
+       /* do not really flush buffer, but report success
+        * to suppress OCI error when flushing not used buffer
+        * */
+       if (descriptor->buffering != PHP_OCI_LOB_BUFFER_USED) {
+               return 0;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCILobFlushBuffer, (connection->svc, connection->err, lob, flush_flag));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+
+       /* marking buffer as enabled and not used */
+       descriptor->buffering = PHP_OCI_LOB_BUFFER_ENABLED;
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_free()
+ Close LOB descriptor and free associated resources */
+void php_oci_lob_free (php_oci_descriptor *descriptor TSRMLS_DC)
+{
+       /* flushing Lobs & Files with buffering enabled */
+       if ((descriptor->type == OCI_DTYPE_FILE || descriptor->type == OCI_DTYPE_LOB) && descriptor->buffering == PHP_OCI_LOB_BUFFER_USED) {
+               php_oci_lob_flush(descriptor, OCI_LOB_BUFFER_FREE TSRMLS_CC);
+       }
+
+       PHP_OCI_CALL(OCIDescriptorFree, (descriptor->descriptor, descriptor->type));
+       efree(descriptor);
+} /* }}} */
+
+/* {{{ php_oci_lob_import()
+ Import LOB contents from the given file */
+int php_oci_lob_import (php_oci_descriptor *descriptor, char *filename TSRMLS_DC)
+{
+       int fp, loblen;
+       OCILobLocator *lob = (OCILobLocator *)descriptor->descriptor;
+       php_oci_connection *connection = descriptor->connection;
+       char buf[8192];
+       ub4 offset = 1;
+       
+       if ((PG(safe_mode) && (!php_checkuid(filename, NULL, CHECKUID_CHECK_FILE_AND_DIR))) || php_check_open_basedir(filename TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if ((fp = VCWD_OPEN(filename, O_RDONLY|O_BINARY)) == -1) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Can't open file %s", filename);
+               return 1;
+       }
+
+       while ((loblen = read(fp, &buf, sizeof(buf))) > 0) {    
+               connection->errcode = PHP_OCI_CALL(
+                               OCILobWrite,
+                               (
+                                       connection->svc, 
+                                       connection->err, 
+                                       lob, 
+                                       &loblen, 
+                                       (ub4) offset, 
+                                       (dvoid *) &buf, 
+                                       (ub4) loblen, 
+                                       OCI_ONE_PIECE, 
+                                       (dvoid *)0, 
+                                       (OCICallbackLobWrite) 0, 
+                                       (ub2) 0, 
+                                       (ub1) SQLCS_IMPLICIT
+                               )
+               );
+
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       close(fp);
+                       return 1;
+               }
+               offset += loblen;
+       }
+       close(fp);
+       
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_append()
+ Append data to the end of the LOB */
+int php_oci_lob_append (php_oci_descriptor *descriptor_dest, php_oci_descriptor *descriptor_from TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor_dest->connection;
+       OCILobLocator *lob_dest = descriptor_dest->descriptor;
+       OCILobLocator *lob_from = descriptor_from->descriptor;
+       ub4 dest_len, from_len;
+
+       if (php_oci_lob_get_length(descriptor_dest, &dest_len TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if (php_oci_lob_get_length(descriptor_from, &from_len TSRMLS_CC)) {
+               return 1;
+       }
+
+       if (from_len <= 0) {
+               return 0;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCILobAppend, (connection->svc, connection->err, lob_dest, lob_from));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_truncate()
+ Truncate LOB to the given length */
+int php_oci_lob_truncate (php_oci_descriptor *descriptor, long new_lob_length TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       OCILobLocator *lob = descriptor->descriptor;
+       ub4 lob_length;
+       
+       if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if (lob_length <= 0) {
+               return 0;
+       }
+
+       if (new_lob_length < 0) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be greater than or equal to 0");
+               return 1;
+       }
+
+       if (new_lob_length > lob_length) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Size must be less than or equal to the current LOB size");
+               return 1;
+       }
+       
+       connection->errcode = PHP_OCI_CALL(OCILobTrim, (connection->svc, connection->err, lob, new_lob_length));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       
+       descriptor->lob_size = new_lob_length;
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_erase()
+ Erase (or fill with whitespaces, depending on LOB type) the LOB (or its part) */
+int php_oci_lob_erase (php_oci_descriptor *descriptor, long offset, long length, ub4 *bytes_erased TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       OCILobLocator *lob = descriptor->descriptor;
+       ub4 lob_length;
+
+       *bytes_erased = 0;
+       
+       if (php_oci_lob_get_length(descriptor, &lob_length TSRMLS_CC)) {
+               return 1;
+       }
+       
+       if (offset == -1) {
+               offset = descriptor->lob_current_position;
+       }
+
+       if (length == -1) {
+               length = lob_length;
+       }
+       
+       connection->errcode = PHP_OCI_CALL(OCILobErase, (connection->svc, connection->err, lob, (ub4 *)&length, offset+1));
+
+       if (connection->errcode != OCI_SUCCESS) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       
+       *bytes_erased = length;
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_is_equal() 
+ Compare to LOB descriptors and figure out if they are pointing to the same LOB */
+int php_oci_lob_is_equal (php_oci_descriptor *descriptor_first, php_oci_descriptor *descriptor_second, boolean *result TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor_first->connection;
+       OCILobLocator *first_lob   = descriptor_first->descriptor;
+       OCILobLocator *second_lob  = descriptor_second->descriptor;
+
+       connection->errcode = PHP_OCI_CALL(OCILobIsEqual, (connection->env, first_lob, second_lob, result));
+
+       if (connection->errcode) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_lob_write_tmp() 
+ Create temporary LOB and write data to it */
+int php_oci_lob_write_tmp (php_oci_descriptor *descriptor, ub1 type, char *data, long data_len TSRMLS_DC)
+{
+       php_oci_connection *connection = descriptor->connection;
+       OCILobLocator *lob         = descriptor->descriptor;
+       ub4 bytes_written = 0;
+       
+       switch (type) {
+               case OCI_TEMP_BLOB:
+               case OCI_TEMP_CLOB:
+                       /* only these two are allowed */
+                       break;
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid temporary lob type: %d", type);
+                       return 1;
+                       break;
+       }
+
+       if (!data || data_len <= 0) {
+               /* nothing to write, silently fail */
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCILobCreateTemporary, (connection->svc, connection->err, lob, OCI_DEFAULT, OCI_DEFAULT, type, OCI_ATTR_NOCACHE, OCI_DURATION_SESSION));
+
+       if (connection->errcode) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+
+       connection->errcode = PHP_OCI_CALL(OCILobOpen, (connection->svc, connection->err, lob, OCI_LOB_READWRITE));
+
+       if (connection->errcode) {
+               php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+               return 1;
+       }
+
+       return php_oci_lob_write(descriptor, 0, data, data_len, &bytes_written TSRMLS_CC);
+} /* }}} */
+
+#endif /* HAVE_OCI8 */
diff --git a/ext/oci8/oci8_statement.c b/ext/oci8/oci8_statement.c
new file mode 100644 (file)
index 0000000..39cdfbf
--- /dev/null
@@ -0,0 +1,992 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2005 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   |          Thies C. Arntzen <thies@thieso.net>                         |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+
+#ifdef HAVE_CONFIG_H
+#include "config.h"
+#endif
+
+#include "php.h"
+#include "ext/standard/info.h"
+#include "php_ini.h"
+
+#if HAVE_OCI8
+
+#include "php_oci8.h"
+#include "php_oci8_int.h"
+
+/* {{{ php_oci_statement_create() 
+ Create statemend handle and allocate necessary resources */
+php_oci_statement *php_oci_statement_create (php_oci_connection *connection, char *query, long query_len, zend_bool cached TSRMLS_DC)
+{
+       php_oci_statement *statement;
+       
+       statement = ecalloc(1,sizeof(php_oci_statement));
+
+#if HAVE_OCI_STMT_PREPARE2
+       if (!query_len) {
+               /* do not allocate stmt handle for refcursors, we'll get it from OCIStmtPrepare2() */
+               PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->stmt), OCI_HTYPE_STMT, 0, NULL));
+       }
+#else
+       PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->stmt), OCI_HTYPE_STMT, 0, NULL));
+#endif
+                       
+       PHP_OCI_CALL(OCIHandleAlloc, (connection->env, (dvoid **)&(statement->err), OCI_HTYPE_ERROR, 0, NULL));
+       
+       if (query_len > 0) {
+#if HAVE_OCI_STMT_PREPARE2
+               connection->errcode = PHP_OCI_CALL(OCIStmtPrepare2, (connection->svc, &(statement->stmt), connection->err, (text *)query, query_len, NULL, 0, OCI_NTV_SYNTAX, OCI_DEFAULT));
+#else
+               connection->errcode = PHP_OCI_CALL(OCIStmtPrepare, (statement->stmt, connection->err, (text *)query, query_len, OCI_NTV_SYNTAX, OCI_DEFAULT));
+#endif         
+               if (connection->errcode != OCI_SUCCESS) {
+                       php_oci_error(connection->err, connection->errcode TSRMLS_CC);
+
+#if HAVE_OCI_STMT_PREPARE2
+                       PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, OCI_DEFAULT));
+                       PHP_OCI_CALL(OCIHandleFree,(statement->err, OCI_HTYPE_ERROR));
+#else
+                       PHP_OCI_CALL(OCIHandleFree,(statement->stmt, OCI_HTYPE_STMT));
+                       PHP_OCI_CALL(OCIHandleFree,(statement->err, OCI_HTYPE_ERROR));
+#endif
+                       
+                       efree(statement);
+                       PHP_OCI_HANDLE_ERROR(connection, connection->errcode);
+                       return NULL;
+               }
+       }
+       
+       if (query && query_len) {
+               statement->last_query = estrndup(query, query_len);
+               statement->last_query_len = query_len;
+       }
+       else {
+               statement->last_query = NULL;
+               statement->last_query_len = 0;
+       }
+
+       statement->connection = connection;
+       statement->has_data = 0;
+
+       if (OCI_G(default_prefetch) > 0) {
+               php_oci_statement_set_prefetch(statement, OCI_G(default_prefetch) TSRMLS_CC);
+       }
+       
+       PHP_OCI_REGISTER_RESOURCE(statement, le_statement);
+       
+       return statement;
+}
+/* }}} */
+
+/* {{{ php_oci_statement_set_prefetch()
+ Set prefetch buffer size for the statement (we're assuming that one row is ~1K sized) */
+int php_oci_statement_set_prefetch(php_oci_statement *statement, ub4 size TSRMLS_DC)
+{ 
+       ub4 prefetch = size * 1024;
+
+       if (size < 1) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Number of rows has to be greater than or equal to 1");
+               return 1;
+       }
+       
+       statement->errcode = PHP_OCI_CALL (OCIAttrSet, (statement->stmt, OCI_HTYPE_STMT, &prefetch, 0, OCI_ATTR_PREFETCH_MEMORY, statement->err));
+
+       if (statement->errcode != OCI_SUCCESS) {
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+               return 1;
+       }
+
+       prefetch = size;
+       statement->errcode = PHP_OCI_CALL (OCIAttrSet, (statement->stmt, OCI_HTYPE_STMT, &prefetch, 0, OCI_ATTR_PREFETCH_ROWS, statement->err));
+       
+       if (statement->errcode != OCI_SUCCESS) {
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+               return 1;
+       }
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ php_oci_statement_fetch() 
+ Fetch a row from the statement */
+int php_oci_statement_fetch(php_oci_statement *statement, ub4 nrows TSRMLS_DC)
+{
+       int i;
+       php_oci_out_column *column;
+
+       statement->errcode = PHP_OCI_CALL(OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
+
+       if ( statement->errcode == OCI_NO_DATA || nrows == 0 ) {
+               if (statement->last_query == NULL) {
+                       /* reset define-list for refcursors */
+                       if (statement->columns) {
+                               zend_hash_destroy(statement->columns);
+                               efree(statement->columns);
+                               statement->columns = NULL;
+                               statement->ncolumns = 0;
+                       }
+                       statement->executed = 0;
+               }
+
+               statement->errcode = 0; /* OCI_NO_DATA is NO error for us!!! */
+               statement->has_data = 0;
+
+               if (nrows == 0) {
+                       /* this is exactly what we requested */
+                       return 0;
+               }
+               
+               return 1;
+       }
+
+       /* reset length for all piecewise columns */
+       for (i = 0; i < statement->ncolumns; i++) {
+               column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+               if (column->piecewise) {
+                       column->retlen4 = 0;
+               }
+       }
+       
+       while (statement->errcode == OCI_NEED_DATA) {
+               for (i = 0; i < statement->ncolumns; i++) {
+                       column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+                       if (column->piecewise)  {
+                               if (!column->data) {
+                                       column->data = (text *) emalloc(PHP_OCI_PIECE_SIZE);
+                               } else {
+                                       column->data = erealloc(column->data, column->retlen4 + PHP_OCI_PIECE_SIZE);
+                               }
+
+                               column->cb_retlen = PHP_OCI_PIECE_SIZE;
+
+                               PHP_OCI_CALL( OCIStmtSetPieceInfo, ((void *) column->oci_define, OCI_HTYPE_DEFINE, statement->err, ((char*)column->data) + column->retlen4, &(column->cb_retlen), OCI_NEXT_PIECE, &column->indicator, &column->retcode));
+                       }
+               }
+
+               statement->errcode = PHP_OCI_CALL( OCIStmtFetch, (statement->stmt, statement->err, nrows, OCI_FETCH_NEXT, OCI_DEFAULT));
+
+               for (i = 0; i < statement->ncolumns; i++) {
+                       column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+                       if (column && column->piecewise)        {
+                               column->retlen4 += column->cb_retlen;
+                       }
+               }
+       }
+
+       if (statement->errcode == OCI_SUCCESS_WITH_INFO || statement->errcode == OCI_SUCCESS) {
+               statement->has_data = 1;
+
+               /* do the stuff needed for OCIDefineByName */
+               for (i = 0; i < statement->ncolumns; i++) {
+                       column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+                       if (column == NULL) {
+                               continue;
+                       }
+                       
+                       if (!column->define) {
+                               continue;
+                       }
+                       
+                       zval_dtor(column->define->zval);
+                       php_oci_column_to_zval(column, column->define->zval, 0 TSRMLS_CC);
+               }
+
+               return 0;
+       }
+
+       php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+       PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+
+       statement->has_data = 0;
+
+       return 1;
+}
+/* }}} */
+
+/* {{{ php_oci_statement_get_column() 
+ Get column from the result set */
+php_oci_out_column *php_oci_statement_get_column(php_oci_statement *statement, long column_index, char *column_name, long column_name_len TSRMLS_DC)
+{
+       php_oci_out_column *column = NULL;
+       int i;
+
+       if (statement->columns == NULL) { /* we release the columns at the end of a fetch */
+               return NULL;
+       }
+
+       if (column_name) {
+               for (i = 0; i < statement->ncolumns; i++) {
+                       column = php_oci_statement_get_column(statement, i + 1, NULL, 0 TSRMLS_CC);
+                       if (column == NULL) {
+                               continue;
+                       } else if (((int) column->name_len == column_name_len) && (!strncmp(column->name, column_name, column_name_len))) {
+                               return column;
+                       }
+               }
+       } else if (column_index != -1) {
+               if (zend_hash_index_find(statement->columns, column_index, (void **)&column) == FAILURE) {
+                       return NULL;
+               }
+               return column;
+       }
+
+       return NULL;
+}
+/* }}} */
+
+/* {{{ php_oci_statement_execute() 
+ Execute statement */
+int php_oci_statement_execute(php_oci_statement *statement, ub4 mode TSRMLS_DC)
+{
+       php_oci_out_column *outcol;
+       php_oci_out_column column;
+       OCIParam *param = NULL;
+       text *colname;
+       ub4 counter;
+       ub2 define_type;
+       ub4 iters;
+       ub4 colcount;
+       ub2 dynamic;
+       int dtype;
+       dvoid *buf;
+       php_oci_descriptor *descr;
+
+       switch (mode) {
+               case OCI_COMMIT_ON_SUCCESS:
+               case OCI_DEFAULT:
+                       /* only these two are allowed */
+                       break;
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid execute mode given: %d", mode);
+                       return 1;
+                       break;
+       }
+       
+       if (!statement->stmttype) {
+               /* get statement type */
+               statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement->stmttype, (ub4 *)0, OCI_ATTR_STMT_TYPE,     statement->err));
+
+               if (statement->errcode != OCI_SUCCESS) {
+                       php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                       return 1;
+               }
+       }
+
+       if (statement->stmttype == OCI_STMT_SELECT) {
+               iters = 0;
+       } else {
+               iters = 1;
+       }
+       
+       if (statement->last_query) { 
+               /* if we execute refcursors we don't have a query and 
+                  we don't want to execute!!! */
+
+               if (statement->binds) {
+                       zend_hash_apply(statement->binds, (apply_func_t) php_oci_bind_pre_exec TSRMLS_CC);
+               }
+
+               /* execute statement */
+               statement->errcode = PHP_OCI_CALL(OCIStmtExecute, (statement->connection->svc,  statement->stmt, statement->err, iters, 0, NULL, NULL, mode));
+
+               if (statement->errcode != OCI_SUCCESS) {
+                       php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                       return 1;
+               }
+               
+               if (statement->binds) {
+                       zend_hash_apply(statement->binds, (apply_func_t) php_oci_bind_post_exec TSRMLS_CC);
+               }
+
+               if (mode & OCI_COMMIT_ON_SUCCESS) {
+                       statement->connection->needs_commit = 0;
+               } else {
+                       statement->connection->needs_commit = 1;
+               }
+       }
+
+       if (statement->stmttype == OCI_STMT_SELECT && statement->executed == 0) {
+               /* we only need to do the define step is this very statement is executed the first time! */
+               statement->executed = 1;
+               
+               ALLOC_HASHTABLE(statement->columns);
+               zend_hash_init(statement->columns, 13, NULL, php_oci_column_hash_dtor, 0);
+               
+               counter = 1;
+
+               /* get number of columns */
+               statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (dvoid *)&colcount, (ub4 *)0, OCI_ATTR_PARAM_COUNT, statement->err));
+               
+               if (statement->errcode != OCI_SUCCESS) {
+                       php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                       return 1; 
+               }
+
+               statement->ncolumns = colcount;
+               
+               for (counter = 1; counter <= colcount; counter++) {
+                       memset(&column,0,sizeof(php_oci_out_column));
+                       
+                       if (zend_hash_index_update(statement->columns, counter, &column, sizeof(php_oci_out_column), (void**) &outcol) == FAILURE) {
+                               efree(statement->columns);
+                               /* out of memory */
+                               return 1;
+                       } 
+                       
+                       outcol->statement = statement;
+
+                       /* get column */
+                       statement->errcode = PHP_OCI_CALL(OCIParamGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, statement->err, (dvoid**)&param, counter));
+                       
+                       if (statement->errcode != OCI_SUCCESS) {
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 1;
+                       }
+
+                       /* get column datatype */
+                       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_type, (ub4 *)0, OCI_ATTR_DATA_TYPE, statement->err));
+
+                       if (statement->errcode != OCI_SUCCESS) {
+                               PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 1;
+                       }
+
+                       /* get size of the column */
+                       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->data_size, (dvoid *)0, OCI_ATTR_DATA_SIZE, statement->err));
+                       
+                       if (statement->errcode != OCI_SUCCESS) {
+                               PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 1; 
+                       }
+
+                       outcol->storage_size4 = outcol->data_size;
+                       outcol->retlen = outcol->data_size;
+
+                       /* get scale of the column */
+                       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->scale, (dvoid *)0, OCI_ATTR_SCALE, statement->err));
+                       
+                       if (statement->errcode != OCI_SUCCESS) {
+                               PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 1;
+                       }
+
+                       /* get precision of the column */
+                       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid *)&outcol->precision, (dvoid *)0, OCI_ATTR_PRECISION, statement->err));
+                       
+                       if (statement->errcode != OCI_SUCCESS) {
+                               PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 1;
+                       }
+                       
+                       /* get name of the column */
+                       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)param, OCI_DTYPE_PARAM, (dvoid **)&colname, (ub4 *)&outcol->name_len, (ub4)OCI_ATTR_NAME, statement->err));
+                       
+                       if (statement->errcode != OCI_SUCCESS) {
+                               PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 1;
+                       }
+                       PHP_OCI_CALL(OCIDescriptorFree, (param, OCI_DTYPE_PARAM));
+
+                       outcol->name = estrndup((char*) colname, outcol->name_len);
+
+                       /* find a user-setted define */
+                       if (statement->defines) {
+                               zend_hash_find(statement->defines,outcol->name,outcol->name_len,(void **) &outcol->define);
+                       }
+
+                       buf = 0;
+                       switch (outcol->data_type) {
+                               case SQLT_RSET:
+                                       outcol->statement = php_oci_statement_create(statement->connection, NULL, 0, 0 TSRMLS_CC);
+                                       outcol->stmtid = outcol->statement->id;
+
+                                       define_type = SQLT_RSET;
+                                       outcol->is_cursor = 1;
+                                       outcol->storage_size4 = -1;
+                                       outcol->retlen = -1;
+                                       dynamic = OCI_DEFAULT;
+                                       buf = &(outcol->statement->stmt);
+                                       break;
+
+                               case SQLT_RDD:   /* ROWID */
+                               case SQLT_BLOB:  /* binary LOB */
+                               case SQLT_CLOB:  /* character LOB */
+                               case SQLT_BFILE: /* binary file LOB */
+                                       define_type = outcol->data_type;
+                                       outcol->is_descr = 1;
+                                       outcol->storage_size4 = -1;
+                                       dynamic = OCI_DEFAULT;
+
+                                       if (outcol->data_type == SQLT_BFILE) {
+                                               dtype = OCI_DTYPE_FILE;
+                                       } else if (outcol->data_type == SQLT_RDD ) {
+                                               dtype = OCI_DTYPE_ROWID;
+                                       } else {
+                                               dtype = OCI_DTYPE_LOB;
+                                       }
+                                       
+                                       descr = php_oci_lob_create(statement->connection, dtype TSRMLS_CC);
+                                       if (!descr) {
+                                               efree(outcol->name);
+                                               return 1;
+                                       }
+                                       outcol->descid = descr->id;
+                                       buf = &(descr->descriptor);
+                                       break;
+
+                               case SQLT_LNG:
+                               case SQLT_LBI:
+                                       if (outcol->data_type == SQLT_LBI) {
+                                               define_type = SQLT_BIN;
+                                       } else {
+                                               define_type = SQLT_CHR;
+                                       }
+                                       outcol->storage_size4 = PHP_OCI_MAX_DATA_SIZE;
+                                       outcol->piecewise = 1;
+                                       dynamic = OCI_DYNAMIC_FETCH;
+                                       break;
+
+                               case SQLT_BIN:
+                               default:
+                                       define_type = SQLT_CHR;
+                                       if ((outcol->data_type == SQLT_DAT) || (outcol->data_type == SQLT_NUM)
+#ifdef SQLT_TIMESTAMP
+                                               || (outcol->data_type == SQLT_TIMESTAMP)
+#endif
+#ifdef SQLT_TIMESTAMP_TZ
+                                               || (outcol->data_type == SQLT_TIMESTAMP_TZ)
+#endif
+                                               ) {
+                                               outcol->storage_size4 = 512; /* XXX this should fit "most" NLS date-formats and Numbers */
+                                       } else {
+                                               outcol->storage_size4++; /* add one for string terminator */
+                                       }
+                                       
+                                       outcol->storage_size4 *= 3;
+                                       
+                                       dynamic = OCI_DEFAULT;
+                                       buf = outcol->data = (text *) emalloc(outcol->storage_size4);
+                                       break;
+                       }
+
+                       if (dynamic == OCI_DYNAMIC_FETCH) {
+                               statement->errcode = PHP_OCI_CALL(
+                                       OCIDefineByPos,
+                                       (
+                                               statement->stmt,                           /* IN/OUT handle to the requested SQL query */
+                                               (OCIDefine **)&outcol->oci_define,             /* IN/OUT pointer to a pointer to a define handle */
+                                               statement->err,                          /* IN/OUT An error handle  */
+                                               counter,                                    /* IN     position in the select list */
+                                               (dvoid *)NULL,                              /* IN/OUT pointer to a buffer */
+                                               outcol->storage_size4,                      /* IN     The size of each valuep buffer in bytes */
+                                               define_type,                                /* IN     The data type */
+                                               (dvoid *)&outcol->indicator,                /* IN     pointer to an indicator variable or arr */
+                                               (ub2 *)NULL,                                /* IN/OUT Pointer to array of length of data fetched */
+                                               (ub2 *)NULL,                                /* OUT    Pointer to array of column-level return codes */
+                                               OCI_DYNAMIC_FETCH                               /* IN     mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
+                                       )
+                               );
+
+                       } else {
+                               statement->errcode = PHP_OCI_CALL(
+                                       OCIDefineByPos,
+                                       (
+                                               statement->stmt,                           /* IN/OUT handle to the requested SQL query */ 
+                                               (OCIDefine **)&outcol->oci_define,             /* IN/OUT pointer to a pointer to a define handle */
+                                               statement->err,                          /* IN/OUT An error handle  */
+                                               counter,                                    /* IN     position in the select list */
+                                               (dvoid *)buf,                               /* IN/OUT pointer to a buffer */
+                                               outcol->storage_size4,                      /* IN     The size of each valuep buffer in bytes */
+                                               define_type,                                /* IN     The data type */
+                                               (dvoid *)&outcol->indicator,                /* IN     pointer to an indicator variable or arr */
+                                               (ub2 *)&outcol->retlen,                     /* IN/OUT Pointer to array of length of data fetched */
+                                               (ub2 *)&outcol->retcode,                    /* OUT    Pointer to array of column-level return codes */
+                                               OCI_DEFAULT                                     /* IN     mode (OCI_DEFAULT, OCI_DYNAMIC_FETCH) */
+                                       )
+                               );
+
+                       }
+                       
+                       if (statement->errcode != OCI_SUCCESS) {
+                               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                               return 0;
+                       }
+               }
+       }
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ php_oci_statement_cancel() 
+ Cancel statement */
+int php_oci_statement_cancel(php_oci_statement *statement TSRMLS_DC)
+{
+       
+       return php_oci_statement_fetch(statement, 0 TSRMLS_CC);
+               
+} /* }}} */
+
+/* {{{ php_oci_statement_free() 
+ Destroy statement handle and free associated resources */
+void php_oci_statement_free(php_oci_statement *statement TSRMLS_DC)
+{
+       if (statement->stmt) {
+#if HAVE_OCI_STMT_PREPARE2
+               if (statement->last_query_len) { /* FIXME: magical */
+                       PHP_OCI_CALL(OCIStmtRelease, (statement->stmt, statement->err, NULL, 0, OCI_DEFAULT));
+               }
+               else {
+                       PHP_OCI_CALL(OCIHandleFree, (statement->stmt, OCI_HTYPE_STMT));
+               }
+#else
+               PHP_OCI_CALL(OCIHandleFree, (statement->stmt, OCI_HTYPE_STMT));
+#endif
+               statement->stmt = 0;
+       }
+
+       if (statement->err) {
+               PHP_OCI_CALL(OCIHandleFree, (statement->err, OCI_HTYPE_ERROR));
+               statement->err = 0;
+       }
+
+       if (statement->last_query) {
+               efree(statement->last_query);
+       }
+
+       if (statement->columns) {
+               zend_hash_destroy(statement->columns);
+               efree(statement->columns);
+       }
+
+       if (statement->binds) {
+               zend_hash_destroy(statement->binds);
+               efree(statement->binds);
+       }
+
+       if (statement->defines) {
+               zend_hash_destroy(statement->defines);
+               efree(statement->defines);
+       }
+
+       efree(statement);
+} /* }}} */
+
+/* {{{ php_oci_bind_pre_exec() 
+ Helper function */
+int php_oci_bind_pre_exec(void *data TSRMLS_DC)
+{
+       php_oci_bind *bind = (php_oci_bind *) data;
+
+       /* reset all bind stuff to a normal state..-. */
+
+       bind->indicator = 0; 
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ php_oci_bind_post_exec() 
+ Helper function */
+int php_oci_bind_post_exec(void *data TSRMLS_DC)
+{
+       php_oci_bind *bind = (php_oci_bind *) data;
+
+       if (bind->indicator == -1) { /* NULL */
+               zval *val = bind->zval;
+               if (Z_TYPE_P(val) == IS_STRING) {
+                       *Z_STRVAL_P(val) = '\0'; /* XXX avoid warning in debug mode */
+               }
+               zval_dtor(val);
+               ZVAL_NULL(val);
+       } else if (Z_TYPE_P(bind->zval) == IS_STRING) {
+               Z_STRVAL_P(bind->zval) = erealloc(Z_STRVAL_P(bind->zval), Z_STRLEN_P(bind->zval)+1);
+               Z_STRVAL_P(bind->zval)[ Z_STRLEN_P(bind->zval) ] = '\0';
+       }
+
+
+       return 0;
+}
+/* }}} */
+
+/* {{{ php_oci_bind_by_name() 
+ Bind zval to the given placeholder */
+int php_oci_bind_by_name(php_oci_statement *statement, char *name, long name_len, zval* var, long maxlength, long type TSRMLS_DC)
+{
+       php_oci_collection *bind_collection = NULL;
+       php_oci_descriptor *bind_descriptor = NULL;
+       php_oci_statement  *bind_statement  = NULL;
+       dvoid *oci_desc                 = NULL;
+       /* dvoid *php_oci_collection           = NULL; */
+       OCIStmt *oci_stmt               = NULL;
+       dvoid *bind_data                = NULL;
+       php_oci_bind bind, *bindp;
+       int mode = OCI_DATA_AT_EXEC;
+       sb4 value_sz = -1;
+
+       switch (type) {
+#ifdef PHP_OCI8_HAVE_COLLECTIONS
+               case SQLT_NTY:
+               {
+                       zval **tmp;
+                       
+                       if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "collection", sizeof("collection"), (void **)&tmp) == FAILURE) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find collection property");
+                               return 1;
+                       }
+
+                       PHP_OCI_ZVAL_TO_COLLECTION_EX(*tmp, bind_collection);
+                       value_sz = sizeof(void*);
+                       mode = OCI_DEFAULT;
+               
+                       if (!bind_collection->collection) {
+                               return 1;
+                       }
+               }
+                       break;
+#endif
+               case SQLT_BFILEE:
+               case SQLT_CFILEE:
+               case SQLT_CLOB:
+               case SQLT_BLOB:
+               case SQLT_RDD:
+               {
+                       zval **tmp;
+                       
+                       if (Z_TYPE_P(var) != IS_OBJECT || zend_hash_find(Z_OBJPROP_P(var), "descriptor", sizeof("descriptor"), (void **)&tmp) == FAILURE) {
+                               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unable to find descriptor property");
+                               return 1;
+                       }
+
+                       PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(*tmp, bind_descriptor);
+
+                       value_sz = sizeof(void*);
+                       
+                       oci_desc = bind_descriptor->descriptor;
+                       
+                       if (!oci_desc) {
+                               return 1;
+                       }
+               }
+                       break;
+                       
+               case SQLT_INT:
+               case SQLT_NUM:
+                       convert_to_long(var);
+                       bind_data = (ub4 *)&Z_LVAL_P(var);
+                       value_sz = sizeof(ub4);
+                       mode = OCI_DEFAULT;
+                       break;
+                       
+               case SQLT_CHR:
+                       /* this is the default case when type was not specified */
+                       convert_to_string(var);
+                       if (maxlength == -1) {
+                               value_sz = Z_STRLEN_P(var);
+                       }
+                       else {
+                               value_sz = maxlength;
+                       }
+                       break;
+
+               case SQLT_RSET:
+                       PHP_OCI_ZVAL_TO_STATEMENT_EX(var, bind_statement);
+                       value_sz = sizeof(void*);
+
+                       oci_stmt = bind_statement->stmt;
+
+                       if (!oci_stmt) {
+                               return 1;
+                       }
+                       break;
+
+               default:
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Unknown or unsupported datatype given: %ld", type);
+                       return 1;
+                       break;
+       }
+       
+       if (value_sz == 0) { 
+               value_sz = 1;
+       }
+       
+       if (!statement->binds) {
+               ALLOC_HASHTABLE(statement->binds);
+               zend_hash_init(statement->binds, 13, NULL, php_oci_bind_hash_dtor, 0);
+       }
+
+       memset((void*)&bind,0,sizeof(php_oci_bind));
+       zend_hash_update(statement->binds, name, name_len + 1, &bind, sizeof(php_oci_bind), (void **)&bindp);
+       
+       bindp->descriptor = oci_desc;
+       bindp->statement = oci_stmt;
+       bindp->zval = var;
+       zval_add_ref(&var); 
+       
+       statement->errcode = PHP_OCI_CALL(
+               OCIBindByName,
+               (
+                       statement->stmt,                /* statement handle */
+                       (OCIBind **)&bindp->bind,       /* bind hdl (will alloc) */
+                       statement->err,               /* error handle */
+                       (text*) name,                    /* placeholder name */                                   
+                       name_len,                        /* placeholder length */
+                       (dvoid *)bind_data,              /* in/out data */
+                       value_sz, /* PHP_OCI_MAX_DATA_SIZE, */ /* max size of input/output data */
+                       (ub2)type,                       /* in/out data type */
+                       (dvoid *)&bindp->indicator,      /* indicator (ignored) */
+                       (ub2 *)0,                        /* size array (ignored) */
+                       (ub2 *)&bindp->retcode,          /* return code (ignored) */
+                       (ub4)0,                          /* maxarr_len (PL/SQL only?) */
+                       (ub4 *)0,                        /* actual array size (PL/SQL only?) */
+                       mode                             /* mode */
+               )
+       );
+
+       if (statement->errcode != OCI_SUCCESS) {
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+               return 1;
+       }
+
+       if (mode == OCI_DATA_AT_EXEC) {
+               statement->errcode = PHP_OCI_CALL(OCIBindDynamic, (bindp->bind, statement->err, (dvoid *)bindp, php_oci_bind_in_callback, (dvoid *)bindp, php_oci_bind_out_callback));
+
+               if (statement->errcode != OCI_SUCCESS) {
+                       php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                       return 1;
+               }
+       }
+
+#ifdef PHP_OCI8_HAVE_COLLECTIONS
+       if (type == SQLT_NTY) {
+               /* Bind object */
+               statement->errcode = PHP_OCI_CALL(OCIBindObject, (bindp->bind, statement->err, bind_collection->tdo, (dvoid **) &(bind_collection->collection), (ub4 *) 0, (dvoid **) 0, (ub4 *) 0));
+               
+               if (statement->errcode) {
+                       php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+                       PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+                       return 1;
+               }
+       }
+#endif
+       
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_bind_in_callback() 
+ Callback used when binding LOBs and VARCHARs */
+sb4 php_oci_bind_in_callback(
+                                       dvoid *ictxp,     /* context pointer */
+                                       OCIBind *bindp,   /* bind handle */
+                                       ub4 iter,         /* 0-based execute iteration value */
+                                       ub4 index,        /* index of current array for PL/SQL or row index for SQL */
+                                       dvoid **bufpp,    /* pointer to data */
+                                       ub4 *alenp,       /* size after value/piece has been read */
+                                       ub1 *piecep,      /* which piece */
+                                       dvoid **indpp)    /* indicator value */
+{
+       php_oci_bind *phpbind;
+       zval *val;
+       TSRMLS_FETCH();
+
+       if (!(phpbind=(php_oci_bind *)ictxp) || !(val = phpbind->zval)) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
+               return OCI_ERROR;
+       }
+
+       if (ZVAL_IS_NULL(val)) {
+               /* we're going to insert a NULL column */
+               phpbind->indicator = -1;
+               *bufpp = 0;
+               *alenp = -1;
+               *indpp = (dvoid *)&phpbind->indicator;
+       } else  if ((phpbind->descriptor == 0) && (phpbind->statement == 0)) {
+               /* "normal string bind */
+               convert_to_string(val); 
+
+               *bufpp = Z_STRVAL_P(val);
+               *alenp = Z_STRLEN_P(val);
+               *indpp = (dvoid *)&phpbind->indicator;
+       } else if (phpbind->statement != 0) {
+               /* RSET */
+               *bufpp = phpbind->statement;
+               *alenp = -1;            /* seems to be allright */
+               *indpp = (dvoid *)&phpbind->indicator;
+       } else { 
+               /* descriptor bind */
+               *bufpp = phpbind->descriptor;
+               *alenp = -1;            /* seems to be allright */
+               *indpp = (dvoid *)&phpbind->indicator;
+       }
+
+       *piecep = OCI_ONE_PIECE; /* pass all data in one go */
+
+       return OCI_CONTINUE;
+}/* }}} */
+
+/* {{{ php_oci_bind_out_callback()
+ Callback used when binding LOBs and VARCHARs */
+sb4 php_oci_bind_out_callback(
+                                       dvoid *octxp,      /* context pointer */
+                                       OCIBind *bindp,    /* bind handle */
+                                       ub4 iter,          /* 0-based execute iteration value */
+                                       ub4 index,         /* index of current array for PL/SQL or row index for SQL */
+                                       dvoid **bufpp,     /* pointer to data */
+                                       ub4 **alenpp,      /* size after value/piece has been read */
+                                       ub1 *piecep,       /* which piece */
+                                       dvoid **indpp,     /* indicator value */
+                                       ub2 **rcodepp)     /* return code */
+{
+       php_oci_bind *phpbind;
+       zval *val;
+       sb4 retval = OCI_ERROR;
+       TSRMLS_FETCH();
+
+       if (!(phpbind=(php_oci_bind *)octxp) || !(val = phpbind->zval)) {
+               php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid phpbind pointer value");
+               return retval;
+       }
+
+       if ((Z_TYPE_P(val) == IS_OBJECT) || (Z_TYPE_P(val) == IS_RESOURCE)) {
+               retval = OCI_CONTINUE;
+       } else {
+               convert_to_string(val);
+               zval_dtor(val);
+               
+               Z_STRLEN_P(val) = PHP_OCI_PIECE_SIZE; /* 64K-1 is max XXX */
+               Z_STRVAL_P(val) = emalloc(Z_STRLEN_P(phpbind->zval));
+               
+               /* XXX we assume that zend-zval len has 4 bytes */
+               *alenpp = (ub4*) &Z_STRLEN_P(phpbind->zval); 
+               *bufpp = Z_STRVAL_P(phpbind->zval);
+               *piecep = OCI_ONE_PIECE;
+               *rcodepp = &phpbind->retcode;
+               *indpp = &phpbind->indicator;
+               retval = OCI_CONTINUE;
+       }
+
+       return retval;
+}
+/* }}} */
+
+/* {{{ php_oci_statement_get_column_helper() 
+ Helper function to get column by name and index */
+php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAMETERS)
+{
+       zval *z_statement, *column_index;
+       php_oci_statement *statement;
+       php_oci_out_column *column;
+
+       if (zend_parse_parameters(ZEND_NUM_ARGS() TSRMLS_CC, "rz", &z_statement, &column_index) == FAILURE) {
+               return NULL;
+       }
+
+       statement = (php_oci_statement *) zend_fetch_resource(&z_statement TSRMLS_CC, -1, "oci8 statement", NULL, 1, le_statement);
+
+       if (!statement) {
+               return NULL;
+       }
+       
+       if (Z_TYPE_P(column_index) == IS_STRING) {
+               column = php_oci_statement_get_column(statement, -1, Z_STRVAL_P(column_index), Z_STRLEN_P(column_index) TSRMLS_CC);
+               if (!column) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column name \"%s\"", Z_STRVAL_P(column_index));
+                       return NULL;
+               }
+       }
+       else {
+               convert_to_long(column_index);
+               column = php_oci_statement_get_column(statement, Z_LVAL_P(column_index), NULL, 0 TSRMLS_CC);
+               if (!column) {
+                       php_error_docref(NULL TSRMLS_CC, E_WARNING, "Invalid column index \"%ld\"", Z_LVAL_P(column_index));
+                       return NULL;
+               }
+       }
+       return column;
+} /* }}} */
+
+/* {{{ php_oci_statement_get_type()
+ Return type of the statement */
+int php_oci_statement_get_type(php_oci_statement *statement, ub2 *type TSRMLS_DC)
+{
+       ub2 statement_type;
+       
+       *type = 0;
+       
+       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub2 *)&statement_type, (ub4 *)0, OCI_ATTR_STMT_TYPE, statement->err));
+
+       if (statement->errcode != OCI_SUCCESS) {
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+               return 1;
+       }
+
+       *type = statement_type;
+
+       return 0;
+} /* }}} */
+
+/* {{{ php_oci_statement_get_numrows() 
+ Get the number of rows fetched to the clientside (NOT the number of rows in the result set) */
+int php_oci_statement_get_numrows(php_oci_statement *statement, ub4 *numrows TSRMLS_DC)
+{
+       ub4 statement_numrows;
+       
+       *numrows = 0;
+       
+       statement->errcode = PHP_OCI_CALL(OCIAttrGet, ((dvoid *)statement->stmt, OCI_HTYPE_STMT, (ub4 *)&statement_numrows, (ub4 *)0, OCI_ATTR_ROW_COUNT, statement->err));
+
+       if (statement->errcode != OCI_SUCCESS) {
+               php_oci_error(statement->err, statement->errcode TSRMLS_CC);
+               PHP_OCI_HANDLE_ERROR(statement->connection, statement->errcode);
+               return 1;
+       }
+
+       *numrows = statement_numrows;
+
+       return 0;
+} /* }}} */
+
+#endif /* HAVE_OCI8 */
index 9da34f85f157bb95f4331ba3eb292ddcf83c8e17..92e8663e92aa61ad6c74392e67b7a7e314902376 100644 (file)
    | obtain it through the world-wide-web, please send a note to          |
    | license@php.net so we can mail you a copy immediately.               |
    +----------------------------------------------------------------------+
-   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
    |          Thies C. Arntzen <thies@thieso.net>                         |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
    +----------------------------------------------------------------------+
 */
 
 #if HAVE_OCI8
 # ifndef PHP_OCI8_H
 #  define PHP_OCI8_H
-# endif
-
-# if (defined(__osf__) && defined(__alpha))
-#  ifndef A_OSF
-#   define A_OSF
-#  endif
-#  ifndef OSF1
-#   define OSF1
-#  endif
-#  ifndef _INTRINSICS
-#   define _INTRINSICS
-#  endif
-# endif /* osf alpha */
 
 #ifdef PHP_WIN32
 #define PHP_OCI_API __declspec(dllexport)
 #define PHP_OCI_API
 #endif                                   
 
-#if defined(min)
-#undef min
-#endif
-#if defined(max)
-#undef max
-#endif
-
-#include <oci.h>
-
-#define OCI_SEEK_SET 0
-#define OCI_SEEK_CUR 1
-#define OCI_SEEK_END 2
-
-typedef struct {
-       int num;
-       int persistent;
-       int is_open;
-       char *dbname;
-       OCIServer *pServer;
-#if 0
-       OCIFocbkStruct failover;
-#endif
-} oci_server;
-
-typedef struct {
-       int num;
-       zend_bool persistent;
-       zend_bool is_open;
-       zend_bool exclusive;
-#if ZTS
-       THREAD_T thread;
-#else
-       zend_bool thread;
+#ifdef ZTS
+# include "TSRM.h"
 #endif
-       zend_llist *sessions_list;
-       oci_server *server;
-       OCISession *pSession;
-       OCIEnv *pEnv;                           /* sessions own environment */
-       ub2 charsetId;                          /* sessions used character set (mostly this will be 0, so NLS_LANG will be used. */
-} oci_session;
-
-typedef struct {
-       int id;
-       int is_open;
-       oci_session *session;
-       OCISvcCtx *pServiceContext;
-       sword error;
-       OCIError *pError;
-       int needs_commit;
-       HashTable *descriptors;
-} oci_connection;
-
-typedef struct {
-       int id;
-       oci_connection *conn;
-       dvoid *ocidescr;
-       ub4 type;
-       int lob_current_position; 
-       int lob_size;  /* -1 = Lob wasn't initialized yet */
-       int buffering; /* 0 - off, 1 - on, 2 - on and buffer was used */
-} oci_descriptor;
-
-typedef struct {
-       int id;
-       oci_connection *conn;
-       OCIType     *tdo;
-       OCITypeCode coll_typecode;
-       OCIRef      *elem_ref;
-       OCIType     *element_type;
-       OCITypeCode element_typecode;
-       OCIColl     *coll;
-} oci_collection;
-
-typedef struct {
-       zval *zval;
-       text *name;
-       ub4 name_len;
-       ub4 type;
-} oci_define;
-
-typedef struct {
-       int id;
-       oci_connection *conn;
-       sword error;
-       OCIError *pError;
-       OCIStmt *pStmt;
-       char *last_query;
-       HashTable *columns;
-       HashTable *binds;
-       HashTable *defines;
-       int ncolumns;
-       int executed;
-       int has_data;
-       ub2 stmttype;
-} oci_statement;
-
-typedef struct {
-       OCIBind *pBind;
-       zval *zval;
-       dvoid *descr;           /* used for binding of LOBS etc */
-       OCIStmt *pStmt;     /* used for binding REFCURSORs */
-       sb2 indicator;
-       ub2 retcode;
-} oci_bind;
-
-typedef struct {
-       oci_statement *statement;
-       OCIDefine *pDefine;
-       char *name;
-       ub4 name_len;
-       ub2 data_type;
-       ub2 data_size;
-       ub4 storage_size4;
-       sb2 indicator;
-       ub2 retcode;
-       ub2 retlen;
-       ub4 retlen4;
-       ub2 is_descr;
-       ub2 is_cursor;
-       int descr;
-       oci_statement *pstmt;
-       int stmtid;
-       int descid;
-       void *data;
-       oci_define *define;
-       int piecewise;
-       ub4 cb_retlen;
-       ub2 scale;
-       ub2 precision;          
-} oci_out_column;
-
-typedef struct {
-       sword error;
-       OCIError *pError;
-               
-       /*
-       char *default_username;
-       char *default_password;
-       char *default_dbname;
-       */
-
-       long debug_mode;
-
-       int shutdown;
-
-       /* XXX NYI
-       long allow_persistent;
-       long max_persistent;
-       long max_links;
-       */
-
-       OCIEnv *pEnv;
-
-       int in_call;
-} php_oci_globals;
 
 extern zend_module_entry oci8_module_entry;
 #define phpext_oci8_ptr &oci8_module_entry
 
-#define OCI_MAX_NAME_LEN  64
-#define OCI_MAX_DATA_SIZE INT_MAX
-#define OCI_PIECE_SIZE    (64*1024)-1
 
-#ifdef ZTS
-#define OCI(v) TSRMG(oci_globals_id, php_oci_globals *, v)
-#else
-#define OCI(v) (oci_globals.v)
-#endif
+PHP_MINIT_FUNCTION(oci);
+PHP_RINIT_FUNCTION(oci);
+PHP_MSHUTDOWN_FUNCTION(oci);
+PHP_RSHUTDOWN_FUNCTION(oci);
+PHP_MINFO_FUNCTION(oci);
 
+# endif /* !PHP_OCI8_H */
 #else /* !HAVE_OCI8 */
 
 # define oci8_module_ptr NULL
@@ -223,3 +59,5 @@ extern zend_module_entry oci8_module_entry;
  * c-basic-offset: 4
  * End:
  */
+
+
diff --git a/ext/oci8/php_oci8_int.h b/ext/oci8/php_oci8_int.h
new file mode 100644 (file)
index 0000000..dc96971
--- /dev/null
@@ -0,0 +1,404 @@
+/*
+   +----------------------------------------------------------------------+
+   | PHP Version 5                                                        |
+   +----------------------------------------------------------------------+
+   | Copyright (c) 1997-2005 The PHP Group                                |
+   +----------------------------------------------------------------------+
+   | This source file is subject to version 3.0 of the PHP license,       |
+   | that is bundled with this package in the file LICENSE, and is        |
+   | available through the world-wide-web at the following url:           |
+   | http://www.php.net/license/3_0.txt.                                  |
+   | If you did not receive a copy of the PHP license and are unable to   |
+   | obtain it through the world-wide-web, please send a note to          |
+   | license@php.net so we can mail you a copy immediately.               |
+   +----------------------------------------------------------------------+
+   | Authors: Stig Sæther Bakken <ssb@php.net>                            |
+   |          Thies C. Arntzen <thies@thieso.net>                         |
+   | Redesigned by: Antony Dovgal <antony@zend.com>                       |
+   |                Andi Gutmans <andi@zend.com>                          |
+   |                Wez Furlong <wez@omniti.com>                          |
+   +----------------------------------------------------------------------+
+*/
+
+/* $Id$ */
+
+#undef HAVE_OCI_STMT_PREPARE2
+
+#if HAVE_OCI8
+# ifndef PHP_OCI8_INT_H
+#  define PHP_OCI8_INT_H
+
+/* misc defines {{{ */
+# if (defined(__osf__) && defined(__alpha))
+#  ifndef A_OSF
+#   define A_OSF
+#  endif
+#  ifndef OSF1
+#   define OSF1
+#  endif
+#  ifndef _INTRINSICS
+#   define _INTRINSICS
+#  endif
+# endif /* osf alpha */
+
+#if defined(min)
+#undef min
+#endif
+#if defined(max)
+#undef max
+#endif
+/* }}} */
+
+#include <oci.h>
+
+extern int le_connection;
+extern int le_pconnection;
+extern int le_statement;
+extern int le_descriptor;
+#ifdef PHP_OCI8_HAVE_COLLECTIONS 
+extern int le_collection;
+#endif
+extern int le_server;
+extern int le_session;
+
+extern zend_class_entry *oci_lob_class_entry_ptr;
+#ifdef PHP_OCI8_HAVE_COLLECTIONS
+extern zend_class_entry *oci_coll_class_entry_ptr;
+#endif
+
+/* constants {{{ */
+#define PHP_OCI_SEEK_SET 0
+#define PHP_OCI_SEEK_CUR 1
+#define PHP_OCI_SEEK_END 2
+
+#define PHP_OCI_MAX_NAME_LEN  64
+#define PHP_OCI_MAX_DATA_SIZE INT_MAX
+#define PHP_OCI_PIECE_SIZE    (64*1024)-1
+#define PHP_OCI_LOB_BUFFER_SIZE 1048576l 
+
+#define PHP_OCI_ASSOC               1<<0
+#define PHP_OCI_NUM                 1<<1
+#define PHP_OCI_BOTH                (PHP_OCI_ASSOC|PHP_OCI_NUM)
+
+#define PHP_OCI_RETURN_NULLS        1<<2
+#define PHP_OCI_RETURN_LOBS         1<<3
+
+#define PHP_OCI_FETCHSTATEMENT_BY_COLUMN    1<<4
+#define PHP_OCI_FETCHSTATEMENT_BY_ROW       1<<5
+#define PHP_OCI_FETCHSTATEMENT_BY           (PHP_OCI_FETCHSTATEMENT_BY_COLUMN | PHP_OCI_FETCHSTATEMENT_BY_ROW)
+
+#define PHP_OCI_LOB_BUFFER_DISABLED 0
+#define PHP_OCI_LOB_BUFFER_ENABLED 1
+#define PHP_OCI_LOB_BUFFER_USED 2
+
+/* }}} */
+
+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 */
+       OCIError *err;          /* private error handle */
+       sword errcode;          /* last errcode */
+
+       HashTable *descriptors;         /* descriptors hash, used to flush all the LOBs using this connection on commit */
+       unsigned is_open:1;                     /* hels to determine if the connection is dead or not */
+       unsigned is_attached:1;         /* hels to determine if we should detach from the server when closing/freeing the connection */
+       unsigned is_persistent:1;       /* self-descriptive */
+       unsigned used_this_request:1; /* helps to determine if we should reset connection's next ping time and check its timeout */
+       unsigned needs_commit:1;        /* helps to determine if we should rollback this connection on close/shutdown */
+       int rsrc_id;                            /* resource ID */
+       time_t idle_expiry;                     /* time when the connection will be considered as expired */
+       time_t next_ping;                       /* time of the next ping */
+       char *hash_key;                         /* hashed details of the connection */
+} php_oci_connection; /* }}} */
+
+typedef struct { /* php_oci_descriptor {{{ */
+       int id;
+       php_oci_connection *connection; /* parent connection handle */
+       dvoid *descriptor;                              /* OCI descriptor handle */
+       ub4 type;                                               /* descriptor type */
+       int lob_current_position;               /* LOB internal pointer */ 
+       int lob_size;                                   /* cached LOB size. -1 = Lob wasn't initialized yet */
+       int buffering;                                  /* cached buffering flag. 0 - off, 1 - on, 2 - on and buffer was used */
+} php_oci_descriptor; /* }}} */
+
+typedef struct { /* php_oci_collection {{{ */
+       int id;
+       php_oci_connection *connection; /* parent connection handle */
+       OCIType     *tdo;                               /* collection's type handle */
+       OCITypeCode coll_typecode;              /* collection's typecode handle */
+       OCIRef      *elem_ref;                  /* element's reference handle */
+       OCIType     *element_type;              /* element's type handle */
+       OCITypeCode element_typecode;   /* element's typecode handle */
+       OCIColl     *collection;                /* collection handle */
+} php_oci_collection; /* }}} */
+
+typedef struct { /* php_oci_define {{{ */
+       zval *zval;             /* zval used in define */
+       text *name;             /* placeholder's name */
+       ub4 name_len;   /* placeholder's name length */
+       ub4 type;               /* define type */
+} php_oci_define; /* }}} */
+
+typedef struct { /* php_oci_statement {{{ */
+       int id;
+       php_oci_connection *connection; /* parent connection handle */
+       sword errcode;                                  /* last errcode*/
+       OCIError *err;                                  /* private error handle */
+       OCIStmt *stmt;                                  /* statement handle */
+       char *last_query;                               /* last query issued. also used to determine if this is a statement or a refcursor recieved from Oracle */
+       long last_query_len;                    /* last query length */
+       HashTable *columns;                             /* hash containing all the result columns */
+       HashTable *binds;                               /* binds hash */
+       HashTable *defines;                             /* defines hash */
+       int ncolumns;                                   /* number of columns in the result */
+       unsigned executed:1;                    /* statement executed flag */
+       unsigned has_data:1;                    /* statement has more data flag */
+       ub2 stmttype;                                   /* statement type */
+} php_oci_statement; /* }}} */
+
+typedef struct { /* php_oci_bind {{{ */
+       OCIBind *bind;                  /* bind handle */
+       zval *zval;                             /* value */
+       dvoid *descriptor;              /* used for binding of LOBS etc */
+       OCIStmt *statement;     /* used for binding REFCURSORs */
+       sb2 indicator;                  /*  */
+       ub2 retcode;                    /*  */
+} php_oci_bind; /* }}} */
+
+typedef struct { /* php_oci_out_column {{{ */
+       php_oci_statement *statement;   /* statement handle. used when fetching REFCURSORS */
+       OCIDefine *oci_define;                  /* define handle */
+       char *name;                                             /* column name */
+       ub4 name_len;                                   /* column name length */
+       ub2 data_type;                                  /* column data type */
+       ub2 data_size;                                  /* data size */
+       ub4 storage_size4;                              /* size used when allocating buffers */
+       sb2 indicator;                                  /* */
+       ub2 retcode;                                    /* code returned when fetching this particular column */
+       ub2 retlen;                                             /* */
+       ub4 retlen4;                                    /* */
+       ub2 is_descr;                                   /* column contains a descriptor */
+       ub2 is_cursor;                                  /* column contains a cursor */
+       int stmtid;                                             /* statement id for cursors */
+       int descid;                                             /* descriptor id for descriptors */
+       void *data;                                             /* */
+       php_oci_define *define;                 /* define handle */
+       int piecewise;                                  /* column is fetched piece-by-piece */
+       ub4 cb_retlen;                                  /* */
+       ub2 scale;                                              /* column scale */
+       ub2 precision;                                  /* column precision */
+} php_oci_out_column; /* }}} */
+
+/* {{{ macros */
+#define PHP_OCI_CALL(func, params) \
+       func params; \
+       if (OCI_G(debug_mode)) { \
+               php_printf ("OCI8 DEBUG: " #func " in %s() (%s:%d) \n", __FUNCTION__, __FILE__, __LINE__); \
+       }
+/*
+\
+*/
+
+#define PHP_OCI_HANDLE_ERROR(connection, errcode) \
+{ \
+       switch (errcode) { \
+               case 1013: \
+                       zend_bailout(); \
+                       break; \
+               case 22: \
+               case 1012: \
+               case 3113: \
+               case 604: \
+               case 1041: \
+               case 3114: \
+                       connection->is_open = 0; \
+                       break; \
+       } \
+} \
+
+#define PHP_OCI_REGISTER_RESOURCE(resource, le_resource) \
+       resource->id = ZEND_REGISTER_RESOURCE(NULL, resource, le_resource); \
+       zend_list_addref(resource->connection->rsrc_id);
+
+#define PHP_OCI_ZVAL_TO_CONNECTION(zval, connection) \
+       ZEND_FETCH_RESOURCE2(connection, php_oci_connection *, &zval, -1, "oci8 connection", le_connection, le_pconnection);
+
+#define PHP_OCI_ZVAL_TO_STATEMENT(zval, statement) \
+       ZEND_FETCH_RESOURCE(statement, php_oci_statement *, &zval, -1, "oci8 statement", le_statement)
+
+#define PHP_OCI_ZVAL_TO_DESCRIPTOR(zval, descriptor) \
+       ZEND_FETCH_RESOURCE(descriptor, php_oci_descriptor *, &zval, -1, "oci8 descriptor", le_descriptor)
+
+#define PHP_OCI_ZVAL_TO_COLLECTION(zval, collection) \
+       ZEND_FETCH_RESOURCE(collection, php_oci_collection *, &zval, -1, "oci8 collection", le_collection)
+
+#define PHP_OCI_FETCH_RESOURCE_EX(zval, var, type, name, resource_type)                      \
+       var = (type) zend_fetch_resource(&zval TSRMLS_CC, -1, name, NULL, 1, resource_type); \
+       if (!var) {                                                                          \
+               return 1;                                                                        \
+       }
+       
+#define PHP_OCI_ZVAL_TO_CONNECTION_EX(zval, connection) \
+       PHP_OCI_FETCH_RESOURCE_EX(zval, connection, php_oci_connection *, "oci8 connection", le_connection)
+
+#define PHP_OCI_ZVAL_TO_STATEMENT_EX(zval, statement) \
+       PHP_OCI_FETCH_RESOURCE_EX(zval, statement, php_oci_statement *, "oci8 statement", le_statement)
+
+#define PHP_OCI_ZVAL_TO_DESCRIPTOR_EX(zval, descriptor) \
+       PHP_OCI_FETCH_RESOURCE_EX(zval, descriptor, php_oci_descriptor *, "oci8 descriptor", le_descriptor)
+
+#define PHP_OCI_ZVAL_TO_COLLECTION_EX(zval, collection) \
+       PHP_OCI_FETCH_RESOURCE_EX(zval, collection, php_oci_collection *, "oci8 collection", le_collection)
+
+/* }}} */
+
+/* PROTOS */
+
+/* main prototypes {{{ */
+
+void php_oci_column_hash_dtor (void *data);
+void php_oci_define_hash_dtor (void *data);
+void php_oci_bind_hash_dtor (void *data);
+void php_oci_descriptor_flush_hash_dtor (void *data);
+
+sb4 php_oci_error (OCIError *, sword TSRMLS_DC);
+sb4 php_oci_fetch_errmsg(OCIError *, text ** TSRMLS_DC);
+#ifdef HAVE_OCI8_ATTR_STATEMENT
+int php_oci_fetch_sqltext_offset(php_oci_statement *, text **, ub2 * TSRMLS_DC);
+#endif
+       
+void php_oci_do_connect (INTERNAL_FUNCTION_PARAMETERS, int , int);
+php_oci_connection *php_oci_do_connect_ex(char *username, long username_len, char *password, long password_len, char *new_password, long new_password_len, char *dbname, long dbname_len, char *charset, long session_mode, int persistent, int exclusive TSRMLS_DC);
+
+int php_oci_connection_rollback(php_oci_connection * TSRMLS_DC);
+int php_oci_connection_commit(php_oci_connection * TSRMLS_DC);
+
+int php_oci_password_change(php_oci_connection *, char *, long, char *, long, char *, long TSRMLS_DC);
+int php_oci_server_get_version(php_oci_connection *, char ** TSRMLS_DC); 
+
+void php_oci_fetch_row(INTERNAL_FUNCTION_PARAMETERS, int, int);
+int php_oci_column_to_zval(php_oci_out_column *, zval *, int TSRMLS_DC);
+
+/* }}} */
+
+/* lob related prototypes {{{ */
+
+php_oci_descriptor * php_oci_lob_create (php_oci_connection *, long TSRMLS_DC);
+int php_oci_lob_get_length (php_oci_descriptor *, ub4 * TSRMLS_DC);
+int php_oci_lob_read (php_oci_descriptor *, long, long, char **, ub4 * TSRMLS_DC);
+int php_oci_lob_write (php_oci_descriptor *, ub4, char *, long, ub4 * TSRMLS_DC);
+int php_oci_lob_flush (php_oci_descriptor *, int TSRMLS_DC);
+int php_oci_lob_set_buffering (php_oci_descriptor *, int TSRMLS_DC);
+int php_oci_lob_get_buffering (php_oci_descriptor * TSRMLS_DC);
+int php_oci_lob_copy (php_oci_descriptor *, php_oci_descriptor *, long TSRMLS_DC);
+#ifdef HAVE_OCI8_TEMP_LOB
+int php_oci_lob_close (php_oci_descriptor * TSRMLS_DC);
+int php_oci_lob_write_tmp (php_oci_descriptor *, ub1, char *, long TSRMLS_DC);
+#endif
+void php_oci_lob_free(php_oci_descriptor * TSRMLS_DC);
+int php_oci_lob_import(php_oci_descriptor *descriptor, char * TSRMLS_DC);
+int php_oci_lob_append (php_oci_descriptor *, php_oci_descriptor * TSRMLS_DC);
+int php_oci_lob_truncate (php_oci_descriptor *, long TSRMLS_DC);
+int php_oci_lob_erase (php_oci_descriptor *, long, long, ub4 * TSRMLS_DC);
+int php_oci_lob_is_equal (php_oci_descriptor *, php_oci_descriptor *, boolean * TSRMLS_DC);
+
+/* }}} */
+
+/* collection related prototypes {{{ */
+
+php_oci_collection * php_oci_collection_create(php_oci_connection *, char *, long, char *, long TSRMLS_DC);
+int php_oci_collection_size(php_oci_collection *, sb4 * TSRMLS_DC);
+int php_oci_collection_max(php_oci_collection *, long * TSRMLS_DC);
+int php_oci_collection_trim(php_oci_collection *, long TSRMLS_DC);
+int php_oci_collection_append(php_oci_collection *, char *, long TSRMLS_DC);
+int php_oci_collection_element_get(php_oci_collection *, long, zval** TSRMLS_DC);
+int php_oci_collection_element_set(php_oci_collection *, long, char*, long TSRMLS_DC);
+int php_oci_collection_element_set_null(php_oci_collection *, long TSRMLS_DC);
+int php_oci_collection_element_set_date(php_oci_collection *, long, char *, long TSRMLS_DC);
+int php_oci_collection_element_set_number(php_oci_collection *, long, char *, long TSRMLS_DC);
+int php_oci_collection_element_set_string(php_oci_collection *, long, char *, long TSRMLS_DC);
+int php_oci_collection_assign(php_oci_collection *, php_oci_collection * TSRMLS_DC);
+void php_oci_collection_close(php_oci_collection * TSRMLS_DC);
+int php_oci_collection_append_null(php_oci_collection * TSRMLS_DC);
+int php_oci_collection_append_date(php_oci_collection *, char *, long TSRMLS_DC);
+int php_oci_collection_append_number(php_oci_collection *, char *, long TSRMLS_DC);
+int php_oci_collection_append_string(php_oci_collection *, char *, long TSRMLS_DC);
+
+
+/* }}} */
+
+/* statement related prototypes {{{ */
+
+php_oci_statement * php_oci_statement_create (php_oci_connection *, char *, long, zend_bool TSRMLS_DC);
+int php_oci_statement_set_prefetch (php_oci_statement *, ub4 TSRMLS_DC);
+int php_oci_statement_fetch (php_oci_statement *, ub4 TSRMLS_DC);
+php_oci_out_column * php_oci_statement_get_column (php_oci_statement *, long, char*, long TSRMLS_DC);
+int php_oci_statement_execute (php_oci_statement *, ub4 TSRMLS_DC);
+int php_oci_statement_cancel (php_oci_statement * TSRMLS_DC);
+void php_oci_statement_free (php_oci_statement * TSRMLS_DC);
+int php_oci_bind_pre_exec(void *data TSRMLS_DC);
+int php_oci_bind_post_exec(void *data TSRMLS_DC);
+int php_oci_bind_by_name(php_oci_statement *, char *, long, zval*, long, long TSRMLS_DC);
+sb4 php_oci_bind_in_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 *, ub1 *, dvoid **);
+sb4 php_oci_bind_out_callback(dvoid *, OCIBind *, ub4, ub4, dvoid **, ub4 **, ub1 *, dvoid **, ub2 **);
+php_oci_out_column *php_oci_statement_get_column_helper(INTERNAL_FUNCTION_PARAMETERS);
+
+int php_oci_statement_get_type(php_oci_statement *, ub2 * TSRMLS_DC);
+int php_oci_statement_get_numrows(php_oci_statement *, ub4 * TSRMLS_DC);
+
+/* }}} */
+
+ZEND_BEGIN_MODULE_GLOBALS(oci) /* {{{ */
+       sword errcode;                  /* global last error code (used when connect fails, for example) */
+       OCIError *err;                  /* global error handle */
+       
+       /*
+       char *default_username;
+       char *default_password;
+       char *default_dbname;
+       */
+
+       zend_bool debug_mode;   /* debug mode flag */
+       
+       long max_persistent;    /* maximum number of persistent connections per process */
+       long num_persistent;    /* number of existing persistent connections */
+       long num_links;                 /* non-persistent + persistent connections */
+       long ping_interval;             /* time interval between pings */
+       long persistent_timeout;        /* time period after which idle persistent connection is considered expired */
+       long statement_cache_size;      /* statement cache size. used with 9i+ clients only*/
+       long default_prefetch;          /* default prefetch setting */
+       zend_bool privileged_connect;   /* privileged connect flag (On/Off) */
+       zend_bool old_oci_close_semantics;      /* old_oci_close_semantics flag (to determine the way oci_close() should behave) */
+       
+       int shutdown;                           /* in shutdown flag */
+
+       OCIEnv *env;                            /* global environment handle */
+
+ZEND_END_MODULE_GLOBALS(oci) /* }}} */ 
+
+#ifdef ZTS
+#define OCI_G(v) TSRMG(oci_globals_id, zend_oci_globals *, v)
+#else
+#define OCI_G(v) (oci_globals.v)
+#endif
+
+ZEND_EXTERN_MODULE_GLOBALS(oci)
+
+# endif /* !PHP_OCI8_INT_H */
+#else /* !HAVE_OCI8 */
+
+# define oci8_module_ptr NULL
+
+#endif /* HAVE_OCI8 */
+
+/*
+ * Local variables:
+ * tab-width: 4
+ * c-basic-offset: 4
+ * End:
+ */
+
+